Embedding CAPTCHAs
From Docupedia
Written By: Bryan Rite
Date: 2/8/2007
Contents |
Overview
Captchas are an important part of securing your website against unwanted bots and auto-advertising. While not the best solution to these problems, it has become an industry standard practice and users are getting more used to it.
I'll show you how to make a quick and easy captcha field on your form using PHP, PEAR, and Sessions.
Pre-install Checklist
- PHP 4.3+
- PEAR installed with the package Text_CAPTCHA (and its dependencies)
- Ability to use Sessions (not necessary, but makes it easier)
- A font file (i.e. any .ttf file)
If you've never used PEAR before, i suggest you check it out. It has a somewhat cool package management system and can supply lots of common libraries (like Captcha) so you don't have to re-invent anything.
You can get a font file anywhere on the internet or your computer. It should be of a somewhat legible font as the user will have to read it through the captcha noise.
Creating the Captcha
To create the captcha we'll need two php files: form.php and captcha.php. One, for the form you want the captcha to appear on (form.php), and one to generate the captcha for us (captcha.php). Since captchas are never static, there is no point in actually saving the image we create anywhere on the server. Thus, we will use captcha.php file to create an image using the a bitstream from the session data (or GET var, or however you alternately want to do it).
Text_CAPTCHA is pretty well documented so for more advanced options you can read its documentation here, but i'll run you through the basics.
First we want to set up the options for our captcha image:
$options = array( 'font_size' => 24, 'font_path' => $PATH_TO_FONT, 'font_file' => 'font.ttf' );
Pretty self-explanatory. We just point to the font file and tell it how big the font should be. This is dependent on how big you want the actual captcha image to be, so you might have to play with the font size to get the desired look afterwards.
Next we use the PEAR utilities to make our captcha image:
$captcha = Text_CAPTCHA::factory('Image');
$retval = $captcha->init(200,75,null,$options);
if (PEAR::isError($retval) {
echo "Error Generating Captcha!";
exit;
}
This creates the captcha image. The options for init are width, height, phrase, and options. In our example we've created a 200x75 pixel image, the phrase variable is null so PEAR will generate something random itself, and we've passed in our font options we defined before.
The next step is we need the phrase the captcha displays and the image. I use sessions here for ease but you could use a normal php variable and edit the code to your own needs.
$_SESSION['phrase'] = $captcha->getPhrase(); $_SESSION['capImg'] = $captcha->getCAPTCHAAsPNG();
This gets the phrase, whatever random alphanumeric it is, and the image bitstream.
Displaying the Captcha
Now we technically have the captcha ready, but we don't have a way to display it. If you echoed $_SESSION['capImg'], it'd just come out as big string. What we'll do is use captcha.php to set the mime type to a .png and the browser will interpret the variable as an image instead of a string. This is very easy (especially using sessions):
header("Content-type: image/png");
echo $_SESSION['capImg'];
unset($_SESSION['capImg']);
So back on form.php, we would display the image like:
<img src="/captcha.php" width="200" height="75" alt="Captcha" />
Thats pretty much it, you can add your own form logic and do whatever you like if the captcha passes or it doesn't. I tend to make the captcha not case-sensitive because sometimes its hard enough as it is.
The Whole Files
form.php
<?php
require_once ("Text/CAPTCHA.php");
session_start();
$options = array(
'font_size' => 24,
'font_path' => $PATH_TO_FONT,
'font_file' => 'f1.ttf'
);
// Generate a new Text_CAPTCHA object, Image driver
$c = Text_CAPTCHA::factory('Image');
$retval = $c->init(200, 75, null, $options);
if (PEAR::isError($retval)) {
echo 'Error generating CAPTCHA!';
exit;
}
// Get CAPTCHA secret passphrase
$_SESSION['phrase'] = $c->getPhrase();
// Get CAPTCHA image (as PNG)
$_SESSION['capImg'] = $c->getCAPTCHAAsPNG();
?>
<html>
<body>
<form>
<p>Enter the letters: <input type="text" name="cap" size="15" maxlength="9" value="" />
<img src="/captcha.php" alt="Human Turing Test Image" width="200" height="75" /></p>
<input type="submit" />
</form>
</body>
</html>
captcha.php
<?php
session_start();
if (!isset($_SESSION['capImg']))
exit;
header("Content-type: image/png");
echo $_SESSION['capImg'];
unset($_SESSION['capImg']);
?>
Alternatives
Alternating Font Style
Ben wanted me to say that this method allows us to alternate the font style to make it even more difficult for bots to read. Since the font file is fed it at runtime, you can vary this however you like to rotate various .ttf files in and thus keep the font style changing.
Instead of SESSIONS
Sessions might not be available/viable solutions to the captcha image so there are some alternatives.
- You could just pass the var in as a
GETvar and$_GETit on thecaptcha.phpside. - You could use a Cookie. Similar to sessions.
- You could actually save the file, probably a bad idea but that depends on your implementation and what you're going to do with the captcha.
- Bryan Rite 18:02, 8 February 2007 (EST)

