jQuery Tutorial – Create Captcha without server-side code

jqueryCreating human validating fields (Captcha) is necessary to avoid robot spamming. While the general ones, like reCaptcha, are being bypassed by several services in the web, like De-Captcher, creating a new solution has come in need.

For the purpose of this tutorial we will be creating a simple sum of two numbers between 0 and 9.

First we create an html of the form we are about to use, note that we are adding the latest jquery library to the html:

 

 

<html>
	<head>
		<script src='http://code.jquery.com/jquery-latest.min.js'></script>
	</head>
	<body>
		<form name = "myForm" id = "myForm">
			<table>
				<tr>
					<td>Name</td>
					<td><input type = "text" name = "Name" ></td>
				</tr>
				<tr>
					<td>Email</td>
					<td><input type = "text" name = "Email" ></td>
				</tr>
				<tr>
					<td colspan = "2" ><input type ="submit" value = "Submit" ></td>
				</tr>
			</table>
		</form>
	</body>
</html>

After getting set up the html, we set up a template we are going to use for appending to the form. This will be of great use, since we can have several forms and instantiate them with the code we are about to generate.

TIP: If you are having some strings that are going to be of great use in several points of the code, those are constants! Don’t be afraid of using constants. They are your friends.

var captchaTemplate = '<tr><td align = "right">[Number1] + [Number2] = </td>'
						+ '<td><input name = "captcha" > '
						+ '<input type="hidden" name = "captchaResult" value = "[CaptchaResult]" >'
						+ '<span class = "error captcha" style = "display: none;" >[CaptchaError]</span>'
						+ '</tr>';

Once we got the template for the captcha field, let’s start with the good thing. First we create the function that is going to rule over all captchas made in the site. The function is going to need two parameters: Target Form Selector, and the Error Message we are going to display.

First we set up a default value to the Error Message, with a cheap hack that checks if the type of the variable is defined or not. After setting up the default value, if needed, we create the random numbers using the Javascript function Math.random(), to get the numbers between 0 and 9, we multiply the value of Math.random() per 10 and then round the number with Math.floor(). Then we replace all in the previous template we made, that way we got the html we want!

TIP: When declaring a new variable, always use “var” before it, that way ie7 and ie8 will not crash.

function captcha( targetForm, errorMessage ) {

	if ( typeof errorMessage === "undefined" ) {
		var errorMessage	= "Incorrect Captcha. Try Again.";
	}

		// Setting up the template with random numbers.

	var number1		= Math.floor( Math.random() * 10 );
	var number2		= Math.floor( Math.random() * 10 );
	var result		= parseInt( number2 ) + parseInt( number1 );
	var captchaTpl	= captchaTemplate.replace( "[Number2]", number2 );
	captchaTpl		= captchaTpl.replace( "[Number1]", number1 );
	captchaTpl		= captchaTpl.replace( "[CaptchaResult]", result );
	captchaTpl		= captchaTpl.replace( "[CaptchaError]", errorMessage );

}

After setting up the html of the captcha we get the jQuery object of the form. Since we are getting the selector (ex. “#myForm”), it’s just needed to add it like this: $( targetForm ). Once we got the object, we find the row that has the input with type submit within the form (pretty neat, huh?), this part is easy. jQuery has a function called “.find”, so we first find the input[type=submit], and we use the “.closest” function to find the parent tr.

Once we got the html into a new variable, we remove it from the form and append to the table the captcha html and then the row we just delete :). There are many ways to do this, but I prefer doing this one, there is no margin of error, or we don’t lose anything.

TIP: Converting all the selector to jQuery object will avoid some unnecessary code writing.

function captcha( targetForm, errorMessage ) {

	if ( typeof errorMessage === "undefined" ) {
		errorMessage	= "Incorrect Captcha. Try Again.";
	}

		// Setting up the template with random numbers.

	var number1		= Math.floor( Math.random() * 10 );
	var number2		= Math.floor( Math.random() * 10 );
	var result		= parseInt( number2 ) + parseInt( number1 );
	var captchaTpl  = captchaTemplate.replace( "[Number2]", number2 );
	captchaTpl		= captchaTpl.replace( "[Number1]", number1 );
	captchaTpl		= captchaTpl.replace( "[CaptchaResult]", result );
	captchaTpl		= captchaTpl.replace( "[CaptchaError]", errorMessage );

		// Convert the targetForm to an jQuery Object

	var formObj	= $( targetForm );

		// Obtain the html of the submit row

	var oldSubmit   = formObj.find( "table input[type=submit]" ).closest( "tr" ).html();

		// Remove the row which contains the submit button

	formObj.find( "table input[type=submit]" ).closest( "tr" ).remove();

		// Append the captcha row and then the submit html

	formObj.find( "table" ).append( captchaTpl + oldSubmit );

}

Next, and final step, we do the submit handler for the form. It is quite easy, since the form’s html got the result for the sum we are doing, and the type is right there, we just compare the two.

function captcha( targetForm, errorMessage ) {

	if ( typeof errorMessage === "undefined" ) {
		errorMessage	= "Incorrect Captcha. Try Again.";
	}

		// Setting up the template with random numbers.

	var number1		= Math.floor( Math.random() * 10 );
	var number2		= Math.floor( Math.random() * 10 );
	var result		= parseInt( number2 ) + parseInt( number1 );
	var captchaTpl  = captchaTemplate.replace( "[Number2]", number2 );
	captchaTpl		= captchaTpl.replace( "[Number1]", number1 );
	captchaTpl		= captchaTpl.replace( "[CaptchaResult]", result );
	captchaTpl		= captchaTpl.replace( "[CaptchaError]", errorMessage );

		// Convert the targetForm to an jQuery Object

	var formObj	= $( targetForm );

		// Obtain the html of the submit row

	var oldSubmit   = formObj.find( "table input[type=submit]" ).closest( "tr" ).html();

		// Remove the row which contains the submit button

	formObj.find( "table input[type=submit]" ).closest( "tr" ).remove();

		// Append the captcha row and then the submit html

	formObj.find( "table" ).append( captchaTpl + oldSubmit );

		// Set up the submit handler

	formObj.submit( function( e ) {

			// Set up the jquery object

		var myForm	= $( e.target );

			// Get the values to compare

		var result		= myForm.find( "input[name=captchaResult]" ).val();
		var humanRes	= myForm.find( "input[name=captcha]" ).val();

			// Compare the input value and the correct value

		if ( result == humanRes ) {

				// It is correct! Submit the Form! FIRE!

			myForm.submit();

		} else {

				// It is incorrect! Show the error field, and stop the submit :(

			e.preventDefault();
			myForm.find( "span.captcha" ).show();

		}
	});

}

Finally, we got all we need in a function, the only thing missing is the actual call. So inside a $( document ).ready, we call the function. The final html should look like this:

<html>
	<head>
		<script src='http://code.jquery.com/jquery-latest.min.js'></script>
		<script type="text/javascript">
			var captchaTemplate	= '<tr><td align = "right">[Number1] + [Number2] = </td>'
									+ '<td><input name = "captcha" > '
									+ '<input type="hidden" name = "captchaResult" value = "[CaptchaResult]" >'
									+ '<span class = "error captcha" style = "display: none;" >[CaptchaError]</span>'
									+ '</tr>';

			function captcha( targetForm, errorMessage ) {

				if ( typeof errorMessage === "undefined" ) {
					var errorMessage	= "Incorrect Captcha. Try Again.";
				}

					// Setting up the template with random numbers.

				var number1		= Math.floor( Math.random() * 10 );
				var number2		= Math.floor( Math.random() * 10 );
				var result		= parseInt( number2 ) + parseInt( number1 );
				var captchaTpl	= captchaTemplate.replace( "[Number2]", number2 );
				captchaTpl		= captchaTpl.replace( "[Number1]", number1 );
				captchaTpl		= captchaTpl.replace( "[CaptchaResult]", result );
				captchaTpl		= captchaTpl.replace( "[CaptchaError]", errorMessage );

					// Convert the targetForm to an jQuery Object

				var formObj	= $( targetForm );

					// Obtain the html of the submit row

				var oldSubmit	= formObj.find( "table input[type=submit]" ).closest( "tr" ).html();

					// Remove the row which contains the submit button

				formObj.find( "table input[type=submit]" ).closest( "tr" ).remove();

					// Append the captcha row and then the submit html

				formObj.find( "table" ).append( captchaTpl + oldSubmit );

					// Set up the submit handler

				formObj.submit( function( e ) {

						// Set up the jquery object

					var myForm	= $( e.target );

						// Get the values to compare

					var result		= myForm.find( "input[name=captchaResult]" ).val();
					var humanRes	= myForm.find( "input[name=captcha]" ).val();

						// Compare the input value and the correct value

					if ( result == humanRes ) {

							// It is correct! Submit the Form! FIRE!

						myForm.submit();

					} else {

							// It is incorrect! Show the error field, and stop the submit :(

						e.preventDefault();
						myForm.find( "span.captcha" ).show();

					}
				});
			}
			$( document ).ready( function() {
				captcha( "#myForm" );
			});
		</script>
	</head>
	<body>
		<form name = "myForm" id = "myForm">
			<table>
				<tr>
					<td>Name</td>
					<td><input type = "text" name = "Name" ></td>
				</tr>
				<tr>
					<td>Email</td>
					<td><input type = "text" name = "Email" ></td>
				</tr>
				<tr>
					<td colspan = "2" align = "center" ><input type ="submit" value = "Submit" ></td>
				</tr>
			</table>
		</form>
	</body>
</html>

Thank you for reading this quick tuto. I will be writing more quick tutos, and some more extensive :)

Here at Psynapsis.net, we can develop all the things you need, from simple javascript to extensive jQuery libraries.

Leave a Reply

Your email address will not be published. Required fields are marked *