Bake Your Own Captcha in 15 minutes (without all the captcha shame)
The Captcha: bane of user experience, plague of cyberkind, mangler of type faces, molester of elegance.
If you must protect your forms from bot submissions, some sort of validation is required. In this tutorial we'll make an image-captcha. They aren't new, but they're easy to build and very effective.
Success Criteria:
-- Must prevent bot-submissions of a form
-- Must be easy for a human to use
-- Must be ready for production in 15 minutes
Here's what you'll create:
An image-picker captcha with 4 images to pick from. It's easy for humans and tough for bots.
You'll need these skills:
-- Proficiency in a web-programming language
-- Proficiency with jQuery or some flavor of javascript
-- The ability to crop, size and save images
-- Some familiarity with CSS to make it prettier
NOTE: I'm going to jump between ColdFusion and PHP in the examples below, but don't worry, you can get the full code in each language.
Download Source Code
Let's do this!
1) Create your four images and name them something generic, such as, "1.png, 2.png..."
2) Find the opening form tag in your code. Just before this point you will add code to do the following:
a) Generate a four element array of unique IDs. For the ColdFusion folks out there, something like this:
Here's what we've done so far:
-- created an array of images, each with a unique id
-- randomized the order of these images
-- randomly chose one of the images as the challenge
-- stored the correct answer in the user's session scope
f) Next, find the end of your form, just before the submit button or closing form tag (whichever comes first).
g) Display the captcha challenge (CFML):
<p>Please click the #captchaAnswer.name# to prove you're human:</p>
h) Loop over the array of images and output them in your form (CFML):
j) Create some javascript to handle the click event on a captcha image (jQuery):
<script> // when the user clicks a captcha image
$(document).on( "click", "img.captchaImg", function() {
// get the answer value
var thisAnswer = $(this).attr( "data-captchaAnswer" );
// and insert it into our hidden field
$("#captchaAnswer").val( thisAnswer );
// also, let's add a class to our selected image
$(this).addClass("captchaAnswer");
// and remove that class from any other images
$(this).siblings().removeClass("captchaAnswer");
} );
</script>
Here's what we've done:
-- added the captcha challenge to the form
-- added a hidden field to collect the user's captcha answer
-- created javascript to record the user's answer into the hidden field
k) And finally, in the code that processes your form post, the following test to decide whether or not the form submission should be saved (PHP):
// if the form captcha answer equals the session captcha answer if ( $_POST['captchaAnswer'] == $_SESSION['captchaAnswer'] ) { // ... process this form submission // if the answer was wrong } else { // ... alert user to failure }
That's all there is to it
Download Source Code
You can take this idea further by adding more images, using ajax validation, or whatever else you can imagine.