在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
相关产品推荐
相关产品推荐

