PHP DevCenter

oreilly.comSafari Books Online.Conferences.

We've expanded our LAMP news coverage and improved our search! Search for all things LAMP across O'Reilly!

Search
Search Tips

advertisement

Listen Print Discuss Subscribe to PHP Subscribe to Newsletters

Securing Web Forms with PEAR's Text_CAPTCHA

by Marcus Whitney
03/31/2005

When you have publicly available forms on the Web, you are always prone to attack by people who want to use your application for their own purposes. Forums, polls, guestbooks, and blogs are the popular places for robots to try to generate inauthentic posts on your site. Many sites, such as Yahoo, now employ CAPTCHA. CAPTCHA, or "completely automated public Turing test to tell computers and humans apart," is a project of the Carnegie Mellon School of Computer Science that sets out to determine if a human or a computer initiated a request. CAPTCHA technology enables you to discern human requests from computer generated requests on the Web, where such a distinction is difficult.

Note: According to Wikipedia, a Turing test is a proposal for a test of a machine's capability to perform human-like conversation.

You have probably seen the CAPTCHA project in action at some of your Web destinations. Its principal tool is a randomly created image that contains a phrase unmentioned in computer-readable text on the rendered page. The form asks the user to provide the phrase. If the form post does not contain the correct phrase, you can safely assume either the human made a user error, or it wasn't a human at all.

Installing Text_CAPTCHA

Thanks to Christian Wenz, PEAR has a package entirely dedicated to providing these tests as security tools in your web application. The Text_CAPTCHA package uses PHP's GD functionality to create dynamic images with random phrases in a simple object-oriented interface. Before you can use Text_CAPTCHA, you must have GD installed with support for JPEGs, PNGs and TrueType fonts. For more information, see PHP Image Functions.

Text_CAPTCHA depends on two other PEAR packages, Image_Text and Text_Password. It uses Text_Password to generate the random phrase used in the CAPTCHA test and Image_Text to generate an image file with text in it. The process for installing Text_CAPTCHA at the command line is:

$ pear install Text_Password
$ pear install Image_Text
$ pear install --alldeps Text_CAPTCHA

Presenting CAPTCHAs

Now it's time to put this package to work. A simple and often-used interface to implement this new security measure is the comments form on a blog. In this form you typically capture the name, email, and comment from the person posting to your blog. A form might look as follows:

<form method="POST" action="">
   Name: <input type="text" name="name" /><br />
   Email: <input type="text" name="email" /><br />
   Comment: <textarea name="comment"></textarea>
   <input type="submit" />
</form>

To add a CAPTCHA technology to the form, add an image tag above the submit button for human verification:

    Please enter the text in the image below: <input type="text"
name="captcha_phrase" /><br />

    <img src="captcha.jpg" />

Here's where Text_CAPTCHA comes in. Prior to outputting the form, implement Text_CAPTCHA with code like the following:

<?php
require_once('Text/CAPTCHA.php');
$captcha = Text_CAPTCHA::factory('Image');
$captcha->init(150,150);
?>

Related Reading

Upgrading to PHP 5
By Adam Trachtenberg

The first line requires the Text_CAPTCHA.php file. The second line uses Text_CAPTCHA's factory method to return an object from a subclass of Text_CAPTCHA. Text_CAPTCHA's design allows for different driver types to render CAPTCHA. Remember, CAPTCHA is a technology for telling humans apart from computers, not just for generating images to do so. The argument to the factory method is Image, instructing Text_CAPTCHA to create an object with the Image driver in order to create a random image. The third line initializes the Text_CAPTCHA object and prepares it for use.

The initialization phase bears more examination. To start, it accepts two parameters: the width and height of the randomly created image. These parameters are optional, with default values of 200 and 80, respectively. init() also accepts two additional, optional parameters. The first is $phrase, which allows the programmer to set the secret phrase to use in the generated image. If you don't pass in a phrase, init() will automatically create a phrase for you with a maximum of eight characters. The final parameter is an $options array, which allows you to pass options into PEAR's Image_Text object, which init() uses to create the image with text.

The $options array is an important parameter for this use of Text_CAPTCHA, as these options configure the font and font size to use, as well as the path to the fonts on your system. (The default font path will probably not work, unless you run this tutorial on Windows.) To set these, create and pass an array into the init() method as follows:

$text_image_options = array(
    'font_size'=>'20',
	'font_path'=>'/path/to/fonts/',
    'font_file'=>'ARIAL.TTF'
);

$captcha->init(150,150,NULL,$text_image_options);

Once init() has created the image and the phrase, the rest of the process is pretty simple. You must create an image file that the browser can display. init() doesn't do that for you. In order to access the image, use the getCAPTCHAAsJPEG() or getCAPTCHAAsPNG() accessor methods, both of which return the randomly generated image data in a buffer so that you can easily dump the data into a fresh file. If you are using PHP4, the way to do this is:

  $image_data = $captcha->getCAPTCHAAsJPEG();
  $handle = fopen('captcha.jpg', 'a');
  fwrite($handle, $image_data);
  fclose($handle);

PHP5 has made this a lot easier through the new file_put_contents function:

  $image_data = $captcha->getCAPTCHAAsPNG();
  file_put_contents('captcha.png',$image_data);

The next thing to do is to extract the phrase from the current object and store it in a session variable. If you haven't created a session for this user, now is a good time to do so:

session_start();

Now, using the getPhrase() accessor method of Text_CAPTCHA, set a session variable to the phrase in preparation for the test on the form post:

$_SESSION['captcha_phrase'] = $captcha->getPhrase();

Validating CAPTCHAs

That's it for the form side. It's time now for the code that determines if the user is a human or not. On the form post, simply check to see if the posted phrase is set and equals the value in the session. If they match, you can proceed with the appropriate POST action. Otherwise, discard the form post and take further steps as you see fit. The following code demonstrates the logic in asserting the CAPTCHA test:

<?php
  session_start();
  if (isset($_POST['captcha_phrase']) &&
      $_POST['captcha_phrase'] == $_SESSION['captcha_phrase'])
  {
    // do post activity
  }
  else {
    // do security audit
  }
?>

Conclusion

CAPTCHA can be a great way to limit the amount of successful, unwanted HTTP POST requests in your application. Text_CAPTCHA provides an adequate object to quickly implement this functionality. At the present time, the package is in alpha, and therefore not officially production-ready. However, it is off to a great start and brings a touch of security consciousness to PEAR that is always appreciated. Happy CAPTCHA-ing!

Marcus Whitney is Director of Product Development for Emma, an email marketing service powering the email marketing efforts of over 1800 organizations around the world with offices in New York City (where he's from) and Nashville (where he lives).


Return to the PHP DevCenter.


Have a question about using CAPTCHAs on your site from PHP? Ask Marcus here.
You must be logged in to the O'Reilly Network to post a talkback.
Post Comment
Full Threads Newest First

Showing messages 1 through 9 of 9.

  • Visually impaired people
    2005-04-15 01:38:43  riffraff [Reply | View]

    why people keep suggesting using a messed up image to check if people are real or bots?

    What about the people that can't see well? I mean, we have accessibility guidelines suggesting we put an alt text on every image and then we cut out from a service all the blind and visually impaired people?

    PS
    I think reusing the same file at every access causes a classical race condition, but I may be wrong..
    • Visually impaired people
      2008-06-13 23:37:23  miguel.garcia [Reply | View]

      In the case of Visually impaired people many websites use sound for validation, so, the user must type what he hear.

      I think you are right with the race condition, a possible solution is to use a .php file as the source of the image and in that file generate the image with the Text_Captcha and echo it.
  • non-pear alternative
    2005-08-24 04:32:20  random_ [Reply | View]

    if you don't have PEAR installed, try this great php/gd CAPTCHA, freecap: http://www.puremango.co.uk/cm_freecap_113.php
  • kill captcha text after form post
    2005-11-19 10:40:28  sullivat [Reply | View]

    You would probably want to take some kind of action against allowing the user to just hit refresh to resubmit the form, such as clearing out the captcha text in the session, or sending a redirect header after the form completes successfully.

    As for visually-impaired users, there are some things you can do to make the form more accessible. If you want the HTML to validate, you do need an alt tag on that image, but I would just put something like "captcha text". I would also want to put a link to download a wav file of the captcha text being pronounced. I haven't tried making audio with php before, but if you have a festival on your machine you can probably access that through system functions to make the wav file.

    And also, it's good practice to lock the file anytime you do an input/output operation to it to avoid race conditions. See http://php.net/flock
  • code not working
    2006-03-06 04:05:40  a1u4z8 [Reply | View]

    I get this error
    Notice: Object to string conversion in ....
    in the following line

    fwrite($handle, $image_data);

    and the content of image file is the word "Object"

    I think it is due to method getCAPTCHAAsPNG return and object and fwrite needs a string

    Any solution ?
  • Using $_SESSION variables
    2006-09-03 20:38:21  Lee73 [Reply | View]

    Isn't using session variables a gigantic achille's heal? It's trivial to read this with Curl (or whatever) and automate away.

    I wrote an implementation recently that wrote a captcha with values 'XYZ', a hidden field with code 'ABC'. Simultaneously write to a table with two fields: ABC and XYZ. The only way the user can read XYZ is through viewing the image. It's more overhead, but less easily bypassed.
  • Need a little help
    2007-01-31 13:29:42  TechiMi [Reply | View]

    Despite never having tried anything like this before, I managed to install pear and the modules I needed and fix a lot of script errors on intuition but I think I'm stuck now.

    If I use the PHP5 way I get:

    Fatal error: Call to undefined function: file_put_contents() in /home/.lovey/goshenpublicli/goshenpubliclibrary.org/writejaemi.html on line 24

    If I try the PHP4 way, even though I have PHP5, I get..well, an even longer message. I think the shorter one is probably easy enough to fix I just don't know how since I've not done much with PHP, so even searching just leaves me confused.
  • Problem with CAPTCHA code.
    2007-04-09 03:37:03  DNagesh [Reply | View]

    Hello Support Team,
    I have followed all the steps to implement the CAPTCHA. Below is part of the code:
    $captcha->init(150,150);
    $image_data = $captcha->getCAPTCHAAsJPEG();
    $handle = fopen('captcha.jpg', 'a');
    The problem is that it is not showing the phrase on the image. I think the problem is with fwrite($handle, $image_data); This line should write the phrase onto the original jpg image. But it is not writting. Please tell me the solution. The user will be entering the phrase but it should be shown on the image and that is what it is not showing.

    I think it is due to method getCAPTCHAAsPNG return and object and fwrite needs a string. Please reply as soon as possible.

    Thankyou all.
  • Site
    2007-11-28 04:02:18  gini007 [Reply | View]

    Hi i recently started a new web site and i will try to use the captcha service the web site is for promovare web (http://sergiubirzu.com/)


Tagged Articles

Post to del.icio.us

This article has been tagged:

php

Articles that share the tag php:

Understanding MVC in PHP (477 tags)

The PHP Scalability Myth (123 tags)

The Dynamic Duo of PEAR::DB and Smarty (53 tags)

PHP Form Handling (43 tags)

Very Dynamic Web Interfaces (39 tags)

View All

security

Articles that share the tag security:

Secure RSS Syndication (169 tags)

Google Your Site For Security Vulnerabilities (74 tags)

Building a Desktop Firewall (64 tags)

The Next 50 Years of Computer Security: An Interview with Alan Cox (42 tags)

Protect Yourself from WiFi Snoops (40 tags)

View All

captcha

Articles that share the tag captcha:

Securing Web Forms with PEAR's Text_CAPTCHA (3 tags)

View All

pear

Articles that share the tag pear:

The Dynamic Duo of PEAR::DB and Smarty (37 tags)

Programming eBay Web Services with PHP 5 and Services_Ebay (12 tags)

Three-Tier Development with PHP 5 (6 tags)

PHP's PEAR on Mac OS X (6 tags)

Caching PHP Programs with PEAR (6 tags)

View All

Sponsored Resources

  • Inside Lightroom
Advertisement

Sponsored by:

O'Reilly Media

©2009, O'Reilly Media, Inc.
(707) 827-7000 / (800) 998-9938
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
About O'Reilly
Academic Solutions
Authors
Contacts
Customer Service
Jobs
Newsletters
O'Reilly Labs
Press Room
Privacy Policy
RSS Feeds
Terms of Service
User Groups
Writing for O'Reilly
Content Archive
Business Technology
Computer Technology
Google
Microsoft
Mobile
Network
Operating System
Digital Photography
Programming
Software
Web
Web Design
More O'Reilly Sites
O'Reilly Radar
Ignite
Tools of Change for Publishing
Digital Media
Inside iPhone
O'Reilly FYI
makezine.com
craftzine.com
hackszine.com
perl.com
xml.com

Partner Sites
InsideRIA
java.net
O'Reilly Insights on Forbes.com