germey/geetest
germey/geetest provides a Laravel integration for Geetest CAPTCHA, adding server-side validation rules, Blade helpers, and configuration for Geetest slider verification. It helps protect forms and APIs from automated abuse with minimal setup.
composer require germey/geetest
php artisan vendor:publish --provider="Germey\Geetest\GeetestServiceProvider"
Laravel 5.5+ discovers Germey\Geetest\GeetestServiceProvider automatically. On 5.4 and below, add the provider to config/app.php and register the alias:
'Geetest' => Germey\Geetest\Facades\Geetest::class,
Then put your credentials in .env and wire them into the published config/geetest.php:
GEETEST_ID=xxxxxxxxxxxxxxxx
GEETEST_KEY=xxxxxxxxxxxxxxxx
// config/geetest.php
return [
'id' => env('GEETEST_ID'),
'key' => env('GEETEST_KEY'),
];
Where to look first, in order:
config/geetest.php — the only file you should normally touch.php artisan route:list | grep -i geetest — the package ships the register/validate handshake endpoints; know their URIs before your front end calls them.vendor/germey/geetest/src/Geetest.php — the two primitives are always "issue a challenge" and "verify challenge/validate/seccode". If a method name in this doc doesn't match your installed version, this file is the source of truth.First use case — protect the login form:
<form method="POST" action="/login">
@csrf
<input name="email">
<input name="password" type="password">
{!! Geetest::render() !!}
<button type="submit">Log in</button>
</form>
public function login(Request $request)
{
$request->validate(['email' => 'required', 'password' => 'required']);
$ok = Geetest::validate(
$request->input('geetest_challenge'),
$request->input('geetest_validate'),
$request->input('geetest_seccode')
);
if (! $ok) {
return back()->withErrors(['geetest' => 'Please complete the verification.']);
}
// proceed with Auth::attempt(...)
}
Geetest::render() emits the container div plus the JS that calls the package's challenge endpoint. Publish the package views if you need to change markup or pin a different Geetest script version.
Reusable validation rule. Keeps controllers clean and composes with FormRequest:
class GeetestRule implements Rule
{
public function passes($attribute, $value)
{
return Geetest::validate(
request('geetest_challenge'),
request('geetest_validate'),
request('geetest_seccode')
);
}
public function message()
{
return 'Captcha verification failed.';
}
}
$request->validate([
'email' => 'required|email',
'password' => 'required',
'geetest' => [new GeetestRule],
]);
Middleware for route groups. Better than sprinkling calls when several endpoints (register, password reset, checkout) need protection:
class VerifyGeetest
{
public function handle($request, Closure $next)
{
$ok = Geetest::validate(
$request->input('geetest_challenge'),
$request->input('geetest_validate'),
$request->input('geetest_seccode')
);
if (! $ok) {
return $request->expectsJson()
? response()->json(['message' => 'Captcha failed'], 422)
: back()->withErrors(['geetest' => 'Captcha failed'])->withInput();
}
return $next($request);
}
}
SPA / API clients. The bundled routes are web-oriented (session, CSRF). For a Vue/React front end, expose your own JSON endpoints that call the underlying library, and pass client_type => 'web' (or 'native') plus the caller's IP in the pre-process payload. Do not try to reuse the package's form view from an API route.
Re-challenge on failure. A Geetest token is single use. After a failed login or failed captcha, return the form and let the widget re-register — don't try to validate the same geetest_validate twice.
Testing. Mock the facade so feature tests don't hit Geetest's servers:
Geetest::shouldReceive('validate')->once()->andReturn(true);
$this->post('/login', [...])->assertRedirect('/home');
Also add a negative test with andReturn(false) asserting the 302 back with errors.
get.php/validate.php flow may not behave as expected. Confirm which product version your key belongs to before debugging your own code.illuminate/* requirement is ^5.x. On Laravel 9+ installation will fail or need --ignore-platform-reqs (which is a red flag for production). Treat this as a Laravel 5–8 package.api group or you cache routes without sessions, validation silently fails every time. Verify with route:list -v.web group or lacks the token. Either include the token in your layout <meta> or exempt that URI in VerifyCsrfToken.false on failback turns a third-party outage into a total login outage; blindly returning true disables the captcha during attacks.config/geetest.php, run php artisan config:clear. Stale cached IDs produce "invalid key" responses that look like network errors.geetest_challenge/geetest_validate/geetest_seccode before calling validate(); a request that skips the widget will otherwise throw rather than fail validation.https:// on HTTPS pages or the browser blocks it as mixed content, leaving a permanently empty widget.throttle middleware or login attempt lockouts — pair them.geetest); if you already own that path, override or rename yours rather than fighting the service provider.How can I help you explore Laravel packages today?