reCAPTCHA with CakePHP Forms Tutorial

January 14th, 2011 Leave a comment
Like the article?
reCAPTCHA with CakePHP

Unfortunately, as a developer today, you have to consider the possibility of spammers using automated scripts to submit the forms on your web site. One popular method for preventing this is to use a CAPTCHA. A CAPTCHA is an image that contains words or an alphanumeric code. The image is often slightly distorted. The user must correctly enter the words or code for the form to be considered valid. This prevents scripts from submitting forms since the CAPTCHA is not readable by automated systems.

The most popular system for implementing CAPTCHA is reCAPTCHA by Google. reCAPTCHA provides an API that makes it easy for any developer to include CAPTCHAs on their web forms. Furthermore, their API provides an audio of the CAPTCHA to help the visually impaired use your web form. This means you can still create accessible systems while protecting your forms from automated SPAM.

As a side note, reCAPTCHA is pretty cool because the test words are actually snippets from scanned books. By completing the CAPTCHA, users are fine tuning the optical character recognition system. Basically, reCAPTCHA works by presenting 2 words. For one of them, the correct answer is known. If the user submits the correct answer for the known word, the unknown one is considered correct. By serving the same unknown word to multiple users, a certain amount of statistical certainty about it can be created. This allows Google to improve their OCR systems.

CAPTCHAs make the most sense on certain forms. Obviously contact forms and other forms that send email are the best places to use a CAPTCHA. However, registration forms are also a good place for one. Spammers will often create accounts on web sites hoping to be able to spam by posting in forums or through email.

I am going to show one method of using reCAPTCHA with CakePHP. To do this, we’ll make a mock registration form but I won’t be getting into a lot of extra details such as confirming passwords and so on. We’re going to focus on the CAPTCHA portion.

To begin, you’ll need to download the PHP library from reCAPTCHA. While you can develop a helper and component to utilize reCAPTCHA, we’re instead going to use the existing PHP library from within CakePHP. The PHP library consists of a single file called recaptchalib.php. Make a new subdirectory of your /vendors directory under your CakePHP installation call reCAPTCHA and place this file in the subdirectory.

We’re going to need a user model to save our registration data. For our example, let’s assume that our User model consists only of an email address, username and password. We’ll use CakePHP’s model validation to make sure that all of the fields are submitted, that a valid email address is submitted and that the username is unique.

Our registration form will need to include the CAPTCHA and a place for the user to type the code. Fortunately, the reCAPTCHA library takes care of this for us. We’re also going to manually write some of the form code. I prefer to wrap my form in an unordered list and I prefer to have field errors inside the label. For my code, I pass parameters to the form helper’s create method to suppress automatically adding div tags and labels:

$form->create('User', array(
	'action'=>'register',
	'inputDefaults' => array(
		'div' => false,
		'label' =>false
	)
));

Then for each form element I output a label, test for an error and output it and finally show the input box. That looks something like this (remember, my form elements are list items in an unordered list):

echo '<li><label for="UserEmail">Email';
if ($form->isFieldError('email')) {
	echo '<br/><strong>' . $form->error('email') . '</strong>';
}
echo '</label>';
echo $form->text('email');
echo '</li>';

After, I’ve output all the form fields but before I close the form or add the submit button, I’ll output the CAPTCHA. First, we’ll need to import the library:

App::import('Vendor','recaptcha/recaptchalib');

This code is the CakePHP equivalent of PHP’s require_once. The parameters tell CakePHP where to find the file to include. In the case, ‘Vendor’ means that it is in the vendors subdirectory. ‘recaptcha/recaptchalib’ tells CakePHP that the file is recaptchalib.php and it is in the “recaptcha” subdirectory of the vendors folder. Here’s how I ouptut the CAPTCHA:

$publickey = ' <your ReCaptcha Public Key>';
if (isset($recaptcha_error)) {
	echo '<strong>' . $recaptcha_error . '</strong><br/>';
}
echo recaptcha_get_html($publickey);

This differs slightly from the sample code provided on the reCAPTCHA web site. The sample code for processing the CAPTCHA has a die statement so that if you do not enter the CAPTCHA correctly, you get a page with an error and instructions to go back and try again. I wanted to output an error message and allow the user to just try again. In my processing code, instead of dying on an error, I’ll set a user-friendly message in $recaptcha_error. The above code looks for the error and if it exists, displays it to the user.

Now, let’s look at our controller code and how we actually process the CAPTCHA. Since we need to check the CAPTCHA and return an error if it is not correct, we’ll want to validate the data from the controller rather than rely on the model.save() method to validate our data. Here’s the code:

if (!empty($this->data)) {
	App::import('Vendor','recaptcha/recaptchalib');
	$privatekey = ' <Your ReCaptcha Private Key>';
	$resp = recaptcha_check_answer( $privatekey, 
					$_SERVER['REMOTE_ADDR'],
					$_POST['recaptcha_challenge_field'],
					$_POST['recaptcha_response_field']);
	if (!$resp->is_valid) {
		$this->set('recaptcha_error', 
			'You did not enter the words correctly.  Please try again.');
	}
	$this->User->set($this->data);
	if (($this->User->validates()) && ($resp->is_valid)) {
		// Success!  Write code to save and redirect user as needed
	} else {
		$errors=$this->User->invalidFields();
		$this->set('errrors',$errors);
	}
}

We check first to see if any data was submitted. If it was, we load the reCAPTCHA library and make a call to the API to check the submitted response to the CAPTCHA. If the response is not valid, we set our user-friendly error message. Next, we load the model with our submitted data and call the validates() method on it. If validates() returns true and the reCAPTCHA response is valid, we have successfully submitted a new registration. We would next add code here to complete the registration. This could be as simple as saving the new user, logging them in and redirecting to the home page. Or we could save the record and send a verification email.

However, if both conditions are not true, we load the $errors variable with the error messages generated by our model’s validates() method. We do this by setting $errors to invalidFields(). Now, we can use the $errors variable in our view code to display individual field errors and the $recaptcha_error variable to display any error generated by our use of a CAPTCHA.

While there are methods of using the reCAPTCHA library to display and validate CAPTCHAs that are more “CakePHP” like, we’ve looked at a very simple method for including the library in CakePHP code. Hopefully this will help you with including CAPTCHAs on your forms and fighting SPAM.

Help us spread the word!
  • Twitter
  • Facebook
  • LinkedIn
  • Pinterest
  • Delicious
  • DZone
  • Reddit
  • Sphinn
  • StumbleUpon
  • Google Plus
  • RSS
  • Email
  • Print
If you liked this article, consider enrolling in one of these related courses:
Don't miss another post! Receive updates via email!

Comment