如何解决 Google v3 reCaptcha 超时?
How to solve Google v3 reCaptcha timeout?
我们有一个 PHP 表单,它有几个选项卡并且在 reCaptcha 上超时。一切都在一页上完成,如果表单在 <3 分钟内完成,它就可以正常工作。
解决思路是将表单处理和reCaptcha移到二级页面处理。
问题是表单页面轮询 google 服务以获取 reCaptcha 并将令牌值收集到隐藏字段。
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
问题是如何在服务端处理页面请求这个token?这是客户端表单页面上使用的代码。我需要以某种方式重新生成令牌值以应用为:
$recaptcha_response
这是表单页面上的工作版本。从表单页面删除发布令牌的要求很容易,只是不确定如何重新生成令牌以在服务器端页面上使用。
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['recaptcha_response'])) {
// Build POST request:
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = RECAPTCHA_SECRET_KEY;
$recaptcha_response = $_POST['recaptcha_response'];
$remoteip = $_SERVER['REMOTE_ADDR'];
// Make and decode POST request:
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response. '&remoteip='.$remoteip);
$recaptcha = json_decode($recaptcha);
// Take action based on the score returned:
if ($recaptcha->score >= 0.5) {
编辑添加:
在提交之前初始化 reCaptcha 是否会延迟时间问题,因为这似乎是一个选项:
https://developers.google.com/recaptcha/docs/v3
"2. 在某个操作或页面加载时调用 grecaptcha.execute"
<script type="text/javascript">
function grecaptcha_execute(){
grecaptcha.execute('RECAPTCHA_SITE_KEY', {action: 'homepage'}).then(function(token) {
document.getElementById('recaptchaResponse').value=token;
});
}
grecaptcha.ready(function() {
grecaptcha_execute();
});
</script>
<?php
if ($recaptcha->success) {
echo '<p style="color: #0a860a;">CAPTCHA was completed successfully!</p>';
}else{
$error_codes = 'error-codes';
if (isset($Retorno->$error_codes) && in_array("timeout-or-duplicate", $Retorno->$error_codes)) {
$captcha_msg = "The verification expired due to timeout, please try again.";
?>
<script>grecaptcha_execute();</script>
<?php
} else {
$captcha_msg = "Check to make sure your keys match the registered domain and are in the correct locations.<br> You may also want to doublecheck your code for typos or syntax errors.";
}
echo '<p style="color: #f80808;">reCAPTCHA error: ' . $captcha_msg . '</p>';
}
?>
如果您不想过多更改代码,那么另一种方法是将 reCaptcha JavaScript 包装在一个命名函数中,设置一个时间间隔并轮询该函数以提示 reCaptcha 添加一个新的在每两分钟令牌到期前 10 秒向您的表单元素发送令牌:
function getReCaptcha(){
grecaptcha.ready(function() {
...
});
}
getReCaptcha(); // This is the initial call
setInterval(function(){getReCaptcha();}, 110000);
我们最近也 运行 关注过这个问题。我在 GitHub 上找到了这个解决方案,它对我们来说效果很好。
这样做的好处是,当用户与页面交互(例如提交表单)时只需要令牌,而不必一直请求令牌。
<script>
grecaptcha.ready(function() {
document.getElementById('contactform').addEventListener("submit", function(event) {
event.preventDefault();
grecaptcha.execute('mykey', {action: 'homepage'}).then(function(token) {
document.getElementById("googletoken").value = token;
document.getElementById('contactform').submit();
});
}, false);
});
</script>
加载 reCaptcha API js 和 Jquery(如果您使用 jquery 代码):
<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
reCaptcha 呈现 Javascript:
<script type="text/javascript">
$(document).ready(function(){
setInterval(function(){
grecaptcha.ready(function() {
grecaptcha.execute('SITE_KEY', {action: 'home'}).then(function(token) {
$('#recaptchaResponse').val(token);
});
});
}, 3000); //you can set timeout for expired.
});
</script>
站点验证:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
if(isset($_POST['recaptcha_response']) && !empty($_POST['recaptcha_response'])){
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = 'SECRET_KEY';
$recaptcha_response = $_POST['recaptcha_response'];
$response = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response);
$recaptcha = json_decode($response);
if ($recaptcha->success == true && $recaptcha->score >= 0.5) {
echo $response;
echo '<br>Form Submitted Successfully';
} else {
echo $response;
echo '<br>reCaptcha varification failed';
}
}else {
echo 'reCaptcha is empty';
}
}
?>
HTML 表格:
<form method="POST">
<label class="label">Name</label>
<input type="text" name="name" class="input" placeholder="Name" required>
<button type="submit" name="submit" class="button is-link">Send Message</button>
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
</form>
忽略这里的一切。原因:
- 如果您只是在页面加载时生成令牌,它会在 2 分钟后超时,这意味着用户不会对此感到满意
- 刷新令牌会产生费用(有免费套餐,但在使用 X 请求后会产生费用)
解决方法:
在提交表单时生成令牌!
https://jsfiddle.net/skobaljic/rL6fux5w/2/
var webQueryForm = $('#webQuery');
webQueryForm.submit(function(event) {
e.preventDefault();
grecaptcha.execute('MYSITEKEY(PUBLIC)', {
action: 'contact'
}).then(function(token) {
$('#recaptchaToken').val(token);
webQueryForm.submit();
});
});
当您使用 grecaptcha.execute()
时,它没有解决问题。因为 execute() 也会抛出错误。要解决这个问题,您应该将 execute 放在 try-catch 块中。例如:
grecaptcha.ready(function() {
try {
grecaptcha.execute('RECAPTCHA_SITE_KEY', {action: 'submit'})
.then(function(token) {
submitYourForm(token);
})
} catch (error) {
yourRetryBlockHere();
}
});
我们有一个 PHP 表单,它有几个选项卡并且在 reCaptcha 上超时。一切都在一页上完成,如果表单在 <3 分钟内完成,它就可以正常工作。
解决思路是将表单处理和reCaptcha移到二级页面处理。
问题是表单页面轮询 google 服务以获取 reCaptcha 并将令牌值收集到隐藏字段。
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
问题是如何在服务端处理页面请求这个token?这是客户端表单页面上使用的代码。我需要以某种方式重新生成令牌值以应用为:
$recaptcha_response
这是表单页面上的工作版本。从表单页面删除发布令牌的要求很容易,只是不确定如何重新生成令牌以在服务器端页面上使用。
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['recaptcha_response'])) {
// Build POST request:
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = RECAPTCHA_SECRET_KEY;
$recaptcha_response = $_POST['recaptcha_response'];
$remoteip = $_SERVER['REMOTE_ADDR'];
// Make and decode POST request:
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response. '&remoteip='.$remoteip);
$recaptcha = json_decode($recaptcha);
// Take action based on the score returned:
if ($recaptcha->score >= 0.5) {
编辑添加: 在提交之前初始化 reCaptcha 是否会延迟时间问题,因为这似乎是一个选项:
https://developers.google.com/recaptcha/docs/v3
"2. 在某个操作或页面加载时调用 grecaptcha.execute"
<script type="text/javascript">
function grecaptcha_execute(){
grecaptcha.execute('RECAPTCHA_SITE_KEY', {action: 'homepage'}).then(function(token) {
document.getElementById('recaptchaResponse').value=token;
});
}
grecaptcha.ready(function() {
grecaptcha_execute();
});
</script>
<?php
if ($recaptcha->success) {
echo '<p style="color: #0a860a;">CAPTCHA was completed successfully!</p>';
}else{
$error_codes = 'error-codes';
if (isset($Retorno->$error_codes) && in_array("timeout-or-duplicate", $Retorno->$error_codes)) {
$captcha_msg = "The verification expired due to timeout, please try again.";
?>
<script>grecaptcha_execute();</script>
<?php
} else {
$captcha_msg = "Check to make sure your keys match the registered domain and are in the correct locations.<br> You may also want to doublecheck your code for typos or syntax errors.";
}
echo '<p style="color: #f80808;">reCAPTCHA error: ' . $captcha_msg . '</p>';
}
?>
如果您不想过多更改代码,那么另一种方法是将 reCaptcha JavaScript 包装在一个命名函数中,设置一个时间间隔并轮询该函数以提示 reCaptcha 添加一个新的在每两分钟令牌到期前 10 秒向您的表单元素发送令牌:
function getReCaptcha(){
grecaptcha.ready(function() {
...
});
}
getReCaptcha(); // This is the initial call
setInterval(function(){getReCaptcha();}, 110000);
我们最近也 运行 关注过这个问题。我在 GitHub 上找到了这个解决方案,它对我们来说效果很好。
这样做的好处是,当用户与页面交互(例如提交表单)时只需要令牌,而不必一直请求令牌。
<script>
grecaptcha.ready(function() {
document.getElementById('contactform').addEventListener("submit", function(event) {
event.preventDefault();
grecaptcha.execute('mykey', {action: 'homepage'}).then(function(token) {
document.getElementById("googletoken").value = token;
document.getElementById('contactform').submit();
});
}, false);
});
</script>
加载 reCaptcha API js 和 Jquery(如果您使用 jquery 代码):
<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
reCaptcha 呈现 Javascript:
<script type="text/javascript">
$(document).ready(function(){
setInterval(function(){
grecaptcha.ready(function() {
grecaptcha.execute('SITE_KEY', {action: 'home'}).then(function(token) {
$('#recaptchaResponse').val(token);
});
});
}, 3000); //you can set timeout for expired.
});
</script>
站点验证:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
if(isset($_POST['recaptcha_response']) && !empty($_POST['recaptcha_response'])){
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = 'SECRET_KEY';
$recaptcha_response = $_POST['recaptcha_response'];
$response = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response);
$recaptcha = json_decode($response);
if ($recaptcha->success == true && $recaptcha->score >= 0.5) {
echo $response;
echo '<br>Form Submitted Successfully';
} else {
echo $response;
echo '<br>reCaptcha varification failed';
}
}else {
echo 'reCaptcha is empty';
}
}
?>
HTML 表格:
<form method="POST">
<label class="label">Name</label>
<input type="text" name="name" class="input" placeholder="Name" required>
<button type="submit" name="submit" class="button is-link">Send Message</button>
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
</form>
忽略这里的一切。原因:
- 如果您只是在页面加载时生成令牌,它会在 2 分钟后超时,这意味着用户不会对此感到满意
- 刷新令牌会产生费用(有免费套餐,但在使用 X 请求后会产生费用)
解决方法: 在提交表单时生成令牌! https://jsfiddle.net/skobaljic/rL6fux5w/2/
var webQueryForm = $('#webQuery');
webQueryForm.submit(function(event) {
e.preventDefault();
grecaptcha.execute('MYSITEKEY(PUBLIC)', {
action: 'contact'
}).then(function(token) {
$('#recaptchaToken').val(token);
webQueryForm.submit();
});
});
当您使用 grecaptcha.execute()
时,它没有解决问题。因为 execute() 也会抛出错误。要解决这个问题,您应该将 execute 放在 try-catch 块中。例如:
grecaptcha.ready(function() {
try {
grecaptcha.execute('RECAPTCHA_SITE_KEY', {action: 'submit'})
.then(function(token) {
submitYourForm(token);
})
} catch (error) {
yourRetryBlockHere();
}
});