April 14, 2008

Three ways to test Web form input with a CAPTCHA

Author: Ben Martin

Many Web forms these days feature a Completely Automated Public Turing test to tell Computers and Humans Apart (CAPTCHA) as an effort to stop people from setting up computers to automatically fill in Web forms. A typical CAPTCHA is an image with some numbers and letters in it with distortion and/or background noise, and a Web form input field where you are to enter the numbers and letters from the image. This article investigates three CAPTCHA applications that you can use on a PHP Web site.

Many CAPTCHA tools use gd to make images and FreeType to handle fonts. To see if your PHP installation includes support for FreeType and gd, run php -i at the command line and check the ./configure line that was used to compile PHP. If you have support you should see --with-gd in the configure options. Support for gd might be distributed in a separate package from PHP itself. If gd is available to the PHP runtime you should see a line containing gd and describing your current capabilities later in the php -i output, shown below:

$ php -i
...
gd

GD Support => enabled
GD Version => bundled (2.0.34 compatible)
FreeType Support => enabled
FreeType Linkage => with freetype
FreeType Version => 2.3.5
...

On Fedora 8, I had to install the php-gd package and restart Apache in order to get one of the three programs, capictcha, to work. If you set error_reporting(E_ALL); in capictcha-0.3.php you will see an error in your /var/log/httpd/error_log file like the one below if PHP cannot use gd. If it can't, you must install gd and/or FreeType support for PHP.

PHP Fatal error: Call to undefined function imagettfbbox()

capictcha

The first of our three alternatives, capictcha, lets you create CAPTCHA images using a string of your choice. It does not try to be a complete framework with developer-accessible PHP classes and other trimmings, but focuses squarely on generating and returning an image. This can be an advantage when you already have a PHP Web site that has custom user session tracking and would like to include a CAPTCHA without changing how your site works.

The current version of capictcha, 0.3, depends on Apache, PHP, and gd. If PHP cannot use gd, you will get no result from loading capictcha.php in your browser.

Install capictcha by expanding its tarball into your Apache DocumentRoot directory, typically /var/www/html. The single PHP file capictcha-0.3.php will generate a CAPTCHA when called with suitable CGI parameters using either POST or GET.

The three main parameters to capictcha are text, which is the text string that will appear in the image; height, which is the height of the image; and output, where you can select to produce output in PNG or JPEG image formats.

Obviously, if you are calling capictcha using the text field, you will want to avoid exposing that call to the Web client so that users cannot just feed the text parameter from your call to capictcha into the Web form that challenges the user to solve the CAPTCHA. A fourth CGI parameter, special, allows you to select a predefined text string for the CAPTCHA without revealing the string itself to a Web client. This works by using a lookup table in the capictcha PHP file mapping a selection string to the text that will appear in the CAPTCHA. The client might be able to see your selection string but will not know the text string associated with the selection string that will be used in the resulting CAPTCHA. In order to use special, you will want to edit the capictcha PHP file and search for // set up specials, where you include your list of CAPTCHAs.

With the defaults shown below, calling capictcha with the CGI parameter special=hello will result in a CAPTCHA containing the text Hi there!.

...
// set up specials
$special_hash = array(
'punk' => "'" . '"/,.!@#$%^&*()_-=\|+ ',
'hello' => 'Hi there!',
'person' => 'SSGTAC',
'random' => '12345789abdefghijmnqrtuyABCDEFGHIJKLMNOPQRSTUVWXYZ',
);

Captcha PHP

Instead of just generating the CAPTCHA image, Captcha PHP offers a PHP function API to the tasks of generating form elements with AJAX for the CAPTCHA input and verifying that the user entered the correct value. This lets you add a CAPTCHA to a Web form and check whether the user entered it correctly without having to worry about generating the CAPTCHA string and tracking what the string that the user enters should be. To get the nice functional API of Captcha PHP you must include("captcha.php"); at the top of your PHP script.

I used version 2.0 of Captcha PHP. Like capictcha, you install it by expanding the tarball into your Apache DocumentRoot.

Captchaphp generates form elements complete with some nice AJAX code by when you call print captcha::form(); inside an HTML FORM element. The PHP script that is called when the form gets submitted should call if( captcha::solved() ) { ...ok... } to see if the user entered the correct value.

The captcha::form() function takes an optional parameter that allows you to specify some HTML that is placed between the CAPTCHA image and the input field for the user to enter the CAPTCHA string. For example, the code below adds a register button between the CAPTCHA and the form input box where the user enters the CAPTCHA string:

captcha::form("<small><a href="...">register</a> to avoid this check</small><br/>");

You can also customize the generated form using CSS; in particular, you can edit the .captcha class and #captcha ID selectors. For details, see the README file from the Captcha PHP distribution.

KCAPTCHA

From the perspective of integration into an existing site, KCAPTCHA sits between capictcha and Captcha PHP. KCAPTCHA gives you elements to track whether the user entered the right response to the CAPTCHA, but there is no clean PHP API like Captcha PHP provides to perform this check. KCAPTCHA does not try to generate a whole section in a form for the CAPTCHA image and response form element, but leaves that up to you.

I used version 1.2.5 of KCAPTCHA. To download the tarball you have to register with phpclasses.org, which requires an email confirmation notice, which might make you favour one of the above solutions instead. The tarball expands directly into the current directory, so you will want to create and change into a new subdirectory named kcaptcha under your DocumentRoot before you expand the tarball.

The utility's index.php file generates the CAPTCHA images. An example is provided in example.php. The package performs generation and verification of CAPTCHA using the PHP session. KCAPTCHA does not require you to include() a PHP file to use it. A drawback of this approach is that you have to directly test _SESSION yourself using code like that shown below in order to see if the user entered the CAPTCHA correctly.

<form ...>
...
<img src="index.php?<?php echo session_name()?>=<?php echo session_id()?>"><
...
</form>

...

if(isset($_SESSION['captcha_keystring'])
&& $_SESSION['captcha_keystring'] == $_POST['keystring'])
{
... ok ...
}

Which one to use?

At its core, a CAPTCHA is just some text presented as an image with some distortion to make it hard for a computer to work out what the text is. You might favour the look or human readability of the CAPTCHA image that one of these tools generates, making the integration of the tool into your Web site the secondary concern.

From a programmer's perspective, if you want to explicitly set what string is presented in a CAPTCHA image, using capictcha will give you a quick solution. If you just want to quickly add a CAPTCHA to a Web form, Captcha PHP is a quick solution with the added bonus of feedback to the user as they type and nice CSS integration. Both Captcha PHP over KCAPTCHA aim to provide a CAPTCHA solution that is easy to integrate into a Web form. I would use Captcha PHP because it provides nice JavaScript feedback to the user, offers a nice PHP interface to test if the CAPTCHA was entered correctly, and does not require registration to download.

Categories:

  • Programming
  • PHP
  • Internet & WWW