Designing a Captcha System with PHP and MySQL

Spam is one of the biggest problems on the Internet. It is getting harder to fight with the advent of spam bots that visit websites and automatically fetch email addresses, fill out forms and do other nasty things, such as blog spam comments, that could degrade your integrity. Fortunately, using captcha can help. This article will show you how to implement captcha on your site.

Spam is a really serious problem. If you fail to correct this issue with your website or blog, spammers and possibly malicious hackers will take over your domain. The following things can happen:

  • If spam is uncontrolled, it can hurt the good visitors to your site. A classic example of this is when a spammer puts a link on your site that points to a malware-infected site, in the hope that visitors might click that link – which in turn will infect the good visitor’s computer.

  • Your reputation will be affected. If you let those spammers make comments on your site, it will cause others to wonder how serious you are about presenting great content.

  • Spammers and malicious types could hack your site, for example using a MySQL injection.

     

There are basically two ways you can generate captcha using PHP. One uses PHP alone; the other can be done using a MySQL database.

This tutorial is intended for an independent web developer needing protection from spam using captcha.

PHP Captcha generation: Basic Principles

Without using a database, one can generate captcha using PHP with GD support enabled. PHP needs GD support to be enabled to perform image processing tasks, such as the generation of captcha images. You can, however, check to see if the GD support was enabled in your Apache server by uploading a script with the phpinfo() function on the root directory, such as the one below:

<?php

echo phpinfo();

?>

Then open it in the browser. For example, if your domain is http://www.domainname.com , then all information about the PHP you are using will be available by typing:

http://www.domainname.com/phpinfo.php

Go to the GD support portion of the PHPinfo results. Yous should see something like the screen shot below:

If you do not have GD support enabled, contact your web hosting agency and ask them to turn it on. If this is not possible, you will need to generate captcha and store images using MySQL, which will not use GD support. This will be discussed in the last part of the tutorial.

Please take this piece of security advice: Remove the phpinfo.php in your server after getting this information. Letting the public access your phpinfo.php poses a security risk.

Suppose you have GD support enabled, which should be true in all cases. You can use the following strategy to generate captcha:

  1. You need a separate PHP file containing the script that will solely generate the captcha images. This file will be stored in the local server in the same path as the PHP form script.

  2. You will be calling this PHP script file in the form. When it is called, the captcha images will be displayed on the form. 

  3. Using PHP sessions you can store the generated string to a session variable, which will then be compared with the actual answer by the query. 

 

The form can only be processed if the captcha has been entered correctly. Only humans have the ability to get text information from images; this is what separates bots from humans.

{mospagebreak title=The Captcha Image Generation Script}

For simplicity of this illustration, we will use random numbers and convert them to images to be used as captcha. Then we will use session and other GD components to generate images. Below is the PHP script, which we call captxt.php

<?php

//start session which will be used to store generated numbers of validation in the form

session_start();

//generate random number between 10,000 and 99999

$number =mt_rand(10000, 99999);

//store generate random number to a session

$_SESSION['answer']=$number;

//create image 50 x 50 pixels

$imagecreate = imagecreate(50, 50);

// white background and blue text

$background = imagecolorallocate($imagecreate, 255, 255, 255);

$textcolor = imagecolorallocate($imagecreate, 0, 0, 255);

// write the string at the top left

imagestring($imagecreate, 5, 5, 10, $number, $textcolor);

// output the image

header("Content-type: image/png");

$image= imagepng($imagecreate);

?>

Let’s discuss the process for you to improve this design:

1. session_start(); is required in the first line of every PHP script if we want to store variables in the session. Storing variables in the session makes it available for use in other files that also use the session. This will be used to test whether the generated random number matches the one typed in by the user.

2. $number =mt_rand(10000, 99999); will generate random numbers in the range of 10,000 to 99,999 and store them the $number variable.

3. $_SESSION['answer']=$number; will store the generated random number to a session array so that it can be used in the PHP form script that will test if the user’s answer matches the generated code.

4. And finally this piece code:

//create image 50 x 50 pixels

$imagecreate = imagecreate(50, 50);

// white background and blue text

$background = imagecolorallocate($imagecreate, 255, 255, 255);

$textcolor = imagecolorallocate($imagecreate, 0, 0, 255);

// write the string at the top left

imagestring($imagecreate, 5, 5, 10, $number, $textcolor);

// output the image

header("Content-type: image/png");

$image= imagepng($imagecreate);

The function creates a space 50 x 50 pixel square, using a white background and blue text. This is purely customizable; for the sake of simplicity we do not include complex backgrounds, as you have seen in some captcha systems.

{mospagebreak title=The PHP Form with Captcha-Generated Challenge}

After we have completely designed the captcha system, we are ready to incorporate it into our web form. Below is a sample web form using the captcha script, with the file name captxt.php

<?php

session_start();

if (!$_POST['submit'])

{

//form not submitted, display form

?>

<form action="<?php echo $SERVER['PHP_SELF']; ?>"

method="post">

Complete name:

<br />

<input type="text" name="name" size="50">

<br />

<img src="captxt.php" />

<br />

Type the security code above:

<br /> <br />

<input type="text" name="captcha" size="10">

<input type="submit" name="submit" value="Submit">

</form>

<?php

}

else

{

//form submitted

if (!isset($_POST['name']) || trim($_POST['name']) == "")

{

die (‘ERROR: Enter name’);

}

else

{

if (!($_POST['captcha']==$_SESSION['answer']))

{

die (‘ERROR: Enter the correct security code.Click here for <a href="http://localhost/captchatest.php">another captcha test</a>’);

}

}

$name =$_POST['name'];

$captcha =$_POST['captcha'];

echo ‘Your name is ‘.’<b>’.$name.’</b>’;

echo ‘<br />’;

echo ‘Congratulations!!! You have correctly answered the security code which is ‘.’<b>’.$_SESSION['answer'].’</b>’;

echo ‘<br />’;

echo ‘<br />’;

echo ‘<h1><b>This means you are human and not a BOT</b></h1>’;

echo ‘<br />’;

echo ‘Click here for <a href="http://localhost/captchatest.php">another captcha test</a>’;

}

?>

Now I will provide you with a detailed explanation. 

One of the important things to note in the form script is the following:

<?php

session_start();

if (!$_POST['submit'])

Without session_start(); you can’t evaluate whether the captcha entered by the user is correct. As stated earlier, it should be placed in the first line of any PHP script using sessions.

Also, take a look at this part of the code:

<img src="captxt.php" />

<br />

Type the security code above:

<br /> <br />

<input type="text" name="captcha" size="10">

The image SRC tag will display the captcha generated from captxt.php

To test and evaluate whether the captcha entered is correct, see this code snippet:

if (!($_POST['captcha']==$_SESSION['answer']))

{

die (‘ERROR: Enter the correct security code.Click here for <a href="http://localhost/captchatest.php">another captcha test</a>’);

When the IF statement is true, the captcha is not entered correctly, thus displaying the error. Note that $_SESSION['answer'] contains the $number variable from the captcha script.

To implement this, save captxt.php and form.php in the same path; for example, the root directory of your web server.

{mospagebreak title=Captcha System Without GD Support}

Without GD support, things will be slightly more complicated but certainly not impossible. The following is a realistic strategy you can implement to create captcha images without GD support:

1. Create captcha in your local computer using your favorite photo editor. You can even make it very challenging as long as it is still readable at your desired image size.

2. Upload all the images to your FTP server specifying a clear path such as:

/captchapath/1.bmp

3. Make a MYSQL table called “captcha” containing three fields:

  • Number
  • Image path
  • Answer

Suppose you have 20 captcha images saved to your server. You should have a PHP script that will generate a random number from 1 to 20, and then fetch the image path corresponding to that number in the MySQL database.

Typically you can have a script like this:

<?php

//connect database

$username = "xxx";

$password = "xxx";

$hostname = "xxx";

$database = "xxx";

$dbhandle = mysql_connect($hostname, $username, $password)

or die("Unable to connect to MySQL");

//select a database to work with

$selected = mysql_select_db($database,$dbhandle)

or die("Could not select $database");

echo ‘Valid Email <br />’;

echo ‘<input type="text" name="rty" size="50">’;

echo ‘<br /><br />’;

echo ‘Enter captcha (Case sensitive for security measure) <br />’;

echo ‘<input type="text" name="cvd" size="50">’;

echo ‘<br /><br />’;

//generate captcha

$random= rand(1,12);

$random = mysql_real_escape_string(stripslashes($random));

$result2 = mysql_query("SELECT `imagepath` FROM `captcha` WHERE `number`=’$random’")

or die(mysql_error());

$row = mysql_fetch_array($result2)

or die("Invalid query: " . mysql_error());

$captcha = $row['imagepath'];

echo ‘<img src="’.$captcha.’"/>’;

echo ‘<br /><br /><input type="submit" /></form>’;

$random = mysql_real_escape_string(stripslashes($random));

//extract answer of captcha

$result3 = mysql_query("SELECT `answer` FROM `captcha` WHERE `number`=’$random’")

or die(mysql_error());

$row = mysql_fetch_array($result3)

or die("Invalid query: " . mysql_error());

$answer = $row['answer'];

//store answer to a session variable

$_SESSION['captchaanswer']=$answer;

?>

That concludes this tutorial. I hope you found it helpful. 

Google+ Comments

Google+ Comments