使用jQuery Validation Plugin进行新的reCaptcha

时间:2015-04-10 14:19:03

标签: javascript php jquery validation recaptcha

我搜索了很多,但在表单提交之前我无法弄清楚如何validate the new reCaptcha以及jQuery validation Plugin的验证功能。

我的意思是这样的:

    $.validator.addMethod('reCaptchaMethod', function (value, element, param) {
            if (grecaptcha.getResponse() == ''){
                return false;
            } else {
                // I would like also to check server side if the recaptcha response is good
                return true
            }
        }, 'You must complete the antispam verification');


    $("#form").validate({
            rules: {
                name: {
                    required: true,
                    minlength: 2
                },
                email: {
                    required: true,
                    email: true
                },
                reCaptcha: {
                    reCaptchaMethod: true   
                }
            },
            messages: {
                name: "Please fill your name",
                email: "Please use a valid email address"
            },
            submitHandler : function () {
                        $.ajax({
                            type : "POST",
                            url : "sendmail.php",
                            data : $('#form').serialize(),
                            success : function (data) {
                                $('#message').html(data);
                            }
                        });
                    }


        });

简而言之,如果用户在提交表单之前已经通过了重新验证验证,我希望使用remote method检查服务器端,以及其他验证规则。

我可以检查recaptcha AFTER提交(在sendmail.php上),但是更好的方法是将recaptcha验证响应与其他字段验证一起使用。

主要原因是为了获得更好的用户体验,同时检查所有字段。

我设法在submitHandler中实现了一些移动检查:

            submitHandler : function () {
                  if (grecaptcha.getResponse() == ''){
                      // if error I post a message in a div
                      $( '#reCaptchaError' ).html( '<p>Please verify youare human</p>' );

                  } else {

                        $.ajax({
                            type : "POST",
                            url : "sendmail.php",
                            data : $('#form').serialize(),
                            success : function (data) {
                                $('#message').html(data);
                            }
                        });
                    }

             }

但我不喜欢有两个原因: 1)我只检查重新填写是否已填写,而不是它是否有效。 2)用户感觉就像是两步验证。

In this answer他们说可以在回调中渲染Recaptcha,为成功的CAPTCHA响应指定函数调用。

我试图实现它,但我无法在validate()函数的规则中使用此解决方案。

欢迎任何提示!

4 个答案:

答案 0 :(得分:73)

我知道这个问题有点陈旧但是我遇到了同样的问题并且刚刚找到了解决方案。 您可以通过在reCaptcha div旁边添加隐藏字段来完成此操作,例如:

<div class="g-recaptcha" data-sitekey="{YOUR-SITE-KEY-HERE}"></div>
<input type="hidden" class="hiddenRecaptcha required" name="hiddenRecaptcha" id="hiddenRecaptcha">

然后在你的javascript:

$("#form").validate({
        ignore: ".ignore",
        rules: {
            name: {
                required: true,
                minlength: 2
            },
            email: {
                required: true,
                email: true
            },
            hiddenRecaptcha: {
                required: function () {
                    if (grecaptcha.getResponse() == '') {
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        },(...rest of your code)

注意您必须代码中的ignore: ".ignore"因为jquery.validate默认忽略隐藏字段,而不是验证它们。

如果要删除reCapcha上的错误消息,请向reCapcha元素添加数据回调

<div class="g-recaptcha" data-sitekey="{YOUR-SITE-KEY-HERE}" data-callback="recaptchaCallback"></div>

然后在你的js文件中添加

function recaptchaCallback() {
  $('#hiddenRecaptcha').valid();
};

答案 1 :(得分:11)

您还可以阻止 submitHandler

中的表单提交
$("#loginForm").validate({
rules: {
    username: {
        required: true,
        minlength: 6
    },
    password: {
        required: true,
    },
},
submitHandler: function(form) {
    if (grecaptcha.getResponse()) {
        form.submit();
    } else {
        alert('Please confirm captcha to proceed')
    }
}
});

答案 2 :(得分:1)

我发现你的解决方案很有趣(@FabioG)。

但是,我已经修改了它以供我自己使用,并且我愿意分享其他人使用的代码。

我正在处理一个交互式表单,在您完成步骤时进行验证。

它用于订购食物。因此,表格需要验证和激活注册按钮,它使用最新的reCaptcha到目前为止(2016年12月5日)。

此外,此代码通过ajax处理过期的reCaptcha,服务器端验证(未包括面团 - 如果有人需要它可以随意评论我的答案,我会相应地编辑它。)

让我们开始吧。

HTML代码:

<form id="registerForm" method="get" action="">
<fieldset class="step-1">
<h4>Step One:</h4>
<span class="clock">Register under one minute!</span>
<label for="email-register" class="label">E-mail*</label>
<input id="email-register" name="email-register" type="email" value="" autocomplete="off"/>

<label for="password-register" class="label">Password*</label>
<input id="password-register" name="password-register" type="password" value="" autocomplete="off"/>

<div class="g-recaptcha" data-sitekey="6LeS4O8SAAAAALWqAVWnlcB6TDeIjDDAqoWuoyo9" data-callback="recaptchaCallback" data-expired-callback="recaptchaExpired" style="margin-top: 3rem;"></div>
<input id="hidden-grecaptcha" name="hidden-grecaptcha" type="text" style="opacity: 0; position: absolute; top: 0; left: 0; height: 1px; width: 1px;"/>
</div>
</fieldset>
<fieldset class="step-2">
<h4>Step two:</h4>
<span class="notice">All fields with a sign are required!*</span>
<label for="first-name" class="label">First Name*</label>
<input name="first-name" id="first-name" type="text" value="" />

<label for="last-name" class="label">Last Name*</label>
<input name="last-name" id="last-name" type="text" value="" />

<label for="address" class="label">Address*</label> 
<input name="address" id="address" type="text" value=""/>

<label for="entrance" class="label">Entrance</label>    
<input name="entrance" id="entrance" type="text" value=""/>

<label for="apartment-number" class="label">Apartment #</label>
<input name="apartment-number" id="apartment-number" type="text" value="" />

<label for="inter-phone" class="label">Interphone</label>           
<input name="inter-phone" id="inter-phone" type="text" value=""/>

<label for="telephone" class="label">Mobile Number*</label>
<input name="telephone" id="telephone" type="text" value="" />

<label for="special-instructions" class="label">Special Instructions</label>    
<textarea name="special-instructions" id="special-instructions"></textarea>
<div>
</fieldset>
<button class="button-register" disabled>Register</button>
</form>

正如您所看到的,提交按钮(&#34; .button-register&#34;)最初已停用。

您只能通过填写必填(*)字段来启用它。

请记住,我没有包含任何CSS。该表格是最低限度的,仅用于教育目的。

与@FabioG不同的是,答案是:

无需隐藏元素或使用&#34; .ignore&#34;。我用内联CSS隐藏了它。

成功的reCaptcha和过期的reCaptcha有一个响应回调

因此,如果您的reCaptcha在填写表单时过期,则会使其无效,该按钮将再次禁用

同样,表单使用输入字段(隐藏输入字段)将信息传递到AJAX(稍后是PHP)并验证服务器端(这是一个潜在的安全风险,我在文本的结尾)。

让我们转到JavaScript / jQuery。

<强>的JavaScript / jQuery的:

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};
function recaptchaCallback() {
    var response = grecaptcha.getResponse(),
        $button = jQuery(".button-register");
    jQuery("#hidden-grecaptcha").val(response);
    console.log(jQuery("#registerForm").valid());
    if (jQuery("#registerForm").valid()) {
        $button.attr("disabled", false);
    }
    else {
        $button.attr("disabled", "disabled");
    }
}

function recaptchaExpired() {
    var $button = jQuery(".button-register");
    jQuery("#hidden-grecaptcha").val("");
    var $button = jQuery(".button-register");
    if (jQuery("#registerForm").valid()) {
        $button.attr("disabled", false);
    }
    else {
        $button.attr("disabled", "disabled");
    }
}
function submitRegister() {
  //ajax stuff
}
(function ($, root, undefined) {
    $(function () {
        'use strict';
        jQuery("#registerForm").find("input").on("keyup", debounce(function() {
          var $button = jQuery(".button-register");
          if (jQuery("#registerForm").valid()) {
            $button.attr("disabled", false);
          }
          else {
            $button.attr("disabled", "disabled");
          }
        }, 1000));
        jQuery("#registerForm").validate({
          rules: {
            "email-register": {
              required: true,
              email: true
            },
            "password-register": {
              required: true,
              minlength: "6"
            },
            "first-name": "required",
            "last-name": "required",
            address: "required",
            telephone: "required",
            "hidden-grecaptcha": {
              required: true,
              minlength: "255"
            }
          },
          messages: {
            "email-register": "Enter valid e-mail address",
            "password-register": {
              required: "Enter valid password",
              minlength: "Password must be bigger then 6 chars!"
            },
            "first-name": "Required!",
            "last-name": "Required!",
            address: "Required!",
            telephone: "Required!"
          },
          submitHandler: submitRegister
        });
    }); 
})(jQuery, this);

正如您在此处所看到的,有一些功能: recaptchaCallback() recaptchaExpired()

通过数据属性 data-callback 嵌入的

recaptchaCallback(),使用 grecaptcha.getResponse()查看reCaptcha验证,如果是这样,它将令牌输入到隐藏的输入字段,并要求通过 jQuery(&#34; #registerForm).validate(); 重新验证。

但是,如果reCaptcha同时到期,它将使用&#34; data-expired-callback&#34;中的已分配函数从输入字段中删除令牌并再次请求重新验证失败,因为该字段为空。这是通过 recaptchaExpired()

功能实现的

稍后在代码中您可以看到我们添加了一个jQuery keyup 函数,以检查重新验证并查看用户是否已将所需信息传递到输入字段。如果信息和字段成功验证, keyup 功能将启用注册按钮。

此外,我在 keyup 上使用了去抖动脚本(tnx,David Walsh)。因此它不会导致浏览器滞后。因为,会有很多打字。

但是,请记住,如果用户决定绕过reCaptcha,他总是可以输入&#34; 255&#34;字符长字符串到输入字段。但是,我更进一步,并建立了一个AJAX验证服务器端来确认reCaptcha。面团,我还没有把它包括在答案中。

它认为此代码对前一个答案的改进是微不足道的。如果您有任何问题或需要AJAX / PHP代码随时发表评论。我会尽可能地提供它。

同样是编写代码:reCaptcha with jQuery.validation

您可以在此处找到有关其api中reCatpcha数据属性和函数的所有信息:reCaptcha API

希望它有所帮助!

此致

答案 3 :(得分:0)

我今天在这个问题上挣扎,结束了:

<form onsubmit="return $(this).valid() && grecaptcha.getResponse() != ''">

这感觉就像最简单的方法。有人肯定会抱怨像这样把js内联,但我很好。