如何在 PHPMailer 6 表单中正确集成 reCAPTCHA v2 验证

轻宇大大_5945

轻宇大大_5945

2026-07-22

876人浏览

原创

如何在 PHPMailer 6 表单中正确集成 reCAPTCHA v2 验证

本文详解如何在基于 phpmailer 6 的多附件联系表单中,可靠实现 google recaptcha v2 服务端验证,避免验证码被忽略或表单无校验提交的问题。

本文详解如何在基于 phpmailer 6 的多附件联系表单中,可靠实现 google recaptcha v2 服务端验证,避免验证码被忽略或表单无校验提交的问题。

在实际开发中,许多开发者成功集成了 PHPMailer 发送邮件及多文件上传功能,却常因遗漏关键验证环节而导致 reCAPTCHA v2 形同虚设——表单无论是否勾选验证码均能提交。根本原因在于:前端渲染的 reCAPTCHA 组件仅生成 token,真正的验证必须由后端主动调用 Google 的 siteverify API 完成,且该逻辑必须置于邮件发送流程之前,并严格控制执行路径。

以下是完整、可落地的解决方案:

✅ 正确的 reCAPTCHA v2 集成流程

  1. 前端确保 token 正确提交
    您的 HTML 中

    使用正确,但需确认:
    • data-sitekey 值为 Google Cloud Console 中为您的域名注册的 Site Key(非 Secret Key);
    • 表单 method="post" 且未被 JavaScript 意外拦截(如 event.preventDefault() 后未手动提交);
    • 提交时,Google 自动将一次性 token 注入 $_POST['g-recaptcha-response'] —— 这是后端验证的唯一依据。
  2. 后端必须进行强制服务端验证
    您原代码中存在两个关键缺陷:

    • if(isset($_POST['submit'], $_POST['g-recaptcha-response'])) 条件块未包裹全部业务逻辑,导致即使验证失败,后续邮件代码仍可能执行;
    • 变量名笔误:$captchResult(少一个 a)导致条件判断恒为 false,无法进入邮件发送分支。

    ✅ 正确写法如下(已修复逻辑与命名):

  3. <?php use PHPMailer\PHPMailer\PHPMailer;
    use PHPMailer\PHPMailer\Exception;
    
    require './src/Exception.php';
    require './src/PHPMailer.php';
    require './src/SMTP.php';
    
    class ReCaptchaValidator
    {
        private $secretKey = 'YOUR_SECRET_KEY_HERE'; // 替换为 Google 控制台获取的 Secret Key
    
        public function verify($response): bool
        {
            if (empty($response)) {
                return false;
            }
    
            $url = 'https://www.google.com/recaptcha/api/siteverify';
            $data = [
                'secret' => $this->secretKey,
                'response' => $response,
                'remoteip' => $_SERVER['REMOTE_ADDR'] ?? ''
            ];
    
            $options = [
                'http' => [
                    'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
                    'method'  => 'POST',
                    'content' => http_build_query($data)
                ]
            ];
    
            $context = stream_context_create($options);
            $result = file_get_contents($url, false, $context);
    
            if ($result === false) {
                error_log('reCAPTCHA verification request failed');
                return false;
            }
    
            $responseJson = json_decode($result, true);
            return $responseJson['success'] ?? false;
        }
    }
    
    // ⚠️ 关键:所有业务逻辑必须在此验证通过后执行
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
        $recaptchaResponse = $_POST['g-recaptcha-response'] ?? '';
    
        $recaptcha = new ReCaptchaValidator();
        if (!$recaptcha->verify($recaptchaResponse)) {
            die('❌ reCAPTCHA 验证失败,请重试。');
        }
    
        // ✅ 验证通过,继续处理邮件
        try {
            $mail = new PHPMailer(true);
            $mail->isSMTP();
            $mail->Host       = 'in-v3.mailjet.com';
            $mail->SMTPAuth   = true;
            $mail->Username   = 'YOUR_MAILJET_API_KEY';
            $mail->Password   = 'YOUR_MAILJET_API_SECRET';
            $mail->SMTPSecure = 'tls';
            $mail->Port       = 587;
    
            $mail->setFrom($_POST['email'] ?? 'no-reply@example.com', $_POST['name'] ?? 'Anonymous');
            $mail->addAddress('your-email@example.com'); // 收件人
            $mail->addReplyTo($_POST['email'], $_POST['name']);
    
            // ✅ 安全处理附件:使用 $_FILES['attachment'] 而非硬编码 'userfile'
            if (!empty($_FILES['attachment']['name'][0])) {
                foreach ($_FILES['attachment']['tmp_name'] as $key => $tmpName) {
                    if (is_uploaded_file($tmpName) && $_FILES['attachment']['error'][$key] === UPLOAD_ERR_OK) {
                        $mail->addAttachment($tmpName, $_FILES['attachment']['name'][$key]);
                    }
                }
            }
    
            $mail->isHTML(true);
            $mail->Subject = '网站咨询表单提交';
            $mail->Body = <strong>发件人:</strong>{$_POST['name'] ?? 'N/A'}
    <p><strong>公司:</strong>{$_POST['company'] ?? 'N/A'}</p><div class="aritcle_card flexRow artxards">
    											<div class="artcardd flexRow">
    												<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2138" title="PHP"><img
    														src="https://img.php.cn/upload/skill/000/000/081/178884013267959.jpg" alt="PHP" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
    												<div class="aritcle_card_info flexColumn">
    													<a rel="nofollow" href="/xiazai/skill2138" title="PHP" class="overflowclass">PHP</a>
    													<p class="overflowclass">编写健壮的PHP代码,规避类型转换陷阱、数组怪癖及常见安全漏洞。</p>
    												</div>
    												<a rel="nofollow" href="/xiazai/skill2138" title="PHP" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
    												</a>
    											</div>
    										</div>
    <p><strong>电话:</strong>{$_POST['phone'] ?? 'N/A'}</p>
    <p><strong>邮箱:</strong>{$_POST['email'] ?? 'N/A'}</p>
    <p><strong>留言:</strong><br>{nl2br(htmlspecialchars($_POST['message'] ?? ''))}</p>
    HTML;
    
            $mail->send();
            header('Location: thank.html');
            exit;
        } catch (Exception $e) {
            http_response_code(500);
            echo "邮件发送失败:{$mail->ErrorInfo}";
        }
    } else {
        http_response_code(400);
        echo '❌ 无效请求:请通过表单提交。';
    }
    ?>

    ⚠️ 关键注意事项

    • Secret Key 保密性:$secretKey 必须严格保密,绝不可暴露在前端或公开仓库中;建议通过环境变量加载(如 getenv('RECAPTCHA_SECRET'))。
    • 附件字段名一致性:HTML 中 对应 PHP 中 $_FILES['attachment'],原代码误用 'userfile' 导致附件丢失。
    • 错误处理增强:使用 file_get_contents() 替代 cURL 可减少依赖,但需确保 allow_url_fopen=On;若禁用,可回退至 cURL(注意启用 CURLOPT_SSL_VERIFYPEER=false 仅用于测试,生产环境应配置 CA 证书)。
    • 用户体验优化:前端可添加简单 JS 校验(如检查 grecaptcha.getResponse() 是否为空),但不能替代服务端验证——它仅作辅助,防止明显恶意绕过。
    • 调试技巧:临时开启 error_log(print_r($_POST, true)); 查看是否收到 g-recaptcha-response;用 var_dump($responseJson) 检查 Google 返回结构(含 error-codes 字段,如 invalid-input-secret 表示密钥错误)。

    通过以上重构,reCAPTCHA v2 将真正成为表单提交的第一道安全闸门,有效抵御自动化垃圾邮件攻击,同时保持 PHPMailer 多附件功能完整可用。

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

8944

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

5461

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

1995

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

3368

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4034

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3171

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

4477

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

3502

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

11562

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程