【问题标题】:How do I show multiple recaptchas on a single page?如何在单个页面上显示多个recaptchas?
【发布时间】:2010-11-17 12:52:18
【问题描述】:

我在一个页面上有 2 个表单。其中一种形式一直显示recaptcha。另一个应该仅在某个事件(例如最大限度地登录尝试)之后显示一个recaptcha。所以有时我需要 2 个重新验证码才能出现在同一页面上。这可能吗?我知道我可能两个都可以使用一个,但是我的布局方式,我更喜欢有 2 个。谢谢。

更新:好吧,我想这可能是不可能的。任何人都可以推荐另一个捕获库与 reCaptcha 一起使用吗?我真的希望能够在同一页面上有 2 个验证码。

更新 2:如果将每个表单都放在 iframe 中会怎样?这是一个可以接受的解决方案吗?

【问题讨论】:

  • 你不能把同一个显示两次吗?
  • 我试过了..当我尝试复制验证码时,它只会显示首先出现的验证码
  • 任何人在新的 recaptcha API 中遇到这个问题,这可以通过使用developers.google.com/recaptcha/docs/display#recaptcha_methods 文档中的示例描述的显式加载来实现
  • iframe 应该是可能的,但与在Hüseyin Yağlı's answer 中使用 JavaScript 相比,它是解决问题的不好方法。大多数浏览器都应该支持 JavaScript,而且默认的 reCAPTCHA 还是使用 JavaScript。我不知道在没有 JavaScript 支持的情况下需要做些什么来解决这个问题。

标签: php captcha recaptcha


【解决方案1】:

使用当前版本的 Recaptcha (reCAPTCHA API version 2.0),您可以在一页上拥有多个 recaptcha。

无需复制验证码,也无需尝试解决问题。您只需为 recaptchas 放置多个 div 元素并在其中显式呈现 recaptchas。

使用 google recaptcha api 很容易:
https://developers.google.com/recaptcha/docs/display#explicit_render

这里是示例 html 代码:

<form>
    <h1>Form 1</h1>
    <div><input type="text" name="field1" placeholder="field1"></div>
    <div><input type="text" name="field2" placeholder="field2"></div>
    <div id="RecaptchaField1"></div>
    <div><input type="submit"></div>
</form>

<form>
    <h1>Form 2</h1>
    <div><input type="text" name="field3" placeholder="field3"></div>
    <div><input type="text" name="field4" placeholder="field4"></div>
    <div id="RecaptchaField2"></div>
    <div><input type="submit"></div>
</form>

在你的javascript代码中,你必须为recaptcha定义一个回调函数:

<script type="text/javascript">
    var CaptchaCallback = function() {
        grecaptcha.render('RecaptchaField1', {'sitekey' : '6Lc_your_site_key'});
        grecaptcha.render('RecaptchaField2', {'sitekey' : '6Lc_your_site_key'});
    };
</script>

在此之后,您的 recaptcha 脚本 url 应如下所示:

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

或者,您可以提供一个类名并使用您的类选择器循环这些元素并调用 .render(),而不是为您的 recaptcha 字段提供 ID

【讨论】:

  • 巧合的是,你知道如何为每个字段添加隐藏的 recaptcha 字段以进行 jquery 验证吗?目前我只使用 1 个 recaptchafield 但它可以使用两个 recaptchas 吗?
  • @IvanJuarez 这是一个很好的新问题。
  • 对于那些想要在多个实例中使用 grecaptcha.getResponse() 的人,您可以简单地将每个渲染引用为 0、1、2 等。例如,第一个实例将被引用为 grecaptcha.getResponse(0)。
  • 完美解决方案节省我的时间
  • 哇!这需要一些工作,但要添加到@GeneKelly 关于grecaptcha.getResponse(0) 和grecaptcha.getResponse(1) 的注释以验证多个实例,我会补充说索引确实必须与grecaptcha.render 排序相对应。对于此示例,grecaptcha.render('RecaptchaField1'... 将使用 grecaptcha.getResponse(0) 进行验证,grecaptcha.render('RecaptchaField2'... 将使用 grecaptcha.getResponse(1) 进行验证,等等...
【解决方案2】:

简单明了:

1) 通常使用以下方法创建您的验证码字段:

<div class="g-recaptcha" data-sitekey="YOUR_KEY_HERE"></div>

2) 用这个加载脚本:

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

3) 现在调用它来遍历字段并创建recaptchas:

<script type="text/javascript">
  var CaptchaCallback = function() {
    jQuery('.g-recaptcha').each(function(index, el) {
        grecaptcha.render(el, {
            'sitekey' : jQuery(el).attr('data-sitekey')
            ,'theme' : jQuery(el).attr('data-theme')
            ,'size' : jQuery(el).attr('data-size')
            ,'tabindex' : jQuery(el).attr('data-tabindex')
            ,'callback' : jQuery(el).attr('data-callback')
            ,'expired-callback' : jQuery(el).attr('data-expired-callback')
            ,'error-callback' : jQuery(el).attr('data-error-callback')
        });
    });
  };
</script>

【讨论】:

  • 这是 IMO 的正确方式,这使它变得动态,因为我可以拥有无​​限的实例而无需定义静态 ID
  • 如果您需要手动提取验证码(如在 ajax 请求中),请查看 my answer。
  • 你能看看in my question吗? POST 参数为空。
  • data-sitekey="YOUR_KEY_HERE"没用,可以从div中去掉(如果需要改key,编辑的地方少)
  • 实际上你有一个错字。属性 data-sitekey 是必需的,如果您有多个站点密钥,它会使其更加动态,为什么会这样。正确的行是grecaptcha.render(el, {'sitekey' : $(el).attr('data-sitekey') });
【解决方案3】:

此答案是@raphadko's answer 的扩展。

如果您需要手动提取验证码(如在 ajax 请求中),您必须调用:

grecaptcha.getResponse(widget_id)

但是如何检索小部件 id 参数?

我使用 CaptchaCallback 的这个定义来存储每个 g-recaptcha 框的 widget id(作为 HTML 数据属性):

var CaptchaCallback = function() {
    jQuery('.g-recaptcha').each(function(index, el) {
        var widgetId = grecaptcha.render(el, {'sitekey' : 'your code'});
        jQuery(this).attr('data-widget-id', widgetId);
    });
};

那我可以打电话了:

grecaptcha.getResponse(jQuery('#your_recaptcha_box_id').attr('data-widget-id'));

提取代码。

【讨论】:

  • 嘿,谢谢。 #your_recaptcha_box_id 是什么?
  • 这在 ajax 中非常适合我,但是在表单上出现错误的情况下(例如,未找到用户)-并且从 ajax 方法返回相关错误,我通常可以通过调用grecaptcha.reset(); 来重新验证验证码,这在每页单一表单的设置中效果很好。但是在每页的多个表单中,此reset 命令不会影响/重置验证码。我也尝试调用CaptchaCallback 函数,但没有解决问题。
  • 回答我上面的评论。见:stackoverflow.com/questions/31344626/…
【解决方案4】:

关于在 ASP 页面 (link) 上执行此操作的类似问题被问到,并且那里的共识是无法使用 recaptcha。似乎单个页面上的多个表单必须共享验证码,除非您愿意使用不同的验证码。如果您没有被 recaptcha 锁定,那么可以看看 Zend Frameworks Zend_Captcha 组件 (link)。它包含一些

【讨论】:

  • 实际上使用 reCAPTCHA 是可能的,只是 没有 JavaScript 是不可能的。大多数浏览器应该支持 JavaScript,并且默认的 ReCaptcha 无论如何都使用 JavaScript,所以这个解决方案很好。 Hüseyin Yağlı's answer 解释了解决方案。此解决方案的 reCAPTCHA 文档位于 developers.google.com/recaptcha/docs/display#explicit_render。我不知道在没有 JavaScript 支持的情况下需要做些什么来解决这个问题。
  • 实际上使用 reCAPTCHA 绝对有可能
【解决方案5】:

这很容易通过 jQuery 的clone() 函数完成。

因此,您必须为 recaptcha 创建两个包装 div。我的第一个表单的recaptcha div:

<div id="myrecap">
    <?php
        require_once('recaptchalib.php');
        $publickey = "XXXXXXXXXXX-XXXXXXXXXXX";
        echo recaptcha_get_html($publickey);
    ?>
</div>

第二个表单的 div 为空(不同的 ID)。所以我的只是:

<div id="myraterecap"></div>

那么javascript就很简单了:

$(document).ready(function() {
    // Duplicate our reCapcha 
    $('#myraterecap').html($('#myrecap').clone(true,true));
});

在clone() 中可能不需要带有true 值的第二个参数,但是拥有它并没有什么坏处...这种方法的唯一问题是如果您通过ajax 提交表单,则问题是你有两个同名的元素,你必须更聪明地捕捉正确元素的值(reCaptcha 元素的两个 id 是 #recaptcha_response_field 和 #recaptcha_challenge_field,以防有人需要它们)

【讨论】:

  • 当你请求一个新的挑战时你会遇到问题,因为它只会更新一个 recaptcha 实例
  • 这不起作用...意味着只有原始验证码(这里称为
    的第一个)会被刷新,其他的不被刷新
  • 其实Oxi,我之前的评论已经解决了你的问题
  • 你可能做错了......如何在 jsfiddle.net 中链接到你的代码无论如何,不​​再需要做任何这些......你应该使用 Hüseyin Yağlı 回答。
【解决方案6】:

我知道这个问题很老,但如果将来有人会寻找它。一页上可以有两个验证码。粉红色的文档在这里:https://developers.google.com/recaptcha/docs/display 下面的示例只是一个副本表单文档,您不必指定不同的布局。

<script type="text/javascript">
  var verifyCallback = function(response) {
    alert(response);
  };
  var widgetId1;
  var widgetId2;
  var onloadCallback = function() {
    // Renders the HTML element with id 'example1' as a reCAPTCHA widget.
    // The id of the reCAPTCHA widget is assigned to 'widgetId1'.
    widgetId1 = grecaptcha.render('example1', {
      'sitekey' : 'your_site_key',
      'theme' : 'light'
    });
    widgetId2 = grecaptcha.render(document.getElementById('example2'), {
      'sitekey' : 'your_site_key'
    });
    grecaptcha.render('example3', {
      'sitekey' : 'your_site_key',
      'callback' : verifyCallback,
      'theme' : 'dark'
    });
  };
</script>

【讨论】:

    【解决方案7】:

    grecaptcha.getResponse() 方法接受一个可选的“widget_id”参数,如果未指定,则默认为创建的第一个小部件。每个创建的小部件从grecaptcha.render() 方法返回一个widget_id,它与reCAPTCHA 容器的属性id 无关!!

    每个 reCAPTCHA 都有自己的响应数据。 您必须为 reCAPTCHA div 提供一个 ID 并将其传递给 getResponse 方法:

    例如

    <div id="reCaptchaLogin"
         class="g-recaptcha required-entry"
         data-sitekey="<?php echo $this->helper('recaptcha')->getKey(); ?>"
         data-theme="<?php echo($this->helper('recaptcha')->getTheme()); ?>"
         style="transform:scale(0.82);-webkit-transform:scale(0.82);transform-origin:0 0;-webkit-transform-origin:0 0;">
    </div>
    
    
    <script type="text/javascript">
      var CaptchaCallback = function() {
        jQuery('.g-recaptcha').each(function(index, el) {
            grecaptcha.render(el, {
                'sitekey' : jQuery(el).attr('data-sitekey')
                ,'theme' : jQuery(el).attr('data-theme')
                ,'size' : jQuery(el).attr('data-size')
                ,'tabindex' : jQuery(el).attr('data-tabindex')
                ,'callback' : jQuery(el).attr('data-callback')
                ,'expired-callback' : jQuery(el).attr('data-expired-callback')
                ,'error-callback' : jQuery(el).attr('data-error-callback')
            });
        });
      };
    </script>
    
    <script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
    

    访问响应:

    var reCaptchaResponse = grecaptcha.getResponse(0);
    

    或

    var reCaptchaResponse = grecaptcha.getResponse(1);
    

    【讨论】:

    • 哇,谢谢!在官方文档中找不到这样的东西。这样您就可以拥有多个验证码,而无需显式渲染。我有一个案例,我在站点周围的任何地方都有正常渲染,我只需要在一个地方显式渲染 - 这解决了我的问题。
    【解决方案8】:

    我在页脚中有始终显示的联系表单,并且某些页面(如创建帐户)也可以有验证码,所以它是动态的,我正在使用 jQuery 的下一个方法:

    html:

    <div class="g-recaptcha" id="g-recaptcha"></div>
    
    <div class="g-recaptcha" id="g-recaptcha-footer"></div>
    

    javascript

    <script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit&hl=en"></script>
    <script type="text/javascript">
      var CaptchaCallback = function(){        
          $('.g-recaptcha').each(function(){
            grecaptcha.render(this,{'sitekey' : 'your_site_key'});
          })
      };
    </script>
    

    【讨论】:

      【解决方案9】:

      这是 raphadko 和 noun 提供的答案的无 JQuery 版本。

      1) 通常使用以下方法创建您的验证码字段:

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

      2) 用这个加载脚本:

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

      3) 现在调用它来遍历字段并创建recaptchas:

      var CaptchaCallback = function() {
          var captchas = document.getElementsByClassName("g-recaptcha");
          for(var i = 0; i < captchas.length; i++) {
              grecaptcha.render(captchas[i], {'sitekey' : 'YOUR_KEY_HERE'});
          }
      };
      

      【讨论】:

        【解决方案10】:

        查看页面的源代码,我取了 reCaptcha 部分并稍微更改了代码。代码如下:

        HTML:

        <div class="tabs">
            <ul class="product-tabs">
                <li id="product_tabs_new" class="active"><a href="#">Detailed Description</a></li>
                <li id="product_tabs_what"><a href="#">Request Information</a></li>
                <li id="product_tabs_wha"><a href="#">Make Offer</a></li>
            </ul>
        </div>
        
        <div class="tab_content">
            <li class="wide">
                <div id="product_tabs_new_contents">
                    <?php $_description = $this->getProduct()->getDescription(); ?>
                    <?php if ($_description): ?>
                        <div class="std">
                            <h2><?php echo $this->__('Details') ?></h2>
                            <?php echo $this->helper('catalog/output')->productAttribute($this->getProduct(), $_description, 'description') ?>
                        </div>
                    <?php endif; ?>
                </div>
            </li>
        
            <li class="wide">
                <label for="recaptcha">Captcha</label>
                <div id="more_info_recaptcha_box" class="input-box more_info_recaptcha_box"></div>
            </li>
        
            <li class="wide">
                <label for="recaptcha">Captcha</label>
                <div id="make_offer_recaptcha_box" class="input-box make_offer_recaptcha_box"></div>
            </li>
        </div>
        

        jQuery:

        <script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
        <script type="text/javascript">
            jQuery(document).ready(function() {
                var recapExist = false;
              // Create our reCaptcha as needed
                jQuery('#product_tabs_what').click(function() {
                    if(recapExist == false) {
                        Recaptcha.create("<?php echo $publickey; ?>", "more_info_recaptcha_box");
                        recapExist = "make_offer_recaptcha_box";
                    } else if(recapExist == 'more_info_recaptcha_box') {
                        Recaptcha.destroy(); // Don't really need this, but it's the proper way
                        Recaptcha.create("<?php echo $publickey; ?>", "more_info_recaptcha_box");
                        recapExist = "make_offer_recaptcha_box";
                    }
                });
                jQuery('#product_tabs_wha').click(function() {
                    if(recapExist == false) {
                        Recaptcha.create("<?php echo $publickey; ?>", "make_offer_recaptcha_box");
                        recapExist = "more_info_recaptcha_box";
                    } else if(recapExist == 'make_offer_recaptcha_box') {
                        Recaptcha.destroy(); // Don't really need this, but it's the proper way (I think :)
                        Recaptcha.create("<?php echo $publickey; ?>", "make_offer_recaptcha_box");
                        recapExist = "more_info_recaptcha_box";
                    }
                });
            });
        </script>
        

        我在这里使用简单的 javascript 选项卡功能。因此,没有包含该代码。

        当用户单击“请求信息”(#product_tabs_what) 时,JS 将检查 recapExist 是否为 false 或具有某些值。如果它有一个值,那么这将调用 Recaptcha.destroy(); 来销毁旧加载的 reCaptcha 并为此选项卡重新创建它。否则,这只会​​创建一个 reCaptcha 并放入 #more_info_recaptcha_box div。与“提出要约”#product_tabs_wha 选项卡相同。

        【讨论】:

          【解决方案11】:

          var ReCaptchaCallback = function() {
              	 $('.g-recaptcha').each(function(){
              		var el = $(this);
              		grecaptcha.render(el.get(0), {'sitekey' : el.data("sitekey")});
              	 });  
                  };
          <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
          <script src="https://www.google.com/recaptcha/api.js?onload=ReCaptchaCallback&render=explicit" async defer></script>
          
          
          ReCaptcha 1
          <div class="g-recaptcha" data-sitekey="6Lc8WQcUAAAAABQKSITdXbc6p9HISCQhZIJwm2Zw"></div>
          
          ReCaptcha 2
          <div class="g-recaptcha" data-sitekey="6Lc8WQcUAAAAABQKSITdXbc6p9HISCQhZIJwm2Zw"></div>
          
          ReCaptcha 3
          <div class="g-recaptcha" data-sitekey="6Lc8WQcUAAAAABQKSITdXbc6p9HISCQhZIJwm2Zw"></div>

          【讨论】:

          • 2 个表单部分在哪里?
          • 抱歉没有收到你
          • 把&lt;div class="g-recaptcha" data-sitekey="your_site_key"&gt;&lt;/div&gt;放在你需要的地方,在forms/divs中
          【解决方案12】:

          在raphadko's answer 中添加一点:由于您有多个验证码(在一页上),您不能使用(通用)g-recaptcha-response POST 参数(因为它只包含一个验证码的响应)。相反,您应该为每个验证码使用grecaptcha.getResponse(opt_widget_id) 调用。这是我的代码(前提是每个验证码都在其表单内):

          HTML:

          <form ... />
          
          <div id="RecaptchaField1"></div>
          
          <div class="field">
            <input type="hidden" name="grecaptcha" id="grecaptcha" />
          </div>
          
          </form>
          

          和

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

          JavaScript:

          var CaptchaCallback = function(){
              var widgetId;
          
              $('[id^=RecaptchaField]').each(function(index, el) {
          
                   widgetId = grecaptcha.render(el.id, {'sitekey' : 'your_site_key'});
          
                   $(el).closest("form").submit(function( event ) {
          
                      this.grecaptcha.value = "{\"" + index + "\" => \"" + grecaptcha.getResponse(widgetId) + "\"}"
          
                   });
              });
          };
          

          请注意,我将事件委托(参见 refresh DOM after append element )应用于所有动态修改的元素。这会将每个人的 captha 响应绑定到其表单 submit 事件。

          【讨论】:

          • 哇,我为此找了好几个小时。谢谢!!
          【解决方案13】:

          一个不错的选择是动态为每个表单生成一个recaptcha 输入(我已经完成了两个,但您可能会执行三个或更多表单)。我正在使用 jQuery、jQuery 验证和 jQuery 表单插件通过 AJAX 以及 Recaptcha AJAX API 发布表单 -

          https://developers.google.com/recaptcha/docs/display#recaptcha_methods

          当用户提交其中一种表单时:

          1. 拦截提交 - 我使用了 jQuery Form Plugin 的 beforeSubmit 属性
          2. 销毁页面上任何现有的 recaptcha 输入 - 我使用了 jQuery 的 $.empty() 方法和 Recaptcha.destroy()
          3. 调用 Recaptcha.create() 为特定表单创建一个 recaptcha 字段
          4. 返回假。

          然后,他们可以填写验证码并重新提交表单。如果他们决定提交不同的表单,那么您的代码会检查现有的验证码,因此您一次在页面上只会有一个验证码。

          【讨论】:

            【解决方案14】:

            这是一个基于许多优秀答案的解决方案。这个选项是 jQuery 免费的,并且是动态的,不需要您专门通过 id 定位元素。

            1) 像往常一样添加您的 reCAPTCHA 标记:

            <div class="g-recaptcha" data-sitekey="YOUR_KEY_HERE"></div>
            

            2) 将以下内容添加到文档中。它可以在任何支持querySelectorAll API的浏览器中运行

            <script src="https://www.google.com/recaptcha/api.js?onload=renderRecaptchas&render=explicit" async defer></script>
            <script>
                window.renderRecaptchas = function() {
                    var recaptchas = document.querySelectorAll('.g-recaptcha');
                    for (var i = 0; i < recaptchas.length; i++) {
                        grecaptcha.render(recaptchas[i], {
                            sitekey: recaptchas[i].getAttribute('data-sitekey')
                        });
                    }
                }
            </script>
            

            【讨论】:

              【解决方案15】:

              有可能,只需覆盖 Recaptcha Ajax 回调。工作 jsfiddle:http://jsfiddle.net/Vanit/Qu6kn/

              您甚至不需要代理 div,因为覆盖后 DOM 代码将无法执行。每当您想再次触发回调时,请调用 Recaptcha.reload()。

              function doSomething(challenge){
                  $(':input[name=recaptcha_challenge_field]').val(challenge);
                  $('img.recaptcha').attr('src', '//www.google.com/recaptcha/api/image?c='+challenge);
              }
              
              //Called on Recaptcha.reload()
              Recaptcha.finish_reload = function(challenge,b,c){
                  doSomething(challenge);
              }
              
              //Called on page load
              Recaptcha.challenge_callback = function(){
                  doSomething(RecaptchaState.challenge)
              }
              
              Recaptcha.create("YOUR_PUBLIC_KEY");
              

              【讨论】:

                【解决方案16】:

                这是一个很好的指南:

                http://mycodde.blogspot.com.ar/2014/12/multiple-recaptcha-demo-same-page.html

                基本上你在api调用中添加一些参数并手动渲染每个recaptcha:

                <script src="https://www.google.com/recaptcha/api.js?onload=myCallBack&render=explicit" async defer></script>
                <script>
                        var recaptcha1;
                        var recaptcha2;
                        var myCallBack = function() {
                            //Render the recaptcha1 on the element with ID "recaptcha1"
                            recaptcha1 = grecaptcha.render('recaptcha1', {
                                'sitekey' : '6Lc_0f4SAAAAAF9ZA', //Replace this with your Site key
                                'theme' : 'light'
                            });
                
                            //Render the recaptcha2 on the element with ID "recaptcha2"
                            recaptcha2 = grecaptcha.render('recaptcha2', {
                                'sitekey' : '6Lc_0f4SAAAAAF9ZA', //Replace this with your Site key
                                'theme' : 'dark'
                            });
                        };
                </script>
                

                PS:“grecaptcha.render”方法接收一个ID

                【讨论】:

                  【解决方案17】:

                  我会使用隐形的recaptcha。然后在您的按钮上使用“formname='yourformname'”之类的标签来指定要提交的表单并隐藏提交表单输入。

                  这样做的好处是它允许您保持html5表单验证的完整性,一个recaptcha,但多个按钮界面。只需为 recaptcha 生成的令牌密钥捕获“验证码”输入值。

                  <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>
                  var formanme = ''
                  $('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>
                  

                  我发现这个 FAR 更简单、更易于管理。

                  【讨论】:

                    猜你喜欢
                    相关资源
                    最近更新 更多
                    热门标签