Symfony and Laravel¶
Symfony and Laravel use the same myra-security-gmbh/eu-captcha package as each other application with PHP 8. The two frameworks have their own function to get the IP address of the visitor, which you give to validate().
Requirements¶
The following requirements must be met:
| Requirement | Value |
|---|---|
| PHP | From version 8.0 |
| Package | myra-security-gmbh/eu-captcha |
| Credentials | Public sitekey and secret from the Details view |
The installation of the package is given in PHP.
Symfony¶
In your services and controllers, use the EuCaptchaInterface type. Then Symfony connects the service automatically. Your source code does not depend on the applicable class.
Enter the service in config/services.yaml and point the interface to it:
services:
Myrasec\EuCaptcha:
arguments:
$sitekey: '%env(EUCAPTCHA_SITE_KEY)%'
$secret: '%env(EUCAPTCHA_SECRET_KEY)%'
Myrasec\EuCaptchaInterface: '@Myrasec\EuCaptcha'
Give the interface to the controller:
<?php
namespace App\Controller;
use Myrasec\EuCaptchaInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ContactController
{
public function __construct(private EuCaptchaInterface $captcha) {}
#[Route('/contact', methods: ['POST'])]
public function submit(Request $request): Response
{
$result = $this->captcha->validate(
$request->request->getString('eu-captcha-response'),
$request->getClientIp() ?? '',
);
if (!$result->success()) {
return new Response('CAPTCHA verification failed', Response::HTTP_BAD_REQUEST);
}
// process the form...
return new Response('OK');
}
}
$request->getClientIp() obeys the setting of the trusted upstream systems of Symfony. Thus, behind a CDN or a load balancer, the true IP address of the visitor goes to the API. As the third argument, validate() also accepts the identifier of the browser.
Laravel¶
Put the credentials in the .env file and publish them with config/services.php.
The .env file:
The config/services.php file:
'eucaptcha' => [
'sitekey' => env('EUCAPTCHA_SITE_KEY'),
'secret' => env('EUCAPTCHA_SECRET_KEY'),
],
Verify the token in the controller:
<?php
namespace App\Http\Controllers;
use Myrasec\EuCaptcha;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
class ContactController extends Controller
{
public function submit(Request $request): RedirectResponse
{
$captcha = new EuCaptcha(
sitekey: config('services.eucaptcha.sitekey'),
secret: config('services.eucaptcha.secret'),
);
$result = $captcha->validate(
$request->input('eu-captcha-response'),
$request->ip(),
);
if (!$result->success()) {
return back()->withErrors(['captcha' => 'CAPTCHA verification failed.']);
}
// process the form...
return redirect()->route('contact.success');
}
}
$request->ip() obeys the setting of the trusted upstream systems of Laravel.
Verification in a form request¶
For more than one controller, put the verification in its own FormRequest:
<?php
namespace App\Http\Requests;
use Myrasec\EuCaptcha;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
class ContactRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email'],
'message' => ['required', 'string'],
];
}
protected function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator) {
$captcha = new EuCaptcha(
sitekey: config('services.eucaptcha.sitekey'),
secret: config('services.eucaptcha.secret'),
);
$result = $captcha->validate(
$this->input('eu-captcha-response'),
$this->ip(),
);
if (!$result->success()) {
$validator->errors()->add('captcha', 'CAPTCHA verification failed.');
}
});
}
}
Then give ContactRequest to the method of the controller instead of Request. Laravel then verifies the request before it calls the method: