If you're looking for a way to prevent brute-force attacks against your login pages, automated sign-ups through your registration forms, or automated spam in your blog commenting system, then look no further! In this article, I'll guide you through the basics of creating and integrating a security image like those found on the sign-up pages of many mainstream sites.
A security image is a visual representation of a number of random characters that can be easily read by humans, but is difficult for a computer program to interpret. If you integrate such an image into your form, ask your site visitors to enter into a separate input box the letters they see in the image, and compare the two, you can easily distinguish humans from machines.
Server Requirements
This project requires that you have a Web server with PHP and the GD library installed, so make sure your hosting environment supports these packages if you want to try out this tutorial. The example we'll discuss writes GIF images, but you could easily substitute the relevant functions to output JPEG or PNG images instead, if that's all your hosting environment supports.
Creating a Reusable Security Image Class
To begin, we'll create a reusable PHP class that we can use to generate security images; we'll finish up with a simple login screen that demonstrates the use of this class.
Our class will need to perform a number of tasks to generate a suitable security image. It will need to:
Create a blank image with a white background.
Add some random background noise to the image. This will help to confuse automated processes that try to use character recognition algorithms to identify the characters within the image.
Write out a specified number of random characters using random font selection for each character.
Write the image to the user's browser. For added flexibility, our class will also provide the option to write the image to a file, although this isn't a core requirement of this example.
Here's the skeleton of our security image class:
class SecurityImage {
var $oImage;
var $iWidth;
var $iHeight;
var $iNumChars;
var $iNumLines;
var $iSpacing;
var $sCode;
function SecurityImage(
$iWidth = 150,
$iHeight = 30,
$iNumChars = 5,
$iNumLines = 30
) {
}
function DrawLines() {
}
function GenerateCode() {
}
function DrawCharacters() {
}
function Create($sFilename = '') {
}
function GetCode() {
}
}
Here, we've defined a few class properties; these will hold important information that we'll use when we generate our image. The class constructor will take four parameters, allowing us to change the appearance of the generated image. Specifically, we can choose the overall width and height of the image, the number of characters we want the image to display, and the number of background lines (or the amount of noise) to draw.
Coding the Constructor
The constructor will create the blank image, assign parameters to class properties and define the background colour of our image. Let's add that code now:
function SecurityImage(
$iWidth = 150,
$iHeight = 30,
$iNumChars = 5,
$iNumLines = 30
) {
// get parameters
$this->iWidth = $iWidth;
$this->iHeight = $iHeight;
$this->iNumChars = $iNumChars;
$this->iNumLines = $iNumLines;
// create new image
$this->oImage = imagecreate($iWidth, $iHeight);
// allocate white background colour
imagecolorallocate($this->oImage, 255, 255, 255);
// calculate spacing between characters based on width of image
$this->iSpacing = (int)($this->iWidth / $this->iNumChars);
}
The last line calculates a value for the spacing to include between characters, based on the number of characters it needs to generate, and the image width we specified.
Making some Noise
Next, we'll add code to create background noise (the lines). We add the lines first, because we want the characters to sit above them in the image, ensuring that the characters can be read by human users.
function DrawLines() {
for ($i = 0; $i < $this->iNumLines; $i++) {
$iRandColour = rand(190, 250);
$iLineColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
imageline($this->oImage, rand(0, $this->iWidth), rand(0, $this->iHeight), rand(0, $this->iWidth), rand(0, $this->iHeight), $iLineColour);
}
}
As the code loops, it creates lines of random lengths in random positions. Each line is drawn with a random grey scale selected from a RGB range. I have chosen a range of 190-250 to sufficiently obscure the characters from any automated process that might try to interpret them, while at the same time offering enough contrast to make them easily readable without squinting! You'll see below that we've chosen a darker grey scale range to write out the characters. You can increase or decrease the number of lines drawn -- and, therefore, the noise generated -- by passing a higher or lower value to the lines parameter of the class constructor.
On to the Characters
The code to generate the characters is split between two methods. The first, GenerateCode, generates the code, while the second, DrawCharacters, writes it to the image.
function GenerateCode() {
// reset code
$this->sCode = '';
// loop through and generate the code letter by letter
for ($i = 0; $i < $this->iNumChars; $i++) {
// select random character and add to code string
$this->sCode .= chr(rand(65, 90));
}
}
The GenerateCode method starts by clearing the $this->sCode variable, to prevent any saved characters that were generated previously from confusing our current image generation work.
Then, the method loops until it has selected the number of random characters requested in the class constructor. On each iteration of the loop, it appends the selected character to the $this->sCode variable.
Upper case characters are picked from ASCII character codes in the range 65 to 90. We use the rand function to select a number within this range, then pass it to the chr function to convert it into a readable character for display.
I've stuck to upper case characters because their ASCII codes are a continuous set of numbers; this makes it easier to pick a character at random. Including lower case characters or numbers would add an extra level of complexity to the character selection process. However, if you wanted to take this step, you could statically declare an array of characters to use, then choose a random number to act as an array index for character selection. The following code illustrates this point:
// characters to use
$aChars = array('A', 'B', 'C', '3', 'g');
// get number of characters
$iTotal = count($aChars) - 1;
// get random index
$iIndex = rand(0, $iTotal);
// selected character
$this->sCode .= $aChars[$iIndex];
This code would replace the following line in the GenerateCode method:
// select random character
$this->sCode .= chr(rand(65, 90));
Having generated this code, we call DrawCharacters to write the selected characters to the image.
function DrawCharacters() {
// loop through and write out selected number of characters
for ($i = 0; $i < strlen($this->sCode); $i++) {
// select random font
$iCurrentFont = rand(1, 5);
// select random greyscale colour
$iRandColour = rand(0, 128);
$iTextColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
// write text to image
imagestring($this->oImage, $iCurrentFont, $this->iSpacing / 3 + $i * $this->iSpacing, ($this->iHeight - imagefontheight($iCurrentFont)) / 2, $this->sCode[$i], $iTextColour);
}
}
With each iteration of the loop, the DrawCharacters method selects a random font from the five built into the GD library. They're simply numbered 1 to 5. We could have used FreeType or TrueType fonts, but this would have meant that, for this example to work, we'd have to worry about the locations of the required font files. I'll leave adding support for those fonts as an exercise for you!
In the next section, a random grey scale from an RGB range of 0 to 128 is selected. As previously mentioned, this is darker than the range we used two draw the background lines, ensuring that our image displays enough contrast to maintain its readability. You may want to tinker with these ranges to obtain what you feel is the best trade-off between obscurity and readability.
Finally, the character is written to the image. You'll notice that we're treating the $this->sCode string as an array, which enables us to select each character in turn.
The three methods we've created so far -- DrawLines, GenerateCode and DrawCharacters -- are private. Any code that calls the class won't use them directly, but, instead, uses them through a public wrapper method. In PHP 4, there's no way to mark a method as private, so we'll just have to hope that anyone who calls the class is well-behaved and uses the wrapper function we've provided.
Source:
http://www.sitepoint.com/artic...rity-image