表单无视Google reCAPTCHA验证仍提交,疑与AJAX验证脚本相关
问题根源及解决方案
你的核心问题出在前端JS没有在表单提交前强制校验reCAPTCHA是否完成验证,同时后端PHP的逻辑顺序也有优化空间,导致即使验证码未通过,请求依然会发送到后端(虽然后端会返回错误,但这会浪费资源,且机器人可以直接绕过前端提交请求)。
1. 前端JS的问题分析与修复
原来的代码依赖validator()插件的默认验证,但该插件并没有包含reCAPTCHA的校验规则,所以即使用户没完成验证码验证,!e.isDefaultPrevented()依然会返回true,导致AJAX请求被触发。
修改后的JS代码如下:
$(function ValidateEmailForm() { window.verifyRecaptchaCallback = function (response) { $('input[data-recaptcha]').val(response).trigger('change') }; window.expiredRecaptchaCallback = function () { $('input[data-recaptcha]').val("").trigger('change') }; $('#contact-form').validator(); $('#contact-form').on('submit', function (e) { // 先阻止默认提交行为 e.preventDefault(); // 1. 检查reCAPTCHA是否已完成验证 const recaptchaResponse = grecaptcha.getResponse(); if (!recaptchaResponse) { $('#contact-form').find('.messages').html( '<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>请完成reCAPTCHA验证后再提交</div>' ); return; } // 2. 检查表单其他字段的验证结果 if (!$(this).validator('validate').has('.has-error').length) { const url = "contact.php"; $.ajax({ type: "POST", url: url, data: $(this).serialize(), success: function (data) { const messageAlert = 'alert-' + data.type; const messageText = data.message; const alertBox = `<div class="alert ${messageAlert} alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>${messageText}</div>`; if (messageAlert && messageText) { $('#contact-form').find('.messages').html(alertBox); $('#contact-form')[0].reset(); grecaptcha.reset(); } } }); } }); });
关键修改点:
- 先调用
e.preventDefault()阻止默认提交,避免意外提交 - 手动检查
grecaptcha.getResponse()的返回值,为空则直接提示错误并终止流程 - 确保表单其他字段通过validator验证后,才发送AJAX请求
2. 后端PHP的逻辑优化
原来的PHP代码是先初始化邮件并尝试发送,再检查reCAPTCHA的验证结果,这会导致即使验证码验证失败,邮件发送的无用操作已经执行。我们需要先验证reCAPTCHA,通过后再处理邮件逻辑:
修改后的PHP代码片段:
try { // 第一步:先验证reCAPTCHA $secretKey = "YOUR_ACTUAL_SECRET_KEY"; // 替换成你的真实密钥 $responseKey = $_POST['g-recaptcha-response']; $userIP = $_SERVER['REMOTE_ADDR']; $url = "https://www.google.com/recaptcha/api/siteverify?secret=$secretKey&response=$responseKey&remoteip=$userIP"; $response = file_get_contents($url); $response = json_decode($response); if (!$response->success) { throw new \Exception('reCAPTCHA验证失败,请重试'); } // 第二步:验证通过后,再处理邮件发送 $mail = new PHPMailer(true); $mail->SMTPDebug = 0; $mail->isSMTP(); $mail->Host = 'YOUR_SMTP_HOST'; $mail->SMTPAuth = true; $mail->Username = 'YOUR_SMTP_USER'; $mail->Password = 'YOUR_SMTP_PASS'; $mail->SMTPSecure = 'ssl'; $mail->Port = 465; $mail->WordWrap = 50; $mail->Priority = 1; $mail->CharSet = 'utf-8'; $mail->setFrom('YOUR_FROM_EMAIL', 'YOUR_FROM_NAME'); $mail->addAddress('YOUR_TARGET_EMAIL'); $mail->addReplyTo($email); $mail->isHTML(true); $mail->Subject = 'NY BESKED - EXAMPLE'; $mail->Body = 'YOUR_HTML_BODY_CONTENT'; $mail->AltBody = 'YOUR_PLAIN_TEXT_BODY_CONTENT'; $mail->send(); $responseArray = array('type' => 'success', 'message' => $okMessage); } catch (\Exception $e) { $responseArray = array('type' => 'danger', 'message' => $e->getMessage()); }
关键优化点:
- 将reCAPTCHA验证放在最前面,失败则直接抛出异常,避免后续无用的邮件初始化操作
- 确保只有验证码验证通过后,才会执行邮件发送逻辑
重要提醒
即使前端做了校验,后端的reCAPTCHA验证依然是必须的——机器人可以直接绕过前端,构造POST请求提交表单,后端的验证是最后一道防线,绝对不能省略。
内容的提问来源于stack exchange,提问作者Keyan
相关产品推荐
相关产品推荐

