11

我们有一个 PHP 表单,它在 reCaptcha 上有几个选项卡和超时。一切都在一个页面中完成,如果表格在 <3 分钟内完成,它工作得非常好。

解决方案的想法是将表单处理和 reCaptcha 移动到辅助页面进行处理。

问题是表单页面轮询谷歌服务以获取 reCaptcha 并将令牌值收集到隐藏字段。

<input type="hidden" name="recaptcha_response" id="recaptchaResponse">

问题是如何在服务器端处理页面上请求这个令牌?这是客户端表单页面上使用的代码。我需要以某种方式重新生成令牌值以应用为:

$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”

4

6 回答 6

18

如果您不希望过多更改代码,那么另一种方法是将 reCaptcha JavaScript 包装在一个命名函数中,设置一个间隔并轮询该函数,提示 reCaptcha 在每个前 10 秒向您的表单元素添加一个新令牌两分钟令牌到期:

function getReCaptcha(){
    grecaptcha.ready(function() {
       ...
     });
 }

 getReCaptcha();  // This is the initial call
 setInterval(function(){getReCaptcha();}, 110000);
于 2019-11-08T08:01:42.723 回答
6

我们最近也遇到了这个问题。我在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>
于 2020-06-09T20:38:29.700 回答
4
<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>';
}
?>
于 2019-03-27T12:16:13.673 回答
1

加载 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>
于 2020-06-22T19:35:32.983 回答
0

当您使用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();
    }
});
于 2021-10-16T11:48:19.833 回答
0

忽略这里的一切。原因:

  1. 如果你只是在页面加载时生成令牌,它会在 2 分钟后超时,这意味着用户不会对此感到高兴
  2. 刷新令牌将花费您(有免费套餐,但在使用 X 请求后需要付费)

解决方法:在表单提交的时候生成token! 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();
  });
});
于 2021-10-04T21:48:57.733 回答