如何在单页中添加多个不可见的验证码?

How to add multiple invisible recaptcha in single page?

我已经添加了两个不可见的 recaptcha div,但是当我在检查元素中看到代码时,我的单个页面中只添加了一个不可见的 recaptcha。 我的代码是:

 <div id="captcha1" class="g-recaptcha"
      data-sitekey="your_site_key"
      data-callback="onSubmit"
      data-size="invisible"></div>
<div id="captcha2" class="g-recaptcha"
      data-sitekey="your_site_key"
      data-callback="onSubmit"
     ></div>

参考来自 Programmatically invoke recaptcha

你能帮我看看我做错了什么吗?

您必须在每个提交按钮上进行显式渲染

<form>
    <button id="captcha1" class="g-recaptcha invisible-recaptcha">submit form 1</button>
</form>

<form>
    <button id="captcha2" class="g-recaptcha invisible-recaptcha">submit form 2</button>
</form>

<script>
    function verifyCaptcha(token){
        console.log('success!');
    };

    var onloadCallback = function() {
        $( ".invisible-recaptcha" ).each(function() {
            grecaptcha.render($( this ).attr('id'), {
                'sitekey' : $key,
                'callback' : verifyCaptcha
            });
        });
    };
</script>

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

有同样的问题。经过一些困惑后,我让它工作了。

使用 Alessandro 提供的想法,并使表单在成功时自动提交。

<script type="text/javascript">
    var onloadCallback = function() {
        $(".g-recaptcha").each(function() {
            var el = $(this);
            grecaptcha.render($(el).attr("id"), {
                "sitekey" : SITE_KEY,
                "callback" : function(token) {
                    $(el).parent().find(".g-recaptcha-response").val(token);
                    $(el).parent().submit();
                }
            });
        });
    };
</script>

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

下面是 Peter 和 Alessandro 在嵌套元素时回答的更可靠的解决方案。

<script>
$(".g-recaptcha").each(function() {
    var object = $(this);
    grecaptcha.render(object.attr("id"), {
        "sitekey" : "6LdwRC0UAAAAAK0hjA8O4y1tViGPk9ypXEH_LU22",
        "callback" : function(token) {
            object.parents('form').find(".g-recaptcha-response").val(token);
            object.parents('form').submit();
        }
    });
});
</script>

<form>
    <input type="text" name="example"/>
    <button id="captcha1" class="g-recaptcha">submit form 1</button>
</form>

<form>
    <input type="text" name="example"/>
    <button id="captcha2" class="g-recaptcha">submit form 2</button>
</form>

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

单页动态多个不可见的 reCaptcha V2

Github Code: https://github.com/prathameshsawant7/multiple-invisible-recaptcha

步骤 1>

页面添加以下2个Js库

<!--  reCaptcha Library -->
<script type="text/javascript" src="https://www.google.com/recaptcha/api.js?render=explicit"></script>

<!--  Customized Init for invisible reCaptcha  -->
<script src="js/init_recaptcha.js" async defer></script>

步骤 2>

在下面的 div 中添加相应的表格。

<div id="recaptcha-form-1" style="display:none;"></div> <!--for Form 1-->
<div id="recaptcha-form-2" style="display:none;"></div> <!--for Form 2-->
<div id="recaptcha-form-3" style="display:none;"></div> <!--for Form 3-->

步骤 3>

创建init_recaptcha.js

  • 第 1 步 - 初始化 reCaptcha 站点密钥和小部件,例如:widget_1 for Form 1
  • 第 2 步 - 在 init 函数中添加代码以创建表单提交回调操作。
  • 步骤 3 - 通过传递 reCaptcha ID 和 createCallbackFn 响应调用 renderInvisibleReCaptcha 函数。

    "use strict";
    
    var PS = PS || {};
    var widget_1;var widget_2;var widget_3;
    var recaptcha_site_key = 'RECAPTCHA_SITE_KEY';
    
    if( typeof PS.RECAPTCHA === 'undefined' ) {
        (function (a, $) {
            var retryTime = 300;
            var x = {
                init: function(){
                    if(typeof grecaptcha != 'undefined'){
    
                        //For Form 1 Initialization
                        if($('#form1 #recaptcha-form-1').length > 0){
                            var callbackFn = {
                                action : function(){
                                    saveData('1'); //Here Callback Function
                                }
                            }
                            /*--- 'recaptcha-form-1' - reCaptcha div ID | 'form1' - Form ID ---*/
                            widget_1 = x.renderInvisibleReCaptcha('recaptcha-form-1',x.createCallbackFn(widget_1,'form1',callbackFn));
                        }
    
                                               //For Form 2 Initialization
                        if($('#form2 #recaptcha-form-2').length > 0){
                            var callbackFn = {
                                action : function(){
                                    saveData('2'); //Here Callback Function
                                }
                            }
                            /*--- 'recaptcha-form-2' - reCaptcha div ID | 'form2' - Form ID ---*/
                            widget_2 = x.renderInvisibleReCaptcha('recaptcha-form-2',x.createCallbackFn(widget_2,'form2',callbackFn));
                        }
    
                                                //For Form 3 Initialization
                        if($('#form3 #recaptcha-form-3').length > 0){
                            var callbackFn = {
                                action : function(){
                                    saveData('3'); //Here Callback Function
                                }
                            }
                            /*--- 'recaptcha-form-3' - reCaptcha div ID | 'form3' - Form ID ---*/
                            widget_3 = x.renderInvisibleReCaptcha('recaptcha-form-3',x.createCallbackFn(widget_3,'form3',callbackFn));
                        }
    
                    }else{
                        setTimeout(function(){ x.init();} , retryTime);
                    }
                },
                renderInvisibleReCaptcha: function(recaptchaID,callbackFunction){
                        return grecaptcha.render(recaptchaID, {
                                'sitekey'   : recaptcha_site_key,
                                "theme" : "light",
                                'size'      : 'invisible',
                                'badge' : 'inline',
                                'callback'  : callbackFunction
                            });
                },
                createCallbackFn: function (widget,formID,callbackFn) {
                    return function(token) {
                        $('#'+formID+' .g-recaptcha-response').val(token);
                        if($.trim(token) == ''){
                            grecaptcha.reset(widget);
                        }else{
                            callbackFn.action();
                        }
                    }
                }
            }
            a.RECAPTCHA = x;
        })( PS, $ );
    }
    
    $(window).load(function(){
        PS.RECAPTCHA.init();
    });
    

步骤 4> 表单验证 JS 的变化 -

/* Execute respective Widget on form submit after form Validations  */
function formSubmit(form){
    var text = $.trim($('#text'+form).val());
    if(text != ''){
        switch(form){
            case '1' : grecaptcha.execute(widget_1); break;
            case '2' : grecaptcha.execute(widget_2); break;
            case '3' : grecaptcha.execute(widget_3); break;
        }
    }
}

步骤 5> 从服务器端验证 reCaptcha -

<?php
    define('RECAPTCHA_SECRET_KEY','KEY');
    /**
    *  @Desc:   To Validate invisible recaptcha from server-side
    *  @Param:  g-recaptcha-response value
    *  @Return: True/False
    **/
    if(!function_exists('check_recaptcha')){
        function check_recaptcha($recaptcha_response){
            $test = array ('secret' => RECAPTCHA_SECRET_KEY,'remoteip' => $_SERVER["REMOTE_ADDR"],'response' => $recaptcha_response);
            foreach ($test as $key => $value) {
                $req .= $key . '=' . urlencode(stripslashes($value)) . '&';
            }
            $req=substr($req, 0, strlen($req)-1);
            $path = 'https://www.google.com/recaptcha/api/siteverify?';
            $response = file_get_contents($path . $req);
            $responseData = json_decode($response);
            if($responseData->success){
                return true;            
            }else{
                return false;
            }
        }
    }

    // Validate reCaptcha
    if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == "POST" && !empty($_POST)) {
        $checkCapcha = false;
            $recaptcha = $_POST['g-recaptcha-response'];
                $checkCapcha = check_recaptcha($recaptcha);
                if($checkCapcha){
                    echo $_POST['textmsg']; exit;
                    /** Perform Actions Here (Add,Update,Delete etc) 
**/
                }
    else{
            echo “reCaptcha Error”;
        }
    }
    echo "failed";exit;
?>

步骤 6> 服务器调用后重置小部件 -

// saveData will be automatically get called on grecaptacha.execute 
function saveData(form){
$.ajax( {
    type: 'POST',
    url:  $("#form"+form).attr( 'action' ),
    data: $("#form"+form).serialize(),
    success: function( response ) {
                switch(form){
            case '1' : grecaptcha.reset(widget_1); break;
            case '2' : grecaptcha.reset(widget_2); break;
            case '3' : grecaptcha.reset(widget_3); break;
            }
        }
    } );
}

您可以使用隐形验证码。在您的按钮上使用“ formname='rcaptchaformname' ”之类的标记来指定要提交的表单并隐藏提交表单输入。

这允许您保持 html5 表单验证完整,一个 recaptcha,但多个按钮界面。只需捕获 recaptcha 生成的令牌密钥的 "captcha" 输入值。

<script src="https://www.google.com/recaptcha/api.js" async defer ></script>

<div class="g-recaptcha" data-sitekey="yours" data-callback="onSubmit" data-size="invisible"></div>
<script>

$('button').on('click', function () { formname = '#'+$(this).attr('formname');
    if ( $(formname)[0].checkValidity() == true) { grecaptcha.execute(); }
    else { $(formname).find('input[type="submit"]').click() }
    });

var onSubmit = function(token) {
    $(formname).append("<input type='hidden' name='captcha' value='"+token+"' />");
    $(formname).find('input[type="submit"]').click()
    };
</script>

对于 Google Recaptcha V3 页面上的多个 Recpatch:

HTML:

<script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=grecaptcha_onload"></script>
<script>
    function grecaptcha_onload() {
        $('.g-recaptcha-response').each(function( k, v ) {
            var submit = $(v).closest("form").find('[type="submit"]');
            grecaptcha.render( submit[0], {
                'sitekey' : SITE_KEY,
                'callback' : function( token ) {
                    $(v).closest("form").find('.g-recaptcha-response').val( token );
                    $(v).closest("form").submit();
                },
                'size' : 'invisible',
            });
        });
    }
</script>
<form>
    <input type="hidden" value="" name="g-recaptcha-response" class="g-recaptcha-response" />
    <button type="submit">Submit</button>
</form>
<form>
    <input type="hidden" value="" name="g-recaptcha-response" class="g-recaptcha-response" />
    <button type="submit">Submit</button>
</form>

PHP:

    function validate()
    {
        if( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
            // Build POST request:
            $recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
            $recaptcha_response = $_POST[ 'g-recaptcha-response' ];
            $recaptcha = file_get_contents( $recaptcha_url . '?secret=' . self::SECRET_KEY . '&response=' . $recaptcha_response );
            $recaptcha = json_decode( $recaptcha );

            if( $recaptcha->success == true ){
                // Take action based on the score returned:
                if( $recaptcha->score >= 0.1 ) {
                    return true;
                } else {
                    $this->errors[] = 'Something went wrong with sumbitting the form.<br />Please try again!';

                    foreach( (array) $recaptcha as $key => $value ) {
                        $this->errors[] = 'Key: ' . $key . ' Value: ' . $value;
                    }

                    return false;
                }
            } else { // there is an error /
                switch ( $recaptcha->{'error-codes'}[0] ) {
                    case 'missing-input-secret':
                        $this->errors[] = 'The secret parameter is missing';
                        break;
                    case 'invalid-input-secret':
                        $this->errors[] = 'The secret parameter is invalid or malformed';
                        break;
                    case 'missing-input-response':
                        $this->errors[] = 'The response parameter is missing';
                        break;
                    case 'invalid-input-response':
                        $this->errors[] = 'The response parameter is invalid or malformed';
                        break;
                    case 'bad-request':
                        $this->errors[] = 'The request is invalid or malformed';
                        break;
                    case 'timeout-or-duplicate':
                        $this->errors[] = 'The response is no longer valid: either is too old or has been used previously';
                        break;
                    default:
                        break;
                }

                return false;
            }
        }
    } 

已完成,但如果您不需要它是动态的,您可以简化该过程:

1.加载 recaptcha 库

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

2。在每个表单的 HTML 中添加您的占位符

<form ...>
...
<div class="g-recaptcha"></div>
...
</form>

3。在您的 JS 中,编写您在加载 reCaptcha 脚本时作为参数调用的回调:

window.onloadCallback = function() {
      $('.g-recaptcha').each(function(i, v) {
        const $placeholder = $(this)

        // Define a widget id that will be used by every grecaptcha method 
        // to keep track of which form is being used
        $placeholder.data('widget-id', i)

        grecaptcha.render( this, {
          callback: function( token ) {

            return new Promise(function(resolve, reject) {
              if( grecaptcha === undefined ) {
                console.log( 'reCaptcha not defined' )
                reject()
              }

              var response = grecaptcha.getResponse( $placeholder.data('widget-id') )
              if( !response ) {
                console.log( 'Could not get reCaptcha response' )
                reject()
              }

              const $form = $placeholder.closest('form')

              $form.find('.g-recaptcha-response').val( token )
              $form
              // Add a class that will be used to bypass the prevented submit event
              .addClass('recap-done')
              // submit by clicking the submit button of your form
              .find('[type="submit"]').trigger('click')
              resolve()
              grecaptcha.reset( $placeholder.data('widget-id') )
            })
          },
          sitekey: RECAPTCHA_KEY,
          size: 'invisible', // This makes the real reCaptcha V2 Invisible
        })
      })
    }

注意:我使用 promise 来防止 Promise null 问题,

4.为所有表单添加提交事件处理程序

$('form').on('submit', function(e) {
      const $form = $(this)

      // 2nd pass (when the submit is triggered within the callback)
      // This bypasses the event to be prevented a new time -> form is really submitted
      if( $form.hasClass('recap-done') ) {
        return
      }

      // 1st pass: prevents the form to be submitted and do the reCaptcha process
      const $placeholder = $form.find('.g-recaptcha')
      if( $placeholder.length > 0 ) {
        e.preventDefault()

        grecaptcha.execute( $placeholder.data('widget-id') )
      }
    })

5.享受