This a simple PHP Captcha Class useful to prevent automatic submissions of your forms. It’s very simple to implement and it uses the GD library to generate the image with the security code. Here’s the full class code (I will explain you how it works below):
<?php
class Captcha {
// Number of characters
public $chars_number = 4;
// Numbers (1), Letters (2), Letters & Numbers (3)
public $string_type = 3;
// Font Size
public $font_size = 5;
// Border Color (optional)
public $border_color = '239, 239, 239';
// Path to TrueType Font
public $tt_font = 'arial.ttf';
/* Show Captcha Image */
public function show_image($width = 88, $height = 31)
{
if(isSet($this->tt_font))
{
if(!file_exists($this->tt_font)) exit('The path to the true type font is incorrect.');
}
if($this->chars_number < 3) exit('The captcha code must have at least 3 characters.');
$string = $this->generate_string();
$im = ImageCreate($width, $height);
/* Set a White & Transparent Background Color */
$bg = ImageColorAllocateAlpha($im, 255, 255, 255, 127); // (PHP 4 >= 4.3.2, PHP 5)
ImageFill($im, 0, 0, $bg);
/* Border Color */
if($this->border_color)
{
list($red, $green, $blue) = explode(',', $this->border_color);
$border = ImageColorAllocate($im, $red, $green, $blue);
ImageRectangle($im, 0, 0, $width - 1, $height - 1, $border);
}
$textcolor = ImageColorAllocate($im, 191, 120, 120);
$y = 24;
for($i = 0; $i < $this->chars_number; $i++)
{
$char = $string[$i];
$factor = 15;
$x = ($factor * ($i + 1)) - 6;
$angle = rand(1, 15);
imagettftext($im, $this->font_size, $angle, $x, $y, $textcolor, $this->tt_font, $char);
}
$_SESSION['security_code'] = md5($string);
/* Output the verification image */
header("Content-type: image/png");
ImagePNG($im);
exit;
}
private function generate_string()
{
if($this->string_type == 1) // letters
{
$array = range('A','Z');
}
else if($this->string_type == 2) // numbers
{
$array = range(1,9);
}
else // letters & numbers
{
$x = ceil($this->chars_number / 2);
$array_one = array_rand(array_flip(range('A','Z')), $x);
if($x <= 2) $x = $x - 1;
$array_two = array_rand(array_flip(range(1,9)), $this->chars_number - $x);
$array = array_merge($array_one, $array_two);
}
$rand_keys = array_rand($array, $this->chars_number);
$string = '';
foreach($rand_keys as $key)
{
$string .= $array[$key];
}
return $string;
}
}
?>
How is this class working?
The function which generates the Captcha is show_image(string $width, string $height). First it checks if the path to the true type font is correct. If it isn’t the script will close after an error message will be shown:
if(isSet($this->tt_font))
{
if(!file_exists($this->tt_font)) exit('The path to the true type font is incorrect.');
}
The security code should have at least 3 characters:
if($this->chars_number < 3) exit('The captcha code must have at least 3 characters');
Further on, the security code will be generated by calling the generate_string() function:
$string = $this->generate_string();
How does this function work?
The value of $string_type is analyzed. Based on the chosen type (letters, numbers, letters & numbers) an array will be generated. Afterwards, we will use array_rand() to create a second array with random keys selected from the first array:
$rand_keys = array_rand($array, $this->chars_number);
What's next? Loop through the recently created array to generate the security code:
$string = '';
foreach($rand_keys as $key)
{
$string .= $array[$key];
}
After the string is generated we can move on with the creation of the image. The first function used is ImageCreate() to create a new palette based image with the specified size.
resource imagecreate ( int $width, int $height )
$im = ImageCreate($width, $height);
Set a white & transparent background for the recently created image:
/* Set a White & Transparent Background Color */ $bg = ImageColorAllocateAlpha($im, 255, 255, 255, 127); // (PHP 4 >= 4.3.2, PHP 5) ImageFill($im, 0, 0, $bg);
Add the border with the specified color (default is grey):
/* Border Color */
if($this->border_color)
{
list($red, $green, $blue) = explode(',', $this->border_color);
$border = ImageColorAllocate($im, $red, $green, $blue);
ImageRectangle($im, 0, 0, $width - 1, $height - 1, $border);
}
Allocate a color for the text:
$textcolor = ImageColorAllocate($im, 191, 120, 120);
Write the text to the image using imagettftext() by calculating the right coordinates:
$y = 24;
for($i = 0; $i < $this->chars_number; $i++)
{
$char = $string[$i];
$factor = 15;
$x = ($factor * ($i + 1)) - 6;
$angle = rand(1, 15);
imagettftext($im, $this->font_size, $angle, $x, $y, $textcolor, $this->tt_font, $char);
}
Now, we need to register the session for the generated string. For security reasons we will use md5() to register a 32 characters hash of the code.
$_SESSION['security_code'] = md5($string);
Finally, output the image and exit:
/* Output the verification image */
header("Content-type: image/png");
ImagePNG($im);
exit;
How can I implement this Captcha with the refresh feature?
This class can be called from a HTML file. Here's the code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Captcha Verification Image</title>
<script type="text/javascript">
<!--
function new_captcha()
{
var c_currentTime = new Date();
var c_miliseconds = c_currentTime.getTime();
document.getElementById('captcha').src = 'image.php?x='+ c_miliseconds;
}
-->
</script>
</head>
<body onload="new_captcha();">
<form action="check.php" method="post">
<table>
<tr>
<td> </td>
<td><img id="captcha" src="image.php" alt="">
<a href="JavaScript: new_captcha();">
<img border="0" alt="" src="refresh.png" align="bottom"></a></td>
</tr>
<tr>
<td>Security Code:</td>
<td><input type="text" name="security_code" value="">
<input type="submit" name="submit" value="Check"></td>
</tr>
</table>
</form>
</body>
</html>
How is the Captcha refreshed?
As you can notice the image has the id attribute equal with 'captcha' and the SRC equal with 'image.php'. Everytime the refresh icon is clicked the JavaScript new_captcha() function is called setting an unique SRC for the image. This way the user will not access a recently cached version of the captcha and the image.php will re-load. The variable 'c_milliseconds' is unique every time the user accesses the page that calls the captcha and contains the number of milliseconds since midnight of January 1, 1970.
function new_captcha()
{
var c_currentTime = new Date();
var c_milliseconds = c_currentTime.getTime();
document.getElementById('captcha').src = 'image.php?x='+ c_milliseconds;
}
The new_captcha() is triggered in every page re-load:
<body onload="new_captcha();">
This way, a new image is generated and the previously shown image is not cached even if the user uses the browser's BACK button to return to the page with the captcha.
In image.php we will call the class that will output the captcha:
include_once 'common.php'; include_once 'class.captcha.php'; $captcha = new Captcha(); $captcha->chars_number = 5; $captcha->font_size = 14; $captcha->tt_font = 'verdana.ttf'; $captcha->show_image();
In common.php, the session is started and the right headers are sent:
<?php
session_start();
header('Cache-control: private'); // IE 6 FIX
// always modified
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
// HTTP/1.1
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
// HTTP/1.0
header('Pragma: no-cache');
?>

How will the submitted code be checked?
In check.php, we will verify if the security code was submitted. If so, we will remove any whitespace from the beginning and ending of the script using the trim() function. Then, we will encrypt it using md5(). The returned hash is compared to the value of the registered session 'security_code'. If it's a match then the correct code was submitted. If it isn't, an error message will be shown:
<?php
include_once 'common.php';
if(isSet($_POST['security_code']))
{
$security_code = trim($_POST['security_code']);
$to_check = md5($security_code);
if($to_check == $_SESSION['security_code'])
{
echo "The security code is <font color='green'>correct</font>.";
}
else
{
echo "The security code is <font color='red'>incorrect</font>.";
}
}
?>
Do you want to increase / decrease the number of characters and also the size of the Captcha Image? Here are some examples of how you can do that:
1) Use an image with 4 characters and a smaller size (70 x 30)
<?php include_once 'common.php'; include_once 'class.captcha.php'; $captcha = new Captcha(); $captcha->chars_number = 4; $captcha->font_size = 14; $captcha->tt_font = 'verdana.ttf'; $captcha->show_image(70, 30); ?>

2) Use an image with 8 characters and a bigger size (120 x 30)
<?php include_once 'common.php'; include_once 'class.captcha.php'; $captcha = new Captcha(); $captcha->chars_number = 8; $captcha->font_size = 14; $captcha->tt_font = 'verdana.ttf'; $captcha->show_image(132, 30); ?>

If you have any questions regarding this class, please ask! Happy coding!
- Requirements: PHP 5+, GD Library Enabled, FreeType Library Enabled
- Pricing: Free


- February 10, 2009
- article by Gabriel C.
- 25 comments
Related Posts
-
How to Create a PHP AutoLogin (‘Remember Me’) Feature using Cookiesat November 25, 2008 with 29 comments
-
PHP: How to center a text on an image using GDat September 9, 2008 with 10 comments
-
PHP: How to Add Transparency to an Image using GDat October 13, 2008 with 6 comments
-
PHP: Check (validate) if the Uploaded File is an Imageat September 24, 2008 with 21 comments
-
Basic Usage of the JS onChange() Event Handlerat November 11, 2008

Comment via Facebook
25 Replies to "Basic PHP Captcha (Image Verification) with Refresh Feature"
February 28, 2009 at 4:00 AM
Great article. thanx for ur sharing.
March 28, 2009 at 9:00 AM
Very nice!!
April 1, 2009 at 5:13 PM
Wow! thanks man!
great job!
April 1, 2009 at 6:16 PM
The downloaded file not run well,
it asks me a check.php file :(
What mistakes done there?
April 1, 2009 at 6:41 PM
# // Numbers (1), Letters (2), Letters & Numbers (3)
# public $string_type = 3;
This line works vice-versa…
That is if i choose 1 it displays letters, and if i choose 2 it displays numbers and 3 is working fine!
thanks mate i love this
May 9, 2009 at 4:38 PM
Download the code, it DOES NOT work as demo
May 9, 2009 at 5:13 PM
The solution is the check.php should be like this:
if( isset($_POST['submit']))
{
if( $_SESSION['security_code'] == md5($_POST['security_code']) && !empty($_SESSION['security_code'] ) )
{
July 7, 2010 at 1:19 AM
thx. it coollll…
July 16, 2009 at 4:29 PM
great article. very helpful. working perfectly.
thanks for this post dear.
August 5, 2009 at 7:33 AM
Hi. First forgive me, my English is bad
I have 2 problems.
The refresh of CAPTCHA not working (“in the file form.html”). I don’t know where this error, because when you click “refresh link” it does not update the CAPTCHA.
And finally when you click submit, validation does not occur and the script returns the mensage exist in the recomenda_ERRO.html file.
I usualled the original file check and now I´m testing the solution sended for ABUT.
Please help me!!!
This Code I adapted and I´m testing. But don´t work.
<?
include_once '../capcode/common.php';
$hoje_tmp = getdate();
$hoje = ($hoje_tmp[hours].":".$hoje_tmp[minutes].":".$hoje_tmp[seconds]."hs");
$remetente_nome = $_POST["remetente_nome"]; //trata a variável – Nome
$remetente_mail = $_POST["remetente_mail"]; //trata a variável – E-mail
$destinatario_nome = $_POST["destinatario_nome"]; //trata a variável – Destinatário
$destinatario_mail = $_POST["destinatario_mail"]; //trata a variável – E-mail do destinatário
$mensagem = $_POST["mensagem"]; //trata a variável – Mensagem
global $email; //transforma em variavel global a variável e-mail
if( isset($_POST['submit']))
{
if( $_SESSION['security_code'] == md5($_POST['security_code']) && !empty($_SESSION['security_code'] ) )
{
$enviou = mail("$destinatario_mail", "$remetente_nome esta recomendando nosso site",
"Olá, $destinatario_nome.
$remetente_nome, visitou o endereço http://www.site.com e achou que você iria gostar de conhecer também.
Mensagem escrita por $remetente_nome:
$mensagem
______________________________________________________________________________
Mensagem enviada via formulário on-line as $hoje
"From: $remetente_nome “, “Bcc: contato@site.com“);
if ($enviou)
{
Header(“Location: recomenda_ok.html”);
}
else
{
Header(“Location: recomenda_erro.html”);
}
}
else
{
Header(“Location: recomenda_erro.html”);
}
}
?>
FORM.HTML
Formulário de envio
Seu nome:
Seu e-mail:
Destinatário(a):
Destinatário(a) e-mail:
Mensagem:
Digite o código de Validação:
ATENÇÃO! Todos os campos são obrigatórios.
August 7, 2009 at 9:45 PM
@Rodrigo, can you show me where you have added the form and the captcha? Send me the URL so I can check them.
November 3, 2009 at 10:47 PM
Captcha images are not displaying why..?check the demo also!
December 8, 2009 at 9:33 PM
The captcha image can be seen now ;-)
February 4, 2010 at 8:32 AM
Thank you very much for publishing this lesson. The code as well as the tutorial seem to be very thorough. The code works right out of the box so thanks for that. I’ll definitely will visit your site often.
March 8, 2010 at 6:55 PM
great work man ,well done
March 14, 2010 at 7:05 PM
thank you verry much,good job!
but when i change the dimension and the number of character the image will not appear..
Why?
April 12, 2010 at 2:05 AM
I have a little problem!
I’ve tried this code and it works properly on my localhost, but if i upload to a server the security image is not shown at all! I tried it on another server and it was almost the same problem, the image was created there but the code was not shown! How could i solve this, and whats the problem?? I tried to change path as well, but didnt work! :(
Thank you very much in advance!
May 25, 2010 at 2:35 AM
I found that PHP version 5.2.13 has two different FreeType versions installed. Running local (Apache) everything works fine with FreeType version 2.39, but on my server (CGI) I find I have FreeType version 2.37 and it will NOT load the image.
Any tip what to do next ?
April 20, 2010 at 4:21 AM
Hi dear,
it is working well in IE but in Mozilla captcha image is not coming.
wheres the error…?
May 7, 2010 at 3:31 AM
Great Tutorial. However for those who don’t have the GdLibs installed you can use ImageMagick – See here http://www.thephpanswers.com/viewtopic.php?f=11&t=3 it wouldnt take long to add the refresh feature :)
August 2, 2010 at 12:01 AM
I m Download the code, it DOES NOT work as demo
March 25, 2011 at 9:57 PM
the download file didn’t work…
Can you look againnn…
March 25, 2011 at 10:05 PM
Also here my captcha:
http://www.misha-tattoo.de/content/general/captcha/index.html
und
http://www.misha-tattoo.de/content/general/captcha/image.php
i have error…
my email:
info@wiyono.de
March 25, 2011 at 10:16 PM
It looks like the CAPTCHA font can’t be read from its location. Make sure you put the right path to the TrueType Font.
March 30, 2011 at 12:49 AM
Thanks for your refresh feature!