Skip to content
Myra EU CAPTCHA Online Help Updated · 25 Aug 2026

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:

EUCAPTCHA_SITE_KEY=YOUR_SITEKEY
EUCAPTCHA_SECRET_KEY=YOUR_SECRET

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:

public function submit(ContactRequest $request): RedirectResponse
{
    // validation and CAPTCHA check already passed
    // process the form...

    return redirect()->route('contact.success');
}