myra-security-gmbh/eu-captcha 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

myra-security-gmbh/eu-captcha

Composer 安装命令:

composer require myra-security-gmbh/eu-captcha

包简介

EU captcha protects your website/API against abuse like form spam and credential stuffing

README 文档

README

Privacy-first, no-cookie, no-manual-interaction bot protection for PHP 8.0+ applications. Automatically filters bots, spam, and credential-stuffing attempts without requiring any user interaction.

Requirements

  • PHP 8.0 or later
  • Guzzle (guzzlehttp/guzzle ^6.0 or ^7.0)

Installation

Note: This package requires PHP 8.0 or newer. If you are running PHP 5.0–7.x, use myra-security-gmbh/eu-captcha-old instead, which supports PHP 5.0+ via file_get_contents().

composer require myra-security-gmbh/eu-captcha

Getting credentials

  1. Register at app.eu-captcha.eu
  2. Create a site and copy the sitekey and secret from the dashboard

Quick start

Using a SPA framework? The script tag and <div> approach below is for server-rendered pages. If you are building with React, Vue, or Angular, use the matching npm package for the frontend widget and continue to use this package for server-side verification only. See SPA integration guides for details.

Add the widget script to any page that contains a form you want to protect:

<script src="https://cdn.eu-captcha.eu/verify.js" async defer></script>

Place the widget inside your form:

<div class="eu-captcha" data-sitekey="EUCAPTCHA_SITE_KEY"></div>

Verify the submitted token on your server:

<?php

use Myrasec\EuCaptcha;

$captcha = new EuCaptcha(
    sitekey: EUCAPTCHA_SITE_KEY,
    secret:  EUCAPTCHA_SECRET_KEY,
);

$result = $captcha->validate();

if (!$result->success()) {
    // Reject the form submission
}

validate() reads the token automatically from $_POST['eu-captcha-response'] and the client IP from server headers, so no extra wiring is needed in the common case.

Configuration options

All options are passed as named constructor arguments.

Option Type Default Description
sitekey string Required. Public sitekey from the dashboard.
secret string Required. Secret key from the dashboard. Never expose this client-side.
failDefault bool true Return value used for both network and token state when the API cannot be reached. true = fail open (allow on error); false = fail closed (deny on error).
checkCdnHeaders bool true When true, the client IP is resolved from CDN/proxy headers (HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR, HTTP_X_REAL_IP) before falling back to REMOTE_ADDR. Set to false when your server is not behind a proxy, or when you pass the IP explicitly.
verifyUrl string (production URL) Override the EU Captcha verify endpoint. Useful for testing.
credentialsUrl string (production URL) Override the EU Captcha verify-credentials endpoint.
client ?Client null Optional Guzzle client instance for custom configuration or testing.

The result object

validate() returns an EuCaptchaResult with three methods:

Method Returns true when…
success() The API was reached and the token is valid.
successNetwork() The API call completed without a network or transport error.
successToken() The API reported the submitted token as valid.

Checking both states separately lets you distinguish a user failing the captcha from an API outage:

<?php

$result = $captcha->validate();

if (!$result->successNetwork()) {
    // Could not reach the API — consider logging or alerting
}

if (!$result->successToken()) {
    // Token was rejected — the submission is likely automated
}

Explicit token and IP

Pass the token and client IP explicitly when you need full control (e.g. non-standard form field names or API endpoints):

<?php

$token    = $_POST['my-captcha-field'] ?? '';
$clientIp = $_SERVER['REMOTE_ADDR'];

$result = $captcha->validate($token, $clientIp);

Verifying credentials

Use verifyCredentials() to confirm your sitekey and secret are valid without submitting a client token. This is useful for startup or configuration checks:

<?php

$captcha = new EuCaptcha(sitekey: EUCAPTCHA_SITE_KEY, secret: EUCAPTCHA_SECRET_KEY);

if (!$captcha->verifyCredentials()) {
    // Credentials are invalid or the API is unreachable — log and alert
}

verifyCredentials() returns false on any network or API error rather than throwing, so it is safe to call during application initialisation.

Symfony

Type-hint EuCaptchaInterface in your services and controllers so Symfony can autowire the client without coupling your code to the concrete class.

Register EuCaptcha as a service and alias the interface to it in config/services.yaml:

services:
    Myrasec\EuCaptcha:
        arguments:
            $sitekey: '%env(EUCAPTCHA_SITE_KEY)%'
            $secret:  '%env(EUCAPTCHA_SECRET_KEY)%'
    Myrasec\EuCaptchaInterface: '@Myrasec\EuCaptcha'

Inject the interface into a 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() respects Symfony's trusted-proxy configuration, so the real visitor IP is forwarded correctly when running behind a CDN or load balancer. Pass the User-Agent as a third argument to validate() if you want to forward it to the API as well.

Laravel

Store credentials in .env and expose them through config/services.php — the Laravel convention for third-party credentials:

.env

EUCAPTCHA_SITE_KEY=YOUR_SITEKEY
EUCAPTCHA_SECRET_KEY=YOUR_SECRET

config/services.php

'eucaptcha' => [
    'sitekey' => env('EUCAPTCHA_SITE_KEY'),
    'secret'  => env('EUCAPTCHA_SECRET_KEY'),
],

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() respects Laravel's trusted-proxy configuration, so the real visitor IP is forwarded correctly when running behind a load balancer or CDN.

Form Request

For reusable validation across multiple controllers, add the CAPTCHA check to a dedicated 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.');
            }
        });
    }
}

Inject ContactRequest instead of Request in your controller method — Laravel resolves and validates it automatically before the method body runs:

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

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

Further reading

License

BSD 2-Clause. See LICENSE for details.

myra-security-gmbh/eu-captcha 适用场景与选型建议

myra-security-gmbh/eu-captcha 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 52 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 02 月 03 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 myra-security-gmbh/eu-captcha 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 myra-security-gmbh/eu-captcha 我们能提供哪些服务?
定制开发 / 二次开发

基于 myra-security-gmbh/eu-captcha 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 52
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 27
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: Unknown
  • 更新时间: 2026-02-03