A ready out of the box example for a powerful registration form that includes Bootstrap form validation, Google invisible recaptcha, Ajax request after recaptcha’s challenge succeed to validate it in the server-side.
Integrating Form validation with Google recaptcha is a great way to protect your site from spams and attacks and verify them as real humans.
Many bots nowadays will look hard for contact forms that donโt use recaptcha or an equivalent and send thousands of messages in a second through these forms. This has a lot of negative effects on your server, website and your brain health, besides, your domain can get marked as spam, or being blocked from email servers, and many more. In this example, you will see how you can add an extra layer of security by only allowing verified humans to submit the form.
Bootstrap form validation.
Google invisible recaptcha.
Recaptcha PHP validation.
Ajax request on recaptcha challenge success.
Ajax form loader ๐
Responsive.
First, you should get a site-key and a secret-key from Google recaptcha’s website, you can get one from this link after you sign in with your Google account https://www.google.com/recaptcha
Save these two keys somewhere, we will go back to them later.
Then you need to integrate Google recaptcha in your webpage, insert the following code in yourtag, or in footer it will work too.Our Javascript function that will handle recaptcha’s work will be named initRecaptcha.
<script src="https://google.com/recaptcha/api.js?onload=initRecaptcha&render=explicit"></script>
We used Bootstrap Validator in our example, you can get it from Bootstrap Form Validator, and also include it in your page somewhere.
Our form contains a lot of extra fields, as an example to make it easy to understand.
<form action="#" method="post" class="row onyx-gap">
<div class="form-head col-12">
<input type="text" readonly="readonly" value="ID: #54357782" class="permanent-id" name="permanent-id">
<div class="validation-errors"></div>
</div>
<!-- Fields -->
<div class="col-md-6 col-sm-12 form-group">
<input type="text"
class="styled-form__input form-control"
placeholder="Type your fullname please..."
name="fullname"
minlength="2"
maxlength="15"
data-bv-notempty-message="Fullname field is required."
data-bv-stringlength-message="Please type a valid value."
required>
</div>
<div class="col-md-6 col-sm-12 form-group">
<input type="password"
class="styled-form__input form-control"
placeholder="Type your password please..."
name="password"
minlength="6"
maxlength="15"
data-bv-notempty-message="Password field is required."
data-bv-stringlength-message="Please type a valid value."
required>
</div>
<div class="col-12 form-group">
<input type="email"
class="styled-form__input form-control"
placeholder="Types your email please..."
name="email"
data-bv-notempty-message="E-mail field is required."
data-bv-emailaddress-message="Please type a valid email."
required>
</div>
<div class="col-md-6 col-sm-12 form-group">
<input type="tel"
class="styled-form__input form-control"
placeholder="Type your telephone..."
name="telephone"
minlength="9"
maxlength="15"
data-bv-notempty-message="Telephone field is required."
data-bv-stringlength-message="Please type a valid telephone number."
required>
</div>
<div class="col-md-6 col-sm-12 select-wrapper">
<select name="university">
<option value="default">University</option>
<option value="test">Test</option>
<option value="test">Test</option>
<option value="test">Test</option>
<option value="test">Test</option>
</select>
</div>
<div class="col-12 form-group">
<label for="contract">
<input type="checkbox"
id="contract"
name="contract"
class="form-control"
value="contract"
data-bv-notempty-message="Lorem ipsum dolor sit amet field is required."
data-bv-stringlength-message="Please check Lorem ipsum dolor sit amet."
required>
Lorem ipsum dolor sit amet.
</label>
</div>
<div class="col-md-6 col-sm-12">
<label for="sms-alert">
<input type="checkbox"
id="sms-alert"
name="sms-alert"
value="sms-alert">
Quisque ullamcorper.
</label>
</div>
<div class="col-md-6 col-sm-12">
<label for="email-alert">
<input type="checkbox"
id="email-alert"
name="email-alert"
value="email-alert">
Nunc suscipit erat.
</label>
</div>
<div class="col-12">
<div class="recaptcha"></div>
</div>
<div class="col-12">
<button type="submit" name="submit" class="btn-icon">Continue</button>
</div>
</form>
The .loading-container div is for the loader that we will show after sending the Ajax request, we were trying to be more user-friendly ๐
.form-head contains a readonly input, this one was for testing purposes, and it will contain the form validation error.
Each field you want to validate should have .form-control class and required attribute.
and of course we need some container for our Google recaptcha, in our example it has #form-recaptch ID, this ID will be used in the Javascript.
var container = $('form'),
limitRuns = 0;
container.bootstrapValidator({
container: container.find('.validation-errors')[0], // Select the messages container
feedbackIcons: {
valid: 'fa fa-check-circle',
invalid: 'fa fa-exclamation-circle',
validating: 'fa fa-refresh'
},
live: 'submitted',
onError: function(e) {
container.find('.validation-errors').stop(0,0).slideDown(500,function(){
$(this).css('height','auto');
});
},
onSuccess: function(e) {
// Bootstrap validation was running success three time so I had to limit it this way
if ( limitRuns == 0 ) {
if ( grecaptcha.getResponse() !== 0 )
grecaptcha.execute(); // Start the Google recaptcha
limitRuns++;
}
}
});
If you’re wondering why we put limitRuns, it’s because for some mysterious reason the Bootstrap Validation was running the onsuccess event multiple times!!
Now we’re calling grecaptcha.execute to start the recaptcha after making sure it’s ready grecaptcha.getResponse and after form validation success.
and of course, the onerror event will show validation errors in the div that we prepared in the HTML form.
/**
* Init recaptcha
*/
if (typeof grecaptcha !== 'undefined') {
console.log('Recaptcha is here');
var reCaptchaIDs = [];
var initRecaptcha = function () {
jQuery('.recaptcha').each(function (index, el) {
var container = jQuery(this).parents('form');
var tempID = grecaptcha.render(el, {
'sitekey': 'YOUR_SITE_KEY',
'theme': 'light',
'badge': 'inline',
'size': 'invisible',
'callback': function (token) { // We may need the token later, who knows!
globalFormsAjax(token, container);
}
});
reCaptchaIDs.push(tempID);
});
};
//Reset reCaptcha
var recaptchaReset = function () {
if (typeof reCaptchaIDs != 'undefined') {
var arrayLength = reCaptchaIDs.length;
for (var i = 0; i < arrayLength; i++) {
grecaptcha.reset(reCaptchaIDs[i]);
}
}
};
}
/**
* The callback
**/
var globalFormsAjax = function(token, container){
$.ajax({
url: "recaptcha.php", // Validate the recaptcha challenge
method: "POST",
dataType:'json',
data: container.serialize(),
beforeSend: function(xhr) {
// Show our loader
container.append('<div class="loading-container"><div class="loading-spinner"><div class="circle_01"></div><div class="circle_02"></div><div class="circle_03"></div><div class="circle_04"></div><div class="circle_05"></div><div class="circle_06"></div><div class="circle_07"></div><div class="circle_08"></div></div></div>');
container.addClass('ajax-loader');
},
success: function(responseObj){
// Stop the loader
container.removeClass('ajax-loader');
container.children('.loading-container').remove();
// Show error message - Messages are in the PHP functions
if ( responseObj.status == "success" ) {
// Now we are OK to submit our form
//container.submit();
// Show a success message (just for testing)
container.find('.validation-errors').html(responseObj.msg).stop(0,0).slideDown(500,function(){
$(this).css('height','auto');
});
// If you want to show thank-you page
// window.location.href='thank-you';
} else {
// Show the error message
container.find('.validation-errors').html(responseObj.msg).stop(0,0).slideDown(500,function(){
$(this).css('height','auto');
});
}
// Reset recaptcha challenge if it's here
if (typeof grecaptcha !== 'undefined') {
recaptchaReset();
}
// Reset the form fields
resetForm(container);
}
});
}
/**
* Reset form fields
**/
var resetForm = function ( $form ) {
// Reset the error message
/*$form.find('.validation-errors').stop(0,0).slideUp(500,function(){
$(this).css('height','auto').html('');
});*/
$form.find('input:not([readonly]), select, textarea').val('');
$form.find('input:radio:not([readonly]), input:checkbox:not([readonly])').removeAttr('checked').removeAttr('selected');
$form.find('input:text, input:password, input, input:file, select, textarea, input:radio, input:checkbox').parent().find('.form-control-feedback').hide();
$form.find('.has-feedback').removeClass('has-feedback');
$form.find('.has-success').removeClass('has-success');
};
You can read about the grecaptcha.render options on their website https://developers.google.com/recaptcha/docs/invisible
Don’t forget to replace YOUR_SITE_KEY with the site-key you got from Google.
Now our great recaptcha will call recaptchaFormsAjax when it runs.
In that function, we’re sending an Ajax request to check and validate the recaptcha challenge in PHP.
/**
* Google recaptcha server side check
*/
$captcha;
if ( isset($_POST['g-recaptcha-response']) ) {
$captcha = $_POST['g-recaptcha-response'];
}
if( !$captcha ){
$response = array (
'status' => 'error',
'msg' => 'Please check the the captcha form.'
);
echo json_encode($response);
exit;
}
$secretKey = "YOUR_SECRET_KEY";
$ip = $_SERVER['REMOTE_ADDR'];
$googleResponse = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".$secretKey."&response=".$captcha."&remoteip=".$ip);
$responseKeys = json_decode($googleResponse,true);
if(intval($responseKeys["success"]) !== 1) {
$response = array (
'status' => 'spam',
'msg' => 'You look like a spam.'
);
echo json_encode($response);
exit;
} else {
$response = array (
'status' => 'success',
'msg' => 'You\'re good to go.'
);
echo json_encode($response);
exit;
}
Also, don’t forget to replace YOUR_SECRET_KEY with the secret-key you got from Goolge.
This function will validate the recaptcha challenge and return a message to our Javascript function to go on.
I’ve updated this snippet to make it more dynamic and supports multiple forms and recaptchas, also a new function to reset the form and the recaptcha challenge was added.
I commented the form submit part and the redirect to the thank-you page for demo purposes but please don’t forget to check it again.
Also, the loader is being added from the Javascript and removed after the Ajax request finish.
Download our working example or view demo from the buttons at the beginning of this post.
Please don’t hesitate to write to me if something went wrong with you ๐ I’m always glad to help.
jQuery ๐
Bootstrap
Font Awesome
Montserrat font
Bootstrap Form Validator
TuniRio
WroteThis article is very helpful because those informations are needs for websites and Google recaptcha.
Thank you for this article, I’m following you every time.
admin
Replied to TuniRioThank you :), I’m glad you like it.
Chad
WroteHey could you please look at my site. I am trying to use your form. Only thing I done was removed some fields and changed the css, for the colours. So everything looks good, but when I click “Submit”, which I changed from “Continue”. Nothing happens? http://cdesignc.co.za/
admin
Replied to ChadHello,
Sorry for the delay, I’ve been busy lately.
I looked at your website but I didn’t understand why you made the form through an Iframe!
and this form is integrated with Google Recaptcha, I think you removed the Google Recaptcha part and the form is giving an error.
contact me through my email if you didn’t solve it.
info[at]onyxdev.net
Regards
svuk
WroteHello, I really liked your implementation of the invisible recaptcha, there is such a task: I need to have two invisible recaptchas on the page (I’m new to this business, and I can not do it)
I really need help.
Thank you in advance
admin
Replied to svukHello,
I’m happy that you like it, no problem, send me your website details and I hope I can help ๐
Prashanth Rajasekaran
WroteGreat Work Thank you so much.
admin
Replied to Prashanth RajasekaranYou’re welcome ๐
Highly recommended Online site
WroteI just could not go away your site before suggesting that I actually enjoyed the standard info a person supply in your guests? Is going to be back continuously to investigate cross-check new posts
https://www.animatron.com/studio/users/broadcastbike
admin
Replied to Highly recommended Online siteI’m glad you like it, you’re welcome ๐
01K
WroteBy they way. If form validation fails – the submit button will be disabled. Then you correct form, but button is still disabled. So you should change the add something or change in a form to execute validation once more.
Otherwise button will be disabled. Any workaroud?
admin
Replied to 01KIf you filled all the required fields the button will be enabled… check that there are no validation errors above the form in the validation messages area… you can send me your project’s URL and I will be glad to help ๐
Panlasang Pinoy
WroteThanks for sharing this. I will implement this to my project,
admin
Replied to Panlasang PinoyYou’re welcome ๐
boekhouding zzp breda
WroteEnjoyed the post.
admin
Replied to boekhouding zzp bredaYou’re welcome, I’ve updated it, it’s more dynamic now ๐
Couperose
WroteLooks realy great! Thanks for the post.
admin
Replied to CouperoseYou’re welcome, I’m glad you like it
sri
WroteHI I used invisible recaptcha while submitting a form. Sometimes the form is getting submitted and sometimes it is showing error. When I checked the network through developer tools, whenever the form is taking time to submit it is throwing error. Can you please help me with that?
admin
Replied to sriHi sri,
I’ll be glad to help you, please send me a screenshot for the error you’re getting in the console
huidverzorging
WroteThanks for this nice post. …
admin
Replied to huidverzorgingYou’re welcome, I’m glad you like it.
It has been updated now if you want to stay up to date download the files again ๐
Shabu
WroteThanks for sharing a great post. However i need a improvement. How to reset the form after successful submission is there any idea
admin
Replied to ShabuHey Shabu!
I’ve made a new version and updated the files, please download it again and follow up the comments I’ve written along the way, it’s now more dynamic ๐
mace
WroteHi, how do i post the form to my email? Ive looked everywhere for a mail address to add to the code somewhere? Thanks
admin
Replied to maceHello Mace,
I’m sorry for this but this example doesn’t include email sending function ๐, I have another example that sends emails through PHPMailer but I didn’t have the time to put it here, I can send it to you by mail and you can figure it out ๐
Gerson
WroteHow can I add the email to the one that will be sent? Thanks
admin
Replied to GersonHello Gerson,
You’ve to use something like PHPMailer to let it send emails, you can find more about PHPMailer here (https://github.com/PHPMailer/PHPMailer).
Regards
Heero
WroteHello,
thank you for your helpful great work, im trying to use it, everything seems oky, but when i submit i get : you seem like a spam, any idea? my envirement is : iis 8.5, php 5.6, hsts enabled, https too, thank you
admin
Replied to HeeroHello Heero,
You’re welcome, I’m glad you liked my article.
This message means that a falsy response is coming from Google, are you sure you’ve replaced YOUR_SECRET_KEY with your key?
Heero
Replied to adminthank you for your replay :
yes my secret key in the post php, my site key in the script js
admin
Replied to HeeroCan it be that your hosting is blocking the outgoing connections?
if itโs not the problem, send me your website details by email and Iโll try to help ๐
Heero
Replied to admintrue, our website allow by country access in iis server, and file robot.txt block crawling
admin
Replied to HeeroThe robots.txt doesn’t affect the outgoing connections.
BTW, why you’re trying to use recaptcha with an IIS?!
Is it working now?