A flexible and extensible Laravel package for integrating multiple CAPTCHA services including Google reCAPTCHA, hCaptcha, and custom implementations.
- Features
- Major Technologies
- Structure
- Requirements
- Installation
- Configuration
- Environment Variables
- Usage
- Available Drivers
- Creating Custom Drivers
- Validation
- Testing
- API Reference
- Configuration Options
- Troubleshooting
- Contributing
- Repository Branches
- Contributions
- Pull Requests
- License
- Authors
- Code of Conduct
- Security Vulnerabilities
- Support
- 🔒 Multiple CAPTCHA providers (Google reCAPTCHA v2, hCaptcha)
- 🎯 Easy configuration and setup
- 🔧 Extensible architecture for custom CAPTCHA drivers
- 🧪 Testing-friendly with NullCaptcha driver
- 📦 Laravel package auto-discovery support
- 🎨 Facade support for clean syntax
- ⚡ Configurable global enable/disable functionality
- laravel
├───config
├───src
└───tests
├───Feature
└───Unit
- PHP >= 8.3
Install the package via Composer:
composer require thecoderraman/laravel-captcha
Publish the configuration file:
php artisan vendor:publish --provider="TheCoderRaman\Captcha\CaptchaServiceProvider" --tag="config"
The package configuration is located at config/captcha.php
. Here's the basic structure:
<?php
use TheCoderRaman\Captcha\Enums\Captcha;
use TheCoderRaman\Captcha\Drivers\Hcaptcha;
use TheCoderRaman\Captcha\Drivers\ReCaptcha;
use TheCoderRaman\Captcha\Drivers\NullCaptcha;
return [
/*
|--------------------------------------------------------------------------
| Captcha Verification Status
|--------------------------------------------------------------------------
|
| Enable/disable captcha verification globally. When set to false,
| CAPTCHA will be replaced by the NullCaptcha handler.
|
*/
'status' => true,
/*
|--------------------------------------------------------------------------
| Default Captcha Handler
|--------------------------------------------------------------------------
|
| Specify which captcha driver to use as default.
|
*/
'default' => Captcha::NullCaptcha->value,
/*
|--------------------------------------------------------------------------
| CAPTCHA Driver Class Mappings
|--------------------------------------------------------------------------
|
| Maps enum values to their respective driver class implementations.
|
*/
'drivers' => [
Captcha::Hcaptcha->value => Hcaptcha::class,
Captcha::ReCaptcha->value => ReCaptcha::class,
Captcha::NullCaptcha->value => NullCaptcha::class,
],
/*
|--------------------------------------------------------------------------
| Captcha Configurations
|--------------------------------------------------------------------------
|
| Specific configurations for each CAPTCHA service.
|
*/
'captchas' => [
'null' => [
'key' => null,
'secret' => null,
'url' => null,
],
'hcaptcha' => [
'key' => env('HCAPTCHA_SITE_KEY'),
'secret' => env('HCAPTCHA_SECRET_KEY'),
'url' => 'https://hcaptcha.com/siteverify',
],
'recaptcha' => [
'key' => env('RECAPTCHA_SITE_KEY'),
'secret' => env('RECAPTCHA_SECRET_KEY'),
'url' => 'https://www.google.com/recaptcha/api/siteverify',
],
],
];
Add the following environment variables to your .env
file:
# hCaptcha Configuration
HCAPTCHA_SITE_KEY=your_hcaptcha_site_key
HCAPTCHA_SECRET_KEY=your_hcaptcha_secret_key
# Google reCAPTCHA Configuration
RECAPTCHA_SITE_KEY=your_recaptcha_site_key
RECAPTCHA_SECRET_KEY=your_recaptcha_secret_key
<?php
use TheCoderRaman\Captcha\Facades\Captcha;
// Get the default CAPTCHA driver
$captcha = Captcha::driver();
// Get a specific CAPTCHA driver
$hcaptcha = Captcha::driver('hcaptcha');
$recaptcha = Captcha::driver('recaptcha');
// Render CAPTCHA HTML
echo $captcha->getCaptcha();
// Render CAPTCHA scripts
echo $captcha->getScript();
// Render CAPTCHA styles
echo $captcha->getStyle();
// Verify CAPTCHA response
$isValid = $captcha->verify();
<?php
use TheCoderRaman\Captcha\Captcha;
class ContactController extends Controller
{
protected $captcha;
public function __construct(Captcha $captcha)
{
$this->captcha = $captcha;
}
public function showForm()
{
$captchaHtml = $this->captcha->getCaptcha();
$captchaScript = $this->captcha->getScript();
return view('contact.form', compact('captchaHtml', 'captchaScript'));
}
public function submitForm(Request $request)
{
if (!$this->captcha->verify()) {
return back()->withErrors(['captcha' => 'CAPTCHA verification failed.']);
}
// Process form submission
}
}
Create a Blade template for displaying CAPTCHA:
{{-- resources/views/contact/form.blade.php --}}
@extends('layouts.app')
@push('styles')
{!! Captcha::getStyle() !!}
@endpush
@push('scripts')
{!! Captcha::getScript() !!}
@endpush
@section('content')
<form method="POST" action="{{ route('contact.submit') }}">
@csrf
<div class="form-group">
<label for="name">{{ trans('Name') }}</label>
<input type="text" name="name" id="name" class="form-control" required>
</div>
<div class="form-group">
<label for="email">{{ trans('Email') }}</label>
<input type="email" name="email" id="email" class="form-control" required>
</div>
<div class="form-group">
<label for="message">{{ trans('Message') }}</label>
<textarea name="message" id="message" class="form-control" required></textarea>
</div>
{{-- CAPTCHA Section --}}
<div class="form-group">
{!! Captcha::getCaptcha() !!}
@error('captcha') <div class="text-danger">{{ $message }}</div> @enderror
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
@endsection
// Configure in config/captcha.php
'default' => Captcha::ReCaptcha->value,
// Use in controller
$recaptcha = Captcha::driver('recaptcha');
$isValid = $recaptcha->verify();
// Configure in config/captcha.php
'default' => Captcha::Hcaptcha->value,
// Use in controller
$hcaptcha = Captcha::driver('hcaptcha');
$isValid = $hcaptcha->verify();
// Configure in config/captcha.php
'default' => Captcha::NullCaptcha->value,
// This driver always returns true for verification
// Useful for testing and development environments
You can create custom CAPTCHA drivers by extending the base Driver
class:
<?php
namespace App\Captcha\Drivers;
use Illuminate\Http\Request;
use TheCoderRaman\Captcha\Drivers\Driver;
class CustomCaptcha extends Driver
{
protected string $key;
protected string $secret;
protected string $url;
public function __construct(string $key = null, string $secret = null, string $url = null)
{
$this->key = $key;
$this->secret = $secret;
$this->url = $url;
}
public function getCaptcha(): string
{
return '<div class="custom-captcha" data-sitekey="' . $this->key . '"></div>';
}
public function getStyle(): string
{
return '<style>.custom-captcha { /* styles */ }</style>';
}
public function getScript(): string
{
return '<script src="https://example.com/captcha.js"></script>';
}
public function verify(Request $request): bool
{
$response = $request->input('custom-captcha-response');
if (empty($response)) {
return false;
}
$result = $this->client->post($this->url, [
'secret' => $this->secret,
'response' => $response, 'remoteip' => $request->ip(),
]);
return $result->json('success', false);
}
}
Register your custom driver:
// In a service provider
use TheCoderRaman\Captcha\Facades\Captcha;
Captcha::extend('custom', function ($config) {
return new CustomCaptcha(
$config['key'], $config['secret'], $config['url']
);
});
Create a custom validation rule:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use TheCoderRaman\Captcha\Facades\Captcha;
class CaptchaRule implements Rule
{
public function passes($attribute, $value)
{
return Captcha::verify(request());
}
public function message()
{
return 'The CAPTCHA verification failed.';
}
}
Use in your controller:
use App\Rules\CaptchaRule;
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email',
'message' => 'required|string',
'captcha' => ['required', new CaptchaRule],
]);
// Process the validated data
}
The package includes a NullCaptcha
driver for testing purposes:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ContactFormTest extends TestCase
{
use RefreshDatabase;
public function test_contact_form_submission_with_captcha()
{
// Set NullCaptcha for testing
config(['captcha.default' => 'null']);
$response = $this->post('/contact', [
'name' => 'John Doe', 'email' => 'john@example.com', 'message' => 'Test message',
]);
$response->assertStatus(200);
}
}
driver(string $driver = null)
: Get a CAPTCHA driver instanceextend(string $driver, Closure $callback)
: Register a custom drivergetDefaultDriver()
: Get the default driver name
All CAPTCHA drivers implement the DriverInterface
:
getCaptcha(): string
: Render the CAPTCHA HTML widgetgetScript(): string
: Render required JavaScript codegetStyle(): string
: Render required CSS stylesverify(Request $request): bool
: Verify the CAPTCHA response
Option | Type | Default | Description |
---|---|---|---|
status |
boolean | true |
Enable/disable CAPTCHA globally |
default |
string | 'null' |
Default CAPTCHA driver |
drivers |
array | [...] |
Driver class mappings |
captchas |
array | [...] |
Driver-specific configurations |
-
CAPTCHA not displaying
- Check if the site key is correctly configured
- Ensure the driver is properly registered
- Verify that scripts and styles are included
-
Verification always fails
- Verify the secret key is correct
- Check network connectivity to CAPTCHA service
- Ensure the request contains the CAPTCHA response
-
Package not auto-discovered
- Manually register the service provider in
config/app.php
- Clear configuration cache:
php artisan config:clear
- Manually register the service provider in
Enable debug logging by setting the log level in your .env
:
LOG_LEVEL=debug
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
- master -> any pull request of changes this branch
- main -> don´t modify, this is what is running in production
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as appropriate.
- Fork the repo and create your branch:
#[type]/PR description
- Ensure to describe your pull request:
Edit the PR title by adding a semantic prefix like
Added
,Updated:
,Fixed:
etc. Title:#[issue] PR title -> #90 Fixed styles the button
This package is open-sourced software licensed under the MIT license.
In order to ensure that the Laravel Captcha community is welcoming to all, please review and abide by the Code of Conduct.
If you discover a security vulnerability within Laravel Captcha, please send an e-mail to Raman Verma via e-mail. All security vulnerabilities will be promptly addressed.
For support, please open an issue on the GitHub repository.