Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Captcha Laravel Package

webman/captcha

A lightweight CAPTCHA plugin for the Webman PHP framework, offering image-based verification codes with session validation and configurable options. Easily add human verification to Webman routes and forms with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer inside the webman project and let the plugin register itself:

composer require webman/captcha

The package is a thin integration layer over gregwar/captcha for webman: it ships a controller that renders a PNG captcha, a route (typically GET /captcha), and a Webman\Captcha\Captcha facade with a static check($code) validator. There is no migration, no service provider to register manually, and no model. If the host runs PHP 8.4, require ^1.0.5 explicitly — earlier tags predate 8.4 support.

First things to inspect, in this order:

  1. The plugin config — look under config/plugin/webman/captcha/ (and the package's own config/ directory in vendor/webman/captcha/ if the override file was not copied). This is where you choose the storage backend (session vs redis), the code length, image width/height, charset, expiry, and the session/redis key name.
  2. src/Captcha.php — this is where the phrase is generated, stored, and compared. It is a few hundred lines; read it once and you own the behavior.
  3. The bundled controller — it decides the route path, the Content-Type, and whether cache headers are set.

The canonical first use case is a login or registration form. Add the image to your template:

<img src="/captcha" alt="captcha" onclick="this.src='/captcha?t='+Date.now()">

and validate in the controller before you authenticate:

use Webman\Captcha\Captcha;

public function login(Request $request)
{
    if (!Captcha::check($request->post('captcha'))) {
        return json(['code' => 1, 'msg' => '验证码错误']);
    }
    // ...authenticate
}

If /captcha returns a 404, the plugin's route was not loaded — check route ordering in config/route.php and confirm the plugin directory exists under config/plugin/.

Implementation Patterns

Storage mode is the first decision. Session mode is the default and is fine for a single-instance deployment. Because webman runs multiple worker processes, you need webman/session (backed by Redis or a shared file store) so the phrase written by one worker is visible to the worker that validates it. If you are behind a load balancer or run more than one host, switch the plugin to its Redis storage mode and make sure the webman/redis pool it references is configured. Session-based captchas behind a sticky-less LB will fail intermittently — that symptom almost always means the storage mode is wrong, not the captcha itself.

Consume the code exactly once. Captcha::check() in most versions compares and returns; it does not necessarily delete the key. Delete or overwrite the stored phrase yourself after a successful check so a captured code cannot be replayed:

if (Captcha::check($code)) {
    Session::forget('captcha'); // or the configured key name
}

Wrap validation in a reusable rule. For forms with several entry points, put the check in a request validator or a small middleware so every controller does not re-implement it:

// app/middleware/CaptchaCheck.php
if ($request->method() === 'POST' && !Captcha::check($request->post('captcha'))) {
    return response('captcha invalid', 422);
}

Apply it selectively via route middleware, not globally — you do not want it firing on asset or API routes.

SPA / JSON clients. <img src> works, but an API consumer usually wants base64. Two options: point the client at /captcha with Cache-Control: no-store and read the src, or generate the builder yourself in a custom controller (new \Gregwar\Captcha\CaptchaBuilder($phrase), ->build(), ->get() for PNG bytes, ->inline()/->output() for a data URI). For key-based stateless APIs, store the phrase in Redis under a UUID you return to the client alongside the image, and validate the UUID + code pair — this avoids depending on cookies entirely.

Customize through config, not by patching. Width, height, length, and charset are all config values. If you need a different route, different fonts, or a JSON response, write your own controller and leave the plugin's route unregistered; the underlying CaptchaBuilder exposes font, distortion, and background options you can pass through.

Layer it with rate limiting. A captcha is a speed bump, not bot protection. Pair it with webman/rate-limiter on the login endpoint, and consider a slider/interactive challenge for high-value flows — the plugin only produces a fixed-phrase image.

Gotchas and Tips

  • GD is mandatory. Confirm extension=gd (with FreeType for TTF fonts) is enabled in the PHP CLI that runs webman. A missing GD surfaces as a blank image or a worker exception, not a friendly error.
  • Image generation is CPU-bound inside the worker. Each request rasterizes a PNG synchronously. On a login endpoint under attack, you are effectively paying CPU for every unauthenticated request — rate-limit before the captcha generates, and keep the image small.
  • Browser caching of GET /captcha. Without Cache-Control: no-store, Chrome and proxies will happily reuse the previous image. Always append a cache-busting query (?t=...) or set the header explicitly.
  • Case sensitivity. The Gregwar phrase is mixed-case by default. Decide now whether comparison is case-insensitive (normalize both sides) and keep it consistent with your charset config — switching to lowercase-only characters removes a whole class of user complaints.
  • One key, one form. If two tabs both load the captcha, the second overwrites the first and the first submission fails. Use distinct keys per form, or accept that this is a known limitation and surface a clean error.
  • Order operations correctly at login. Validate the captcha before Session::regenerate() — regenerating first can drop the stored phrase and produce a "wrong captcha" error on a correct code.
  • Route collisions. The plugin registers a global /captcha route. If you already have a controller on that path, one silently shadows the other. Fix the ordering in config/route.php or change the plugin's route.
  • Never log the phrase. Debug dumps of session data or the builder object will leak the answer into logs; scrub it from any request-logging middleware.
  • Testing. You cannot read the image in CI. Add a dev-only fixed-phrase switch in config (or mock Captcha::check in your test harness) rather than disabling captchas in production.
  • Pin and vendor. With 13 stars and no dependents, this is a small-surface package — that is an advantage: read all of it. It pins gregwar/captcha, which sees infrequent releases, so lock versions in composer.json and be prepared to fork (MIT) if PHP-version deprecations appear. Keep your own controller thin so a future swap to a different captcha library is a one-file change.
  • PHP 8.4 support arrived in v1.0.5. That release is a compatibility bump only — no API, config, or route changes — so it is a drop-in upgrade from 1.0.4. If you are on PHP 8.4, require ^1.0.5 or newer rather than leaving the constraint open down to older tags; if you are on 8.1–8.3, the upgrade is still worth taking but changes nothing for you. Test on 8.4 in CI before rolling it to workers that generate images, since GD/FreeType behavior is the piece most likely to differ across PHP minors.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource