Create custom reCAPTCHA images using their API

If you need to spam protect your contact, comment or any other public form you should think about using a CAPTCHA image. A CAPTCHA image is an image with a random text which spam bots can’t read. The visitor need to enter that text into a form field and only if there is a match the form get processed.

Try a search for “CAPTCHA image” on Google and you will find a lot of scripts, some of them are powerful and some of them are not very effective. I’m using reCAPTCHA since several years, their challenge image is very effective and safe and if people can’t read it they can listen to an audio file.

recpatcha_red

I’m sure you have seen this image before, this is the challenge image you get with their default configuration. if you don’t like this huge RED image (like me) you need a custom theme. The good news is they offer a very powerful API system for the client side and also for the server side. In this tutorial we use some jQuery code together with the reCAPTCHA ajax library to generate the challenge images. The validation process is done by a PHP script that use a simple cURL function to submit the request and response to the reCAPTCHA server to test the submitted match. We use also the jQuery form plugin to process the form fields and client side validation.

If you like to see how it looks like check this custom CAPTCHA theme demo page.

reCAPTCHA client side script

Before we start we need to register a domain name at the reCAPTCHA website to receive a public and private key. To create a custom challenge image the Ajax way, we need to include the external file recaptcha_ajax.js and we use the following JavaScript code:

var RecaptchaOptions = {
	theme : 'custom'
};
Recaptcha.create('your public key', 'recaptcha_image', RecaptchaOptions);
Recaptcha.focus_response_field();

There is only one option required for this custom function, check this link if you like to set more options.
Next we need a small HTML snippet to show the challenge image:

<div id="recaptcha_image"></div>
<p>
	<input type="text" name="recaptcha_response_field" id="recaptcha_response_field" size="30" />
	<input type="submit" value="Submit" id="submit_button" /> 
</p>

To get this working you need to create a form text field with the name and ID recaptcha_response_field, use the same ID name of the target DIV container as you used in the JavaScript function. Using both snippets in used in a HTML page will generate a neutral CAPTCHA image like:

captcha

The current code doesn’t process our CAPTCHA validation script. We do this using jQuery and the jQuery form plugin. In this tutorial we do not explain how the plugin works, we did that already in this jQuery form plugin tutorial. In the next JavaScript snippet we check if the text field is not empty and if there is a response we hide the form and show the response in the DIV container output.

$(document).ready(function() { 
	var options = { 
        target:        '#output',   // target element(s) to be updated with server response 
        beforeSubmit:  showRequest,  // pre-submit callback 
        success:       showResponse,  // post-submit callback 
        url:       'recaptcha.php'  // override for form's 'action' attribute 
    }; 
    $('#myform').submit(function() { 
        $(this).ajaxSubmit(options); 
        return false; 
    });
	var RecaptchaOptions = {
		theme : 'custom'
	};
 	Recaptcha.create('your public key', 'recaptcha_image', RecaptchaOptions);
}); 
// pre-submit callback 
function showRequest(formData, jqForm, options) { 
	var resp_field = $('input[name=recaptcha_response_field]').fieldValue();
	if (!resp_field[0]) { 
		alert('You need to enter the validation string.'); 
		return false; 
	} 
} 
// post-submit callback 
function showResponse(responseText, statusText)  { 
    if (statusText == 'success' && responseText != '') {
    	$('#formcont').html(''); 
	} else {
		alert('Error while processing your request\nPlease try it again on a later moment.'); 
	}
}

Server side validation script

Next we need to create a PHP script called recaptcha.php that will validate the entered text from our CAPTCHA image.

if (!empty($_POST['recaptcha_response_field'])) {
	$answer = trim(stripslashes($_POST['recaptcha_response_field']));
	$postData['challenge'] = $_POST['recaptcha_challenge_field'];	
	$postData['response'] = urlencode($answer);
	$postData['remoteip'] = $_SERVER['REMOTE_ADDR'];
	$postData['privatekey'] = 'your private key';
	$ch = curl_init("http://api-verify.recaptcha.net/verify");
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	$data = curl_exec($ch);
	curl_close($ch);
	$response = explode(PHP_EOL, $data);
	if ($response[0] == 'true') {
		echo 'Success, you may proceed!';
	} else {
		echo 'Error, please try again.';
		// check the API documentation for detailed error reports
	}
}

In this script we create a post array for the cURL function and post all the data to the reCAPTCHA API URL. Note all used variables are required, the post variable recaptcha_challenge_field is generated by the client API. The value for the challenge entry need to be encoded before we can post that value to the reCAPTCHA API. After we received the response we split the string and check if the first part is equal to true and output a success or error message which is presented in the target DIV container.

If you like to use this script on your own website feel free to download the script on finalwebsites.com.

Comments

  1. A lot of this logic, including the ability to display custom themes, is encapsulated in the Services_ReCaptcha PEAR package.

  2. Hi Michael,

    ever thought about that this kind of comments are spam too?
    You promote PEAR, even if it’s a free product ;)

  3. Olaf,

    Sorry, I forgot you’re not a fan of PEAR :)

    Your tutorial is well written and is helpful for people to learn how to integrate with reCAPTCHA.

    My reason for mentioning Services_ReCaptcha is not to take away from the educational aspects of your post, but to let people know a well written packaged solution also exists.

    Cheers, and happy coding!

  4. Your tutorial is well written and is helpful for people to learn how to integrate with reCAPTCHA.

    The reason for this tutorial is to show how stuff works PLUS how-to create a custom challenge for your form using jQuery and the jQuery form plugin.
    I’m sure there are many scripts for creating and validating a reCAPTCHA challenge, but do the work slightly together with jQuery like in this tutorial? I don’t think so…

  5. Thanks man! easy to follow.

  6. This is weird. The ReCaptcha documentation says to put recaptcha_image inside recaptcha_widget, and to give recaptcha_widget as the value of the option custom_theme_widget. However, just have recaptcha_image by itself, and instead pass that as the div argument to Recaptcha.create(). Is that legit?

  7. Hello Bob,

    I took some example code and put that code together with jQuery contact form plugin :)
    I’m the example code from here on several websites (try the contact form on my company site finalwebsites.nl)
    Anyway do you have any problems with this code? Since I’m using the reCaptcha image on dutch language websites I think the challenges are very hard, even if use “nl” as localization parameter.

  8. Hello,

    I followed exactly your steps as described, the captcha work, but when i submit the form, even if i put wrong code or nothing and i click submit, the form gets submited, im using it to secure a link (URL).

    If you can be of any help please …
    Regards

  9. Hi,
    do you tried the example code?

    (I removed your code because it wasn’t stored by 100% by wordpress)

  10. Hi,

    In my case if i put wrong code or nothing it won’t submit so this is working fine for me but when i submit with proper code it says
    Fatal error: Call to undefined function curl_init()on recaptcha.php line 9

    this is the line it refers to

    $ch = curl_init(“http://api-verify.recaptcha.net/verify”);

    and the rest of it is

    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $data = curl_exec($ch);
    curl_close($ch);
    $response = explode(PHP_EOL, $data);
    if ($response[0] == ‘true’) {
    echo ‘Success, you may proceed!’;
    } else {
    echo ‘Error, please try again.’;
    // check the API documentation for detailed error reports
    }

    Hope you can help me please

    Best

  11. Hello Angela,

    you need to install cURL on your web server. Ask your hosting provider to do that for you, it’s a very common library.

  12. thanks olaf ^^

  13. you’re welcome Angela :)

Because of all the spam attemps I've decided to close the comment form at this time. If you have have any questions or comments please post them by using Google+ or Twitter (the links to my profiles are located at the top of this page).