【问题标题】:How do I perform HTML form validation with Google ReCaptcha V2 Invisible AND Multiple Forms?如何使用 Google ReCaptcha V2 Invisible AND Multiple Forms 执行 HTML 表单验证?
【发布时间】:2020-05-21 18:36:48
【问题描述】:

我在一个页面上有 2 个表单,它们都需要 Google ReCaptcha V2 Invisible。我使用以下代码完美地工作。

在标题中:

<script src='https://www.google.com/recaptcha/api.js?onload=myCallBack&render=explicit' async defer></script>

这是表格。很简单。您可以看到 ReCaptcha 与按钮绑定,并且它具有唯一的回调和 ID。

<form id="subForm" action="form-processing.php" method="POST">         
    <input placeholder="Name" id="name" name="fname" type="text" required/>
    <input placeholder="Email" id="email" name="email" type="text" required/>
    <textarea placeholder="Comments" id="comments" cols="30" name="comments" rows="6" required></textarea>

    <button class="g-recaptcha form-submit-button" data-sitekey="MySiteKey" data-callback="captchaSubmit2" id="recaptcha2">Submit</button>
</form>

当标头中的 ReCaptcha api 加载并触发 onload 回调 (myCallBack) 时,将调用以下代码以在每个表单按钮上呈现 ReCaptcha。

var recaptcha1;
var recaptcha2;
var myCallBack = function() {
    //Render recaptcha1 on element with ID "recaptcha1"
    recaptcha1 = grecaptcha.render('recaptcha1', {
      'sitekey' : 'MySiteKey',
      'theme' : 'light'
    });

    //Render recaptcha2 on element with ID "recaptcha2"
    recaptcha2 = grecaptcha.render('recaptcha2', {
      'sitekey' : 'MySiteKey',
      'theme' : 'light'
    });
};

最后,当点击提交按钮时,ReCaptcha 会进行处理,并使用按钮上指定的回调来触发实际的表单提交。

function captchaSubmit1(data) {
    document.getElementById("mainForm").submit();
}
function captchaSubmit2(data) {
    document.getElementById("subForm").submit();
}

在我的服务器端处理的后端,我使用以下代码来验证 ReCaptcha。

<?php
    // reCaptcha info
    $secret = "MySecretKey";
    $remoteip = $_SERVER["REMOTE_ADDR"];
    $url = "https://www.google.com/recaptcha/api/siteverify";

    // Form info
    $first = $_POST["first"];
    $last = $_POST["last"];
    $response = $_POST["g-recaptcha-response"];

    // Curl Request
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, array(
        'secret' => $secret,
        'response' => $response,
        'remoteip' => $remoteip
        ));
    $curlData = curl_exec($curl);
    curl_close($curl);

    // Parse data
    $recaptcha = json_decode($curlData, true);
    if ($recaptcha["success"])
    { 
       /// MY DATA VALIDATION & EMAILING OF FORM DATA ///
    }else{
        header('Location: /thank-you-for-contacting-us/?gvx');
        exit;
    }
?>

如果表单验证由于 Google ReCaptcha 验证失败而失败,它会简单地重定向到带有代码的感谢页面,因此我知道是 recaptcha 失败了。如果表单字段数据验证失败,则有一个单独的代码。只是一种帮助我了解发生了什么的方法。

好的!所以现在的问题是这些表单不执行 HTML 客户端字段验证。我试图合并这个解决方案但没有运气:How to run reCaptcha ONLY if HTML5 validation has passed?

这些代码是那篇文章的主要内容。我替换了提交按钮:

之前:

<button class="g-recaptcha form-submit-button" data-sitekey="MySiteKey" data-callback="captchaSubmit2" id="recaptcha2">Submit</button>

之后:

<button class="form-submit-button" type="submit">Submit</button>

我在提交按钮上方的表单中添加了这个 div:

<div id="recaptcha2" class="g-recaptcha" 
data-sitekey="MySiteKey"
data-size="invisible"
data-callback="captchaSubmit2">

这些是表单提交的新处理程序:

$('#mainForm').submit(function (event) {
    if (!grecaptcha.getResponse()) {
        event.preventDefault(); //prevent form submit
        grecaptcha.reset();
        grecaptcha.execute();
    } 
});
$('#subForm').submit(function (event) {
    if (!grecaptcha.getResponse()) {
        event.preventDefault(); //prevent form submit
        grecaptcha.reset();
        grecaptcha.execute();
    } 
});

所以这里的最终流程是页面加载api,api调用recaptcha render,在g-recaptcha div上呈现recaptcha,提交表单,阻止默认行为允许HTML验证起作用(哪个确实如此),并且当表单确实提交时,它会触发上述函数调用 grecaptcha.execute();哪个进程,当它完成时,调用与其相关的回调函数(captchaSubmit2),它会执行真正的最终提交。然后我的服务器端脚本没有通过谷歌验证,悲伤随之而来......

我现在花了两天时间来解决这个问题,通常是“完成了吗?”从上面回荡。我是如此接近我可以品尝它,但我显然错过了一些东西。

我只需要 Google ReCaptcha V2 Invisible 在同一页面上处理 2 个表单,并对必填字段进行 HTML 表单验证。

非常感谢任何帮助。

【问题讨论】:

    标签: recaptcha invisible-recaptcha html-validation multiple-forms


    【解决方案1】:

    经过大量搜索,我终于找到了一个可行且相当优雅的解决方案,因为它支持单个页面上的多个表单,并且是动态的。它搜索页面并将 recaptcha 附加到任何匹配的标记 div。它应该在一页上支持尽可能多的表单。

    这是它附加的标签:

    <div class="recaptcha-holder"></div>
    

    我仍然不确定为什么我自己的实现不起作用。每次我将recaptcha附加到多个表单时,服务器端处理都会失败,并且调试显示它没有收到recaptcha数据。

    请注意,这是在 WordPress 网站上实现的,因此我将 javascript 添加到我现有的 js 中,包括我将自定义代码放入其中。

    此代码是 Mch (https://stackoverflow.com/users/7327512/mch) 发布的此问题 (Implement the new Invisible reCaptcha from Google) 的最后一个条目。感谢他们提供的前端解决方案。有趣的是,它是在 2016 年底发布的。

    Mch 的前端示例

    <!DOCTYPE html>
    <html>
    <body>
    
    <form action="" method="post">
        <input type="text" name="first-name-1"> <br />
        <input type="text" name="last-name-1"> <br />
    
        <div class="recaptcha-holder"></div>
    
        <input type="submit" value="Submit">
    </form>
    
    <br /><br />
    
    <form action="" method="post">
        <input type="text" name="first-name-2"> <br />
        <input type="text" name="last-name-2"> <br />
    
        <div class="recaptcha-holder"></div>
    
        <input type="submit" value="Submit">
    </form>
    <script src="https://www.google.com/recaptcha/api.js?onload=renderGoogleInvisibleRecaptcha&render=explicit" async defer></script>
    </body>
    </html>
    

    Mch 的 Javascript(添加到我现有的 JS 包括)

      var renderGoogleInvisibleRecaptcha = function() {
        for (var i = 0; i < document.forms.length; ++i) {
          var form = document.forms[i];
          var holder = form.querySelector('.recaptcha-holder');
          if (null === holder){
            continue;
          }
    
          (function(frm){
    
            var holderId = grecaptcha.render(holder,{
              'sitekey': 'CHANGE_ME_WITH_YOUR_SITE_KEY',
              'size': 'invisible',
              'badge' : 'bottomright', // possible values: bottomright, bottomleft, inline
              'callback' : function (recaptchaToken) {
                HTMLFormElement.prototype.submit.call(frm);
              }
            });
    
            frm.onsubmit = function (evt){
              evt.preventDefault();
              grecaptcha.execute(holderId);
            };
    
          })(form);
        }
      };
    

    最后是我的后端(服务器端)处理:

    <?php
        // reCaptcha info
        $secret = "MySecretKey";
        $remoteip = $_SERVER["REMOTE_ADDR"];
        $url = "https://www.google.com/recaptcha/api/siteverify";
    
        // Form info
        $first = $_POST["first"];
        $last = $_POST["last"];
        $response = $_POST["g-recaptcha-response"];
    
        // Curl Request
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, array(
            'secret' => $secret,
            'response' => $response,
            'remoteip' => $remoteip
            ));
        $curlData = curl_exec($curl);
        curl_close($curl);
    
        // Parse data
        $recaptcha = json_decode($curlData, true);
        if ($recaptcha["success"])
        { 
            // MY DATA VALIDATION & EMAILING OF FORM DATA
        }else{
            // Google ReCaptcha Failed to Verify - Send to False Positive
            header('Location: /thank-you-for-contacting-us/?gvx');
            exit;
        }
    ?>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-10
      • 2015-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-12
      相关资源
      最近更新 更多