Security Images in PHP

Learn how to create a sign-up form for a website with a security image. The image prevents fake sign-ups and spam. In this tutorial, we will learn how to create a security image template, then put it to use.


Support files can be found here.


Introduction

Computers have such amazing power today that they are able to behave almost like humans. Programs can be written to interact with many websites. Unfortunately, many of these interactions are ones we don’t want, including fake sign-ups, spam through contact forms, and stealing places in line for items such as tickets.

The best way to avoid this is to include confirmations only real humans can comprehend. One of the most popular methods of doing this is through Security Images. In a nutshell, security images are dynamically generated images containing text that is hidden within other graphics. The characters must be entered correctly in a confirmation field to continue. In this tutorial, we will learn how to create a security image template, then put it to use.

Prerequisites:

  • Basic PHP skills
  • Basic GD Graphics Library knowledge (not required, but helpful)
  • Basic MySQL/PHP integration skills
  • PHP with GD graphics library (included with PHP 4.3.x)
  • MySQL database
  • Included files – securityimage_finished.php, signupdemo_finished.php, bg1.png, bg2.png, bg3.png

Preparation

Before beginning, you will need to create a database table in your MySQL database. Use the following SQL to do so:

CREATE TABLE `security_images` (
   `ID` int(11) NOT NULL auto_increment,
   `insertdate` datetime NOT NULL default ‘0000-00-00 00:00:00′,
   `referenceid` varchar(100) NOT NULL default ”,
   `hiddentext` varchar(100) NOT NULL default ”,
   PRIMARY KEY (`ID`)
) TYPE=MyISAM;

Laying Down a Plan

I believe the best first step is to create a plan. First of all, we will have a signup form, signupdemo.php. In the form, we will have a security image, a hidden field containing the unique reference ID to this image, and a confirmation field. The image will be called from another PHP page, securityimage.php.

When the security image is requested, the unique reference ID will be passed in the url as refid (i.e. securityimage.php?refid=abcdefg123hij). This page will generate a random string of a set length and output an image containing the text. Next, the reference ID and the hidden text value will be entered into the MySQL database table, security_images. Finally, any records older than one day will be deleted from the table.

When the user submits the signup form, the handler script will collect the hidden reference ID, and the entered hidden text. Then, it will check these two values against the database. If the query doesn’t return 0 records, the signup is valid. Otherwise, it is invalid, and the user will have to re-enter the security image text.

{mospagebreak title=Getting Started — Securityimage.php}

The first page to create is the page which will generate the security images, securityimage.php. First, we need to open the PHP block and determine if we can use refid in the querystring; otherwise, we generate a unique one ourselves.

<?php
//Generate Reference ID
if (isset($HTTP_GET_VARS["refid"]) && $HTTP_GET_VARS["refid"]!=””) {
   $referenceid = stripslashes($HTTP_GET_VARS["refid"]);
} else {
   $referenceid = md5(mktime()*rand());
}

Now, we must select a font to use. For this demo, we will use Century, because it is easy to distinguish between zeroes and o’s, and because it is a serif font, it is harder for a computer to comprehend. You will need to set the path to the font, reflecting what OS you are using and where the fonts folder is.

//Select Font
$font = “C:WINDOWSFontsCentury.ttf”;

Next, we will randomly select one of the three backgrounds (from the included files). Using one of these files, we initialize a new image identifier $im, representing the background image, using ImageCreateFromPNG. If you want more variety, you can create more backgrounds (must be PNG format).

//Select random background image
$bgurl = rand(1, 3);
$im = ImageCreateFromPNG(“images/bg”.$bgurl.”.png”);

After this, we will generate a random string. To do this, we first create an array of characters to use. Then, we specify a length for the text to be generated. For this demonstration, we will use 8, but you can change it to any length you wish. Finally, we create an empty variable, then randomly fill it with characters in a loop.

//Generate the random string
$chars = array(“a”,”A”,”b”,”B”,”c”,”C”,”d”,”D”,”e”,”E”,”f”,”F”,”g”,”G”,
“h”,”H”,”i”,”I”,”j”,”J”,”k”,
“K”,”l”,”L”,”m”,”M”,”n”,”N”,”o”,”O”,”p”,”P”,”q”,”Q”,”r”,
“R”,”s”,”S”,”t”,”T”,”u”,”U”,”v”,
“V”,”w”,”W”,”x”,”X”,”y”,”Y”,”z”,”Z”,”1″,”2″,”3″,”4″,”5″,
“6”,”7″,”8″,”9″);
$length = 8;
$textstr = “”;
for ($i=0; $i<$length; $i++) {
   $textstr .= $chars[rand(0, count($chars)-1)];
}

{mospagebreak title=Set Other Text Variables}

Next, we set other text variables. To do so, we first create a random font size between 12 and 16 points. Then, we create a random angle. Even though angles should only be positive values, the GD Library is smart enough to correct it (-5° to 355° for example). A random dark color to be used with the image is then created.

//Create random size, angle, and dark color
$size = rand(12, 16);
$angle = rand(-5, 5);
$color = ImageColorAllocate($im, rand(0, 100), rand(0, 100), rand(0, 100));

We will be preparing the text position next. To do this, we will use imagettfbbox to return the dimensions of the true type text box using the already defined size, angle, font, and textstr variables. After that, we determine the absolute difference between 1- lower right corner x position and the lower left corner x position (the width), and 2- the upper right corner y position and the lower right corner y position (height). If you’re scratching your head, consider the following diagram:

Security Images in PHP

Then, using the imagesx (width) & imagesy (height) properties of the image we created earlier, we generate an x and a y position. Note that we add a random number between -20 and 20 to the x position, so that it is a little to the left or right of center.

//Determine text size, and use dimensions to generate x & y coordinates
$textsize = imagettfbbox($size, $angle, $font, $textstr);
$twidth = abs($textsize[2]-$textsize[0]);
$theight = abs($textsize[5]-$textsize[3]);
$x = (imagesx($im)/2)-($twidth/2)+(rand(-20, 20));
$y = (imagesy($im))-($theight/2);

We’re finally ready to add the text to the image using all of the variables we have just created. Now, let’s go over the variables:

$im represents the original image reference
$size represents the font size
$angle represents the angle the text is to be tilted at
$x represents the x coordinate to place the text at
$y represents the y coordinate to place the text at
$color represents the random color you just created
$font represents the reference to the ttf font file
$textstr represents the text to be inserted

//Add text to image
ImageTTFText($im, $size, $angle, $x, $y, $color, $font, $textstr);

Now that we’ve prepared our image, we’re finally ready to output it. So, we first set the Content-Type header to be a PNG image. Then, we simply write the image content in PNG format using ImagePNG.

//Output PNG Image
header(“Content-Type: image/png”);
ImagePNG($im);

Deleting the image is very important, because it frees the server memory. This ensures optimal performance from the server. To do so, we use the imagedelete function, passing our image reference $im to it.

//Destroy the image to free memory
imagedestroy($im);

The next step is to enter the random text, $textstr, and the reference ID, $referenceid, into the MySQL database, using the table we created earlier. Be sure you enter your username and password in the connection function. To insert the text, we first connect to the server. Then, we insert the current date and time, reference ID, and the hidden text value. After this, we delete the references older than one day, to prevent them from stacking up and wasting space.

//Insert reference into database, and delete any old ones
mysql_connect(“localhost”, “username”, “password”) or die(mysql_error());
mysql_select_db(“dw_php”);
//Create reference
mysql_query(“INSERT INTO security_images (insertdate, referenceid, hiddentext) VALUES (
now(), ‘”.$referenceid.”‘, ‘”.$textstr.”‘)”);
//Delete references older than 1 day
mysql_query(“DELETE FROM security_images
WHERE insertdate < date_sub(now(), interval 1 day)”);

Finally, we end the output by using exit and close the PHP block.

//End Output
exit;

?>

{mospagebreak title=Code for securityimage.php}

The complete code listing for securityimage.php should now look like this:

<?php
//Generate Reference ID
if (isset($HTTP_GET_VARS["refid"]) && $HTTP_GET_VARS["refid"]!=””) {
   $referenceid = stripslashes($HTTP_GET_VARS["refid"]);
} else {
   $referenceid = md5(mktime()*rand());
}

//Select Font
$font = “C:WINDOWSFontsCentury.ttf”;

//Select random background image
$bgurl = rand(1, 3);
$im = ImageCreateFromPNG(“images/bg”.$bgurl.”.png”);

//Generate the random string
$chars = array(“a”,”A”,”b”,”B”,”c”,”C”,”d”,”D”,”e”,”E”,”f”,”F”,”g”,
“G”,”h”,”H”,”i”,”I”,”j”,”J”,”k”,
“K”,”l”,”L”,”m”,”M”,”n”,”N”,”o”,”O”,”p”,”P”,”q”,”Q”,
“r”,”R”,”s”,”S”,”t”,”T”,”u”,”U”,”v”,
“V”,”w”,”W”,”x”,”X”,”y”,”Y”,”z”,”Z”,”1″,”2″,”3″,”4″,
“5”,”6″,”7″,”8″,”9″);
$length = 8;
$textstr = “”;
for ($i=0; $i<$length; $i++) {
   $textstr .= $chars[rand(0, count($chars)-1)];
}

//Create random size, angle, and dark color
$size = rand(12, 16);
$angle = rand(-5, 5);
$color = ImageColorAllocate($im, rand(0, 100), rand(0, 100), rand(0, 100));

//Determine text size, and use dimensions to generate x & y coordinates
$textsize = imagettfbbox($size, $angle, $font, $textstr);
$twidth = abs($textsize[2]-$textsize[0]);
$theight = abs($textsize[5]-$textsize[3]);
$x = (imagesx($im)/2)-($twidth/2)+(rand(-20, 20));
$y = (imagesy($im))-($theight/2);

//Add text to image
ImageTTFText($im, $size, $angle, $x, $y, $color, $font, $textstr);

//Output PNG Image
header(“Content-Type: image/png”);
ImagePNG($im);

//Destroy the image to free memory
imagedestroy($im);

//Insert reference into database, and delete any old ones
mysql_connect(“localhost”, “username”, “password”) or die(mysql_error());
mysql_select_db(“dw_php”);
//Create reference
mysql_query(“INSERT INTO security_images (insertdate, referenceid, hiddentext) VALUES (
now(), ‘”.$referenceid.”‘, ‘”.$textstr.”‘)”);
//Delete references older than 1 day
mysql_query(“DELETE FROM security_images
WHERE insertdate < date_sub(now(), interval 1 day)”);

//End Output
exit;

?>

Open securityimage.php in a browser. You should see something like the image below:

Security Images in PHP

Now, we are finished with the file and ready to put it to use!

Note: If you receive a message about ImageCreateFromPNG being an undefined function, this is probably because you don’t have the GD Graphics Library installed. Install this (download may be obtained from http://www.boutell.com/gd/) and retry.

{mospagebreak title=Creating the Sign-up Demo — Signupdemo.php}

Now we are ready to create the sign-up demo. To begin, start with the following PHP file:

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″>
<title>Signup Demo</title>
</head>
<body>

</body>
</html>

Now, we need to create two functions in a PHP block at the top of the file — insertSecurityImage, a function to insert a unique security image, and checkSecurityImage, a function to check the user entered value.

In this function, we have one parameter, $inputname. We first of all create a unique reference ID by hashing the current UTC time times a random number. Then, we generate a string that will insert an image with the reference ID passed in the querystring. It also inserts a hidden input named whatever was passed in $inputname, and a value of the reference ID. Finally, we write it to the browser.

<?php
//Define function to insert security image
function insertSecurityImage($inputname) {
   $refid = md5(mktime()*rand());
   $insertstr = “<img src=”securityimage.php?refid=”.$refid.”” alt=”Security Image”>n
   <input type=”hidden” name=””.$inputname.”” value=””.$refid.””>”;
   echo($insertstr);
}

In checkSecurityImage, we have two parameters — the reference ID ($referenceid), and the value the user entered ($enteredvalue). First, we prepare the two strings by escaping them for database use. Then, we select the record(s) containing the reference ID and the hiddentext that were passed to the function. Finally, we return true (indicating valid) if there are more than zero records, and otherwise return false (indicating invalid) if there are zero records. You must have already opened a MySQL connection to use this function.

//Define function to check security image confirmation
function checkSecurityImage($referenceid, $enteredvalue) {
   $referenceid = mysql_escape_string($referenceid);
   $enteredvalue = mysql_escape_string($enteredvalue);
   $tempQuery = mysql_query(“SELECT ID FROM security_images WHERE
   referenceid='”.$referenceid.”‘ AND hiddentext='”.$enteredvalue.”‘”);
   if (mysql_num_rows($tempQuery)!=0) {
      return true;
   } else {
      return false;
   }
}
?>

Now, we are ready to create the signup form within the <body> tags. The form will post to itself. Because this is a demonstration, we will only have one field (name) in addition to the security image. Then, we simply call the insertSecurityImage function, specifying the hidden form field name to be security_refid. Finally we add a confirmation field named security_try, and a submit button.

<form name=”signupform” method=”post” action=”<?=$_SERVER["PHP_SELF"]?>”>
Please sign up for our website:
<br>
<br>
Name:
<input name=”name” type=”text” id=”name”>
<br>
<? insertSecurityImage(“security_refid”) ?>
<br>
Enter what you see:
<input name=”security_try” type=”text” id=”security_try” size=”20″ maxlength=”10″>
(can’t see? try reloading page)
<br>
<br>
<input type=”submit” name=”Submit” value=”Signup!”>
</form>

Open signupdemo.php in a browser. If you view the source, you should see something like the code listing below. Note the hidden field and the security image reference ID.

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″>
<title>Signup Demo</title>
</head>
<body>
<form name=”signupform” method=”post” action=”/php/signupdemo.php”>
Please sign up for our website:<br>
<br>
Name:
<input name=”name” type=”text” id=”name”>
<br>
<img src=”securityimage.php?refid=0ed393101d240092186f47c3dc80c84e” alt=”Security Image”>
<input type=”hidden” name=”security_refid” value=”0ed393101d240092186f47c3dc80c84e”> <br>
Enter what you see:
<input name=”security_try” type=”text” id=”security_try” size=”20″ maxlength=”10″>
(can’t see? try reloading page)
<br>
<br>
<input type=”submit” name=”Submit” value=”Signup!”>
</form>
</body>
</html>

{mospagebreak title=Form Handler Script}

We are now ready to write the form handler script. We will be adding another PHP block just above the <form> tag. First of all, we connect to the MySQL database. Be sure to enter your username and password. Then, we check to see if the security_refid and security_try fields are defined. If so, we define $security_refid and $security_try based on the form values. After that, we call checkSecurityImage using the reference ID and the value the user entered. Based on the value returned, we tell the user if they entered the correct code or not.

<?php
if (isset($HTTP_POST_VARS["name"]) && isset($HTTP_POST_VARS["security_try"])) {
   //Connect to database
   mysql_connect(“localhost”, “username”, “password”);
   mysql_select_db(“dw_php”);
   //Set variables, and call checkSecurityImage
   $security_refid = $HTTP_POST_VARS["security_refid"];
   $security_try = $HTTP_POST_VARS["security_try"];
   $checkSecurity = checkSecurityImage($security_refid, $security_try);
   //Depending on result, tell user entered value was correct or incorrect
   if ($checkSecurity) {
      $validnot = “correct”;
   } else {
      $validnot = “incorrect”;
   }
   //Write output
   echo(“<b>You entered this as the security text:</b><br>n
   “.$security_try.”<br>n
   This is “.$validnot.”.<br>n
   ——————————-<br><br>n
   “);
}
?>

The complete code listing for signupdemo.php should now look like this:

<?php
//Define function to insert security image
function insertSecurityImage($inputname) {
   $refid = md5(mktime()*rand());
   $insertstr = “<img src=”securityimage.php?refid=”.$refid.”” alt=”Security Image”>n
   <input type=”hidden” name=””.$inputname.”” value=””.$refid.””>”;
   echo($insertstr);
}

//Define function to check security image confirmation
function checkSecurityImage($referenceid, $enteredvalue) {
   $referenceid = mysql_escape_string($referenceid);
   $enteredvalue = mysql_escape_string($enteredvalue);
   $tempQuery = mysql_query(“SELECT ID FROM security_images WHERE
   referenceid='”.$referenceid.”‘ AND hiddentext='”.$enteredvalue.”‘”);
   if (mysql_num_rows($tempQuery)!=0) {
      return true;
   } else {
      return false;
   }
}
?>

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd“>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″>
<title>Signup Demo</title>
</head>
<body>

<?php
if (isset($HTTP_POST_VARS["name"]) && isset($HTTP_POST_VARS["security_try"])) {
   //Connect to database
   mysql_connect(“localhost”, “username”, “password”);
   mysql_select_db(“dw_php”);
   //Set variables, and call checkSecurityImage
   $security_refid = $HTTP_POST_VARS["security_refid"];
   $security_try = $HTTP_POST_VARS["security_try"];
   $checkSecurity = checkSecurityImage($security_refid, $security_try);
   //Depending on result, tell user entered value was correct or incorrect
   if ($checkSecurity) {
      $validnot = “correct”;
   } else {
      $validnot = “incorrect”;
   }
   //Write output
   echo(“<b>You entered this as the security text:</b><br>n
   “.$security_try.”<br>n
   This is “.$validnot.”.<br>n
   ——————————-<br><br>n
   “);
}
?>

<form name=”signupform” method=”post” action=”<?=$_SERVER["PHP_SELF"]?>”>
Please sign up for our website:
<br>
<br>
Name:
<input name=”name” type=”text” id=”name”>
<br>
<? insertSecurityImage(“security_refid”) ?>
<br>
Enter what you see:
<input name=”security_try” type=”text” id=”security_try” size=”20″ maxlength=”10″>
(can’t see? try reloading page)
<br>
<br>
<input type=”submit” name=”Submit” value=”Signup!”>

</body>
</html>

Preview signupdemo.php in a browser. You should see something like this:

Security Images in PHP


If you enter the text correctly, you should see something like this:

Security Images in PHP

Note: if you receive a MySQL error, ensure that you replaced “username” and “password” with the real values.

Summary and Conclusion

In this article we have learned how to use the GD Graphics Library, creating an easy solution to prevent computers from behaving like humans. We also wrote basic functions, allowing us to reuse the Security Image file in other applications.

Until next time, happy coding :-)

[gp-comments width="770" linklove="off" ]

chat