FormValidation v0.8.1 is released, supports Bootstrap 4 alpha 3

Validating Google reCAPTCHA

Examples

This example is a step by step instruction on how to use a remote validator to verify a Google reCAPTCHA.

You don't need to follow this instruction anymore. FormValidation now provides recaptcha1 and recaptcha2 add-ons adding support for Google reCAPTCHA v1 and v2 in a quick and more easy way.

Registry keys

You need to register a public and private keys provided at Get reCAPTCHA page.

Showing the captcha

Assume that the captcha will be placed inside an element with id of recaptcha as following:

<form id="defaultForm" method="post" class="form-horizontal">
    <div class="form-group">
        <label class="col-sm-3 control-label">Captcha</label>
        <div class="col-sm-9 captchaContainer">
            <div id="recaptcha"></div>
        </div>
    </div>
</form>

Google reCAPTCHA allows using either Non-Javascript or Ajax API to show up the recaptcha image. In this example, we will use the reCAPTCHA Ajax API.

<!-- The reCAPTCHA Ajax script -->
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
<script type="text/javascript">
$(document).ready(function() {
    // Call the FormValidation plugin
    $('#defaultForm').formValidation({
        icon: {
            valid: 'glyphicon glyphicon-ok',
            invalid: 'glyphicon glyphicon-remove',
            validating: 'glyphicon glyphicon-refresh'
        }
        // You can define other settings and other fields on form here
    });

    // Replace 'PUBLIC_KEY' with your public key
    // The second parameter 'recaptcha' is the Id of element showing up the captcha image
    Recaptcha.create('PUBLIC_KEY', 'recaptcha', {
        theme: 'white'
    });
});
</script>

reCAPTCHA then creates a text box with name of recaptcha_response_field. We use the addField() method to add this field:

<script type="text/javascript">
$(document).ready(function() {
    $('#defaultForm').formValidation(...);

    Recaptcha.create('PUBLIC_KEY', 'recaptcha', {
        theme: 'white',
        // captchaLoaded function will be called after the captcha image is loaded
        callback: captchaLoaded
    });

    function captchaLoaded() {
        // Add new field after loading captcha
        $('#defaultForm').formValidation('addField', 'recaptcha_response_field', {
            validators: {
                notEmpty: {
                    message: 'The captcha is required and can\'t be empty'
                }
            }
        });
    };
});
</script>

At the moment, the captcha field uses only notEmpty validator indicating that the field is required. We will use the remote validator to verify it in the next step.

Currently, if you leave the captcha empty and submit the form, the field will be masked as invalid. But the element showing captcha seem to be shown not properly, because the feedback icon is placed right after the field:

Feedback icon position

In order to fix this, we need to move the feedback icon right after the recaptcha element. It can be done by triggering the added.field.fv event, which is called after adding a field:

<script type="text/javascript">
$(document).ready(function() {
    ...

    function captchaLoaded() {
        $('#defaultForm')
            .on('added.field.fv', function(e, data) {
                // The field "recaptcha_response_field" has just been added
                if (data.field === 'recaptcha_response_field') {
                    // Find the icon
                    var $icon = data.element.data('fv.icon');

                    // Move icon to other position
                    $icon.insertAfter('#recaptcha');
                }
            })
            .formValidation('addField', 'recaptcha_response_field', {
                validators: {
                    notEmpty: {
                        message: 'The captcha is required and can\'t be empty'
                    }
                }
            });
    };
});
</script>

Now, try to submit the form, and you will see that the feedback icon is shown at the desired position:

Feedback icon position

Verifying the captcha

The last step is to validate the captcha using the remote validator. Google reCAPTCHA requires the value of recaptcha_response_field and recaptcha_challenge_field fields. The last one is a hidden field generated by Google reCAPTCHA.

So, we need to send these fields to our back-end:

<script type="text/javascript">
$(document).ready(function() {
    ...

    function captchaLoaded() {
        $('#defaultForm')
            .on('added.field.fv', function(e, data) {
                ...
            })
            .formValidation('addField', 'recaptcha_response_field', {
                validators: {
                    notEmpty: {
                        message: 'The captcha is required and can\'t be empty'
                    },
                    remote: {
                        type: 'POST',
                        url: 'recaptcha.php',
                        message: 'The captcha is not valid',
                        data: function() {
                            // We also need to send the challenge field value
                            return {
                                recaptcha_challenge_field: $('#defaultForm').find('[name="recaptcha_challenge_field"]').val()
                            };
                        },
                        // Set it to enough time that you think the user complete typing the captcha
                        delay: 1000
                    }
                }
            });
    };
});
</script>

Google reCAPTCHA provides many libraries in different languages to help us verify the captcha based on recaptcha_response_field and recaptcha_challenge_field values.

To simply demonstrate the back-end verifying process, I use the reCAPTCHA PHP library which can be downloaded here.

<?php
// Register the public and private keys at https://www.google.com/recaptcha/admin
define('PUBLIC_KEY',  '...');
define('PRIVATE_KEY', '...');

// Download the PHP library
// https://developers.google.com/recaptcha/docs/php
require_once('recaptchalib.php');

// Verify the captcha
// https://developers.google.com/recaptcha/docs/verify
$resp = recaptcha_check_answer(PRIVATE_KEY,
                                $_SERVER['REMOTE_ADDR'],
                                $_POST['recaptcha_challenge_field'],
                                $_POST['recaptcha_response_field']
                            );

echo json_encode(array(
    'valid' => $resp->is_valid,
));

Of course, you can use your own solution to verify the captcha as long as the back-end need to return an encoded JSON containing the valid key.

Final code

<form id="defaultForm" method="post" class="form-horizontal">
    <div class="form-group">
        <label class="col-xs-3 control-label">Captcha</label>
        <div class="col-xs-9 captchaContainer">
            <div id="recaptcha"></div>
        </div>
    </div>
</form>

<script src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>

<script>
$(document).ready(function() {
    $('#defaultForm').formValidation({
        icon: {
            valid: 'glyphicon glyphicon-ok',
            invalid: 'glyphicon glyphicon-remove',
            validating: 'glyphicon glyphicon-refresh'
        }
    });

    // Replace 'PUBLIC_KEY' with your public key
    Recaptcha.create('PUBLIC_KEY', 'recaptcha', {
         theme: 'white',
         callback: captchaLoaded
    });

    function captchaLoaded() {
        $('#defaultForm')
            .on('added.field.fv', function(e, data) {
                // The field 'recaptcha_response_field' has just been added
                if (data.field === 'recaptcha_response_field') {
                    // Find the icon
                    var $icon = data.element.data('fv.icon');

                    // Move icon to other position
                    $icon.insertAfter('#recaptcha');
                }
            })
            // Add new field after loading captcha
            .formValidation('addField', 'recaptcha_response_field', {
                validators: {
                    notEmpty: {
                        message: 'The captcha is required and can\'t be empty'
                    },
                    remote: {
                        type: 'POST',
                        url: 'recaptcha.php',
                        message: 'The captcha is not valid',
                        data: function() {
                            return {
                                recaptcha_challenge_field: $('#defaultForm').find('[name="recaptcha_challenge_field"]').val()
                            };
                        },
                        // Set it to enough time that you think the user complete typing the captcha
                        delay: 1000
                    }
                }
            });
    };
});
</script>
<?php
// recaptcha.php

// Register the public and private keys at https://www.google.com/recaptcha/admin
define('PUBLIC_KEY',  '...');
define('PRIVATE_KEY', '...');

// Download the PHP library
// https://developers.google.com/recaptcha/docs/php
require_once('recaptchalib.php');

// Verify the captcha
// https://developers.google.com/recaptcha/docs/verify
$resp = recaptcha_check_answer(PRIVATE_KEY,
                                $_SERVER['REMOTE_ADDR'],
                                $_POST['recaptcha_challenge_field'],
                                $_POST['recaptcha_response_field']
                            );

echo json_encode(array(
    'valid' => $resp->is_valid,
));

The following image shows how the field looks like when the captcha is valid:

Valid recaptcha