dario_swain/re-captcha-library
PHP backend client for Google reCAPTCHA v2. Validate the user’s g-recaptcha-response token against Google using your secret key (optionally passing the client IP) to confirm form submissions and block bots. Composer-installable and lightweight.
Install the package via Composer:
composer require dario_swain/re-captcha-library:2.0.*
Configure .env:
RECAPTCHA_SECRET_KEY=your_private_key_here
RECAPTCHA_SITE_KEY=your_site_key_here
Bind the service in AppServiceProvider:
use DS\Library\ReCaptcha\Client;
use DS\Library\ReCaptcha\Http\Client\Guzzle\GuzzleClient;
public function register()
{
$this->app->singleton(Client::class, function ($app) {
$guzzleClient = new GuzzleClient();
return new Client(config('services.recaptcha.key'), $guzzleClient);
});
}
First use case: Validate a form submission in a controller:
use DS\Library\ReCaptcha\Client;
use DS\Library\ReCaptcha\ValidationException;
public function store(Request $request, Client $reCaptcha)
{
try {
$valid = $reCaptcha->validate($request->input('g-recaptcha-response'), $request->ip());
if (!$valid) {
return back()->withErrors(['captcha' => 'CAPTCHA verification failed']);
}
// Proceed with form submission
} catch (ValidationException $e) {
return back()->withErrors(['captcha' => $e->getMessage()]);
}
}
Frontend: Include the ReCAPTCHA widget in your Blade template:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey="{{ config('services.recaptcha.site_key') }}"></div>
g-recaptcha-response token in your form request.use Illuminate\Foundation\Http\FormRequest;
use DS\Library\ReCaptcha\Client;
use DS\Library\ReCaptcha\ValidationException;
class ContactFormRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'g-recaptcha-response' => 'required|recaptcha',
];
}
public function validateRecaptcha()
{
$reCaptcha = app(Client::class);
try {
$valid = $reCaptcha->validate($this->input('g-recaptcha-response'), $this->ip());
if (!$valid) {
$this->addError('g-recaptcha-response', 'CAPTCHA verification failed');
}
} catch (ValidationException $e) {
$this->addError('g-recaptcha-response', $e->getMessage());
}
}
}
Create middleware to validate ReCAPTCHA for specific routes:
php artisan make:middleware ValidateRecaptcha
// app/Http/Middleware/ValidateRecaptcha.php
public function handle($request, Closure $next)
{
$reCaptcha = app(Client::class);
try {
$valid = $reCaptcha->validate($request->input('g-recaptcha-response'), $request->ip());
if (!$valid) {
return redirect()->back()->withErrors(['captcha' => 'CAPTCHA verification failed']);
}
} catch (ValidationException $e) {
return redirect()->back()->withErrors(['captcha' => $e->getMessage()]);
}
return $next($request);
}
Register the middleware in app/Http/Kernel.php:
protected $routeMiddleware = [
'recaptcha' => \App\Http\Middleware\ValidateRecaptcha::class,
];
Apply it to routes:
Route::post('/contact', [ContactController::class, 'store'])->middleware('recaptcha');
Extend the package’s ClientInterface for custom HTTP logic (e.g., logging, retries):
use DS\Library\ReCaptcha\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Client as GuzzleClient;
class CustomReCaptchaClient implements ClientInterface
{
protected $client;
public function __construct()
{
$this->client = new GuzzleClient([
'timeout' => 5.0,
'headers' => [
'User-Agent' => 'MyApp/1.0',
],
]);
}
public function send(RequestInterface $request)
{
$response = $this->client->send(
$request,
['http_errors' => false]
);
return new CustomResponse($response);
}
}
Bind the custom client in AppServiceProvider:
$this->app->singleton(Client::class, function ($app) {
$customClient = new CustomReCaptchaClient();
return new Client(config('services.recaptcha.key'), $customClient);
});
Deprecated PHP Features:
error_reporting). Test with PHP 8.x and update if needed.php-compat or fork the package.Guzzle Version Conflicts:
composer.json:
"replace": {
"guzzlehttp/guzzle": "6.*"
}
IP Address Issues:
REMOTE_ADDR may not reflect the user’s actual IP if behind a proxy (e.g., Cloudflare, Nginx).trusted proxies config:
'trust_proxies' => true,
Then use $request->ip() instead of $_SERVER['REMOTE_ADDR'].Rate Limiting:
$cacheKey = "recaptcha:{$ip}:{$response}";
if (Cache::has($cacheKey)) {
return Cache::get($cacheKey);
}
$valid = $reCaptcha->validate($response, $ip);
Cache::put($cacheKey, $valid, now()->addMinutes(5));
Frontend Token Submission:
g-recaptcha-response token is included in the form submission.<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response">
Use JavaScript to populate it:
document.getElementById('g-recaptcha-response').value = grecaptcha.getResponse();
Error Handling:
ValidationException for failed validations. Ensure your error handling is robust.catch (ValidationException $e) {
\Log::error('ReCAPTCHA validation failed: ' . $e->getMessage());
return back()->withErrors(['captcha' => 'CAPTCHA verification failed']);
}
Enable Guzzle Debugging: Add middleware to log HTTP requests/responses:
$reCaptchaClient = new Client($privateKey, new GuzzleClient([
'on_stats' => function (GuzzleHttp\Message\RequestInterface $request, GuzzleHttp\Message\ResponseInterface $response) {
\Log::debug('ReCAPTCHA Request:', [$request->getUri(), $response->getBody()->getContents()]);
}
]));
Test with Google’s Test Keys:
Use Google’s test keys (6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI) to simulate valid/invalid responses during development.
Validate the Response Manually:
Use Google’s test form to verify your sitekey and secretkey are correct.
Client class to add custom validation rules (e.g., score thresholds for v3):
class ExtendedReCaptchaClient extends Client
{
public function validateWithScore($response, $ip, $minScore = 0.5)
{
$result = parent::validate($response, $ip);
if (
How can I help you explore Laravel packages today?