You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Grav中为Zammad反馈表单集成hCaptcha的技术实现咨询

在Grav中为Zammad表单集成hCaptcha的正确API接入方式

看起来你已经搞定了Zammad表单的基础功能,现在卡在Grav插件的事件绑定和逻辑处理上了。我来帮你理清Grav的插件机制,把hCaptcha的验证逻辑正确接入进去。

首先,Grav的插件需要正确注册事件才能被触发,你的onFormProcessed函数本身逻辑没问题,但缺少了事件订阅的步骤,而且直接输出JSON也不符合Grav的表单处理流程。下面是完整的解决方案:

1. 正确编写Grav插件的事件订阅

Grav插件必须通过类的getSubscribedEvents方法声明要监听的事件,这样系统才会在表单处理时调用你的方法。创建或修改你的hCaptcha插件主文件(比如hcaptcha.php):

<?php
namespace Grav\Plugin;

use Grav\Common\Plugin;
use RocketTheme\Toolbox\Event\Event;

class HCaptchaPlugin extends Plugin
{
    // 订阅表单处理事件
    public static function getSubscribedEvents(): array
    {
        return [
            'onFormProcessed' => ['onFormProcessed', 0]
        ];
    }

    // 表单处理时触发的方法
    public function onFormProcessed(Event $event)
    {
        // 这里放你的验证逻辑,下面会修改
    }
}

2. 修改hCaptcha验证逻辑(适配Grav流程)

把你原来的验证逻辑调整成符合Grav表单处理的方式:不要直接输出JSON,而是用Grav的表单错误机制阻止提交,同时显示错误信息。另外,建议用cURL代替file_get_contents,因为后者在部分服务器环境中可能被禁用:

public function onFormProcessed(Event $event)
{
    // 只处理你的Zammad反馈表单(替换成你的表单name)
    $form = $event['form'];
    if ($form->getName() !== 'zammad-feedback-form') {
        return;
    }

    $err_msg = '';

    // 检查hCaptcha响应是否存在
    if (!isset($_POST['h-captcha-response']) || empty($_POST['h-captcha-response'])) {
        $err_msg = '请完成hCaptcha验证';
    } else {
        // 替换为你的hCaptcha密钥
        $secret = '0x0000000000000000000000000000000000000000';
        $remote_address = $_SERVER['REMOTE_ADDR'];
        
        // 构建验证请求(用urlencode避免参数拼接错误)
        $verify_url = sprintf(
            'https://hcaptcha.com/siteverify?secret=%s&response=%s&remoteip=%s',
            urlencode($secret),
            urlencode($_POST['h-captcha-response']),
            urlencode($remote_address)
        );

        // 用cURL发送请求更可靠
        $ch = curl_init($verify_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);

        if (!$response) {
            $err_msg = 'hCaptcha验证请求失败,请稍后重试';
        } else {
            $responseData = json_decode($response);
            if (!$responseData || !$responseData->success) {
                $err_msg = 'hCaptcha验证失败,请重新尝试';
                // 可选:显示具体错误码帮助排查
                if (isset($responseData->{'error-codes'})) {
                    $err_msg .= '(错误码:' . implode(', ', $responseData->{'error-codes'}) . ')';
                }
            }
        }
    }

    // 如果有错误,阻止表单提交并添加错误消息
    if (!empty($err_msg)) {
        $form->addError($err_msg);
        $event->stopPropagation(); // 停止后续表单处理(包括提交到Zammad)
        return;
    }

    // 验证通过,表单会继续正常提交到Zammad
    $this->grav['messages']->add('验证通过,正在提交反馈...', 'success');
}

3. 前端添加hCaptcha组件

别忘了在你的Zammad表单HTML中加入hCaptcha的渲染代码(替换成你的站点密钥):

<!-- 在表单内添加hCaptcha容器 -->
<div class="h-captcha" data-sitekey="你的hCaptcha站点密钥"></div>
<!-- 加载hCaptcha脚本 -->
<script src="https://hcaptcha.com/1/api.js" async defer></script>

关键注意点

  • 事件优先级:getSubscribedEvents中的第二个参数0是事件优先级,确保你的验证在表单提交到Zammad之前执行。
  • 表单过滤:通过$form->getName()只处理目标表单,避免影响Grav中其他表单的功能。
  • 错误处理:使用$form->addError()添加的错误会自动显示在表单页面上,比直接输出JSON更符合Grav的用户体验。

这样调整后,你的hCaptcha插件就能在表单提交时自动触发验证,只有验证通过的表单才会被提交到Zammad。

内容的提问来源于stack exchange,提问作者Flora Faßbender

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 15:32:37