网站之前一直用的是google recaptcha v2 ,同一页面内如果有多个表单需要保护也很麻烦,官方也没什么文档。自己折腾了一下大致如下:
单页面多表单利用callback引入js:
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
<script type="text/javascript">
var CaptchaCallback = function() {
//表单一
grecaptcha.render('g-recaptcha-news', {'sitekey' : '<?php echo Mage::helper('recaptcha')->getKey(); ?>'});
//表单二
grecaptcha.render('g-recaptcha-pop', {'sitekey' : '<?php echo Mage::helper('recaptcha')->getKey(); ?>'});
//表单三
grecaptcha.render('g-recaptcha-contact', {'sitekey' : '<?php echo Mage::helper('recaptcha')->getKey(); ?>'});
};
</script>
还需要确保以上3个form里面分别有id为g-recaptcha-news、g-recaptcha-pop、g-recaptcha-contact的div与代码对应,如果js找不到这个id是会报错的;
后端php在表单控制器或者在表单控制器之前提交验证并返回,若失败则阻断表单提交即可;
public function Validate_captcha($response)
{
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' . $this->getSecretkey() . '&response=' . $response);
$responseData = json_decode($verifyResponse);
if ($responseData->success):
return true;
else:
return false;
endif;
}
v2总有个框有碍观瞻一直觉得很不爽,所以手欠换成了V3 invisible recaptcha 就是无感验证;然后发现这个就比较坑爹了;v3的思路跟v2差不多但有个很明显的缺陷就是超时了没办法自动刷新,因为V2验证超时了你还可以通过验证界面再次点击刷新token但是v3是没有界面的无处点击!
具体安装如下:
安装js在回调里面执行初始化方法,在需要验证的表单里面放入一个input用于接收token跟上面v2的div类似
var recaptchaScript = document.createElement('script');
recaptchaScript.src = 'https://www.google.com/recaptcha/api.js?onload=mtInvisibleCaptchaOnloadCallback&render=<?php echo $captcha->getSiteKey(); ?>';
recaptchaScript.attributes = 'async defer';
document.body.appendChild(recaptchaScript);
window.mtInvisibleCaptchaOnloadCallback = function () {
for (var i = 0; i < window.formToProtectOnPage.length; i++) {
window.formToProtectOnPage[i].innerHTML +=
'<input class="invisible_token" type="hidden" name="invisible_token" value=""/>';
}
for (var i = 0; i < window.formToProtectOnPage.length; i++) {
var form = window.formToProtectOnPage[i];
if (form.tagName.toLowerCase() != 'form') {
continue;
}
currentFormId = form.id;
currentFormId = currentFormId.replace(/\W+(?!$)/g, '');
grecaptcha.ready(function() {
grecaptcha.execute('<?php echo $captcha->getSiteKey(); ?>', {action: currentFormId})
.then(function(token) {
$(".invisible_token").val(token);
});
});
}
};
后端验证:
public function verify($token)
{
$verification = array(
'success' => false,
'error' => ''
);
if ($token) {
try {
$secret = Mage::getStoreConfig(self::CONFIG_PATH_GENERAL_SECRET_KEY);
$url = 'https://www.google.com/recaptcha/api/siteverify?secret=' .
$secret . '&response=' . $token . '&remoteip=' . $_SERVER["REMOTE_ADDR"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['success']) {
$verification['success'] = true;
} elseif (array_key_exists('error-codes', $result)) {
$verification['error'] = $this->getErrorMessage($result['error-codes'][0]);
}
} catch (Exception $e) {
$verification['error'] = $e->getMessage();
}
}
return $verification;
}
逻辑跟v2一样,唯一不同的我们需要额外处理超时的问题,谷歌的验证超时是大约2-3分钟,页面上的验证过了这段时间就过期了,但是用户如果不刷新页面是永远无法提交受保护的表单的,那么如何解此问题呢?
方法有2个:
1,在初始化的地方写一个定时器每2分钟执行一次获取验证码的方法,此方法优点就是可全局一次性搞定,缺点我就不说了很low的一种做法;
setInterval(function () {
grecaptcha.execute('GOOGLE CLIENT KEY', { action: 'contact' }).then(function (token) {
if ($("#recaptcha_token").length) {
console.log("set new token to existing input >> token = " + token);
$("#recaptcha_token").val(token);
} else {
console.error("recaptcha_token does not exist on email_form");
}
});
}, 60000);
2、在提交表单的时候执行一次获取验证码的方法,此方法就是每个表单都要单独加代码比较麻烦点;