Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / Apache

CAPTCHA Image in PHP

4.94/5 (21 votes)
23 Feb 2009GPL31 min read 1   4K  
This article demonstrates how we can create a CAPTCHA image with PHP
CAPTCHA.png

Introduction

CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) image is a way to prevent from bot attacks to our website's forms.
This article demonstrates how we can create our own CAPTCHA.

Using the Code

At first, we have to create a new true color image.
We can create it with imagecreatetruecolor [^] function in PHP.

$image = imagecreatetruecolor($this -> winWidth, 
	$this -> winHeight) //Create a new true color image
	or die("<b>" . __FILE__ . "</b><br />" . __LINE__ . " : " 
    ."Cannot Initialize new GD image stream");
$bg = imagecolorallocate($image, 255, 255, 255);//Allocate a color for an image
imagefill($image, 10, 10, $bg);//Flood fill
.
.
.
return imagepng($image);//Outputs or saves a PNG image from the given $image
imagedestroy($image);//rees any memory associated with image $image

This image is too simple, so we can change the background with a simple algorithm:

private $Colors =  array (	'0' => '145',
                    '1' => '204',
                    '2' => '177',
                    '3' => '184',
                    '4' => '199',
                    '5' => '255');
.
.
.
for ($x=0; $x < $this -> winWidth; $x++)
{
    for ($y=0; $y < $this -> winHeight; $y++)
    {
        $random = mt_rand(0 , 5);
        $temp_color = imagecolorallocate($image, 
        	$this -> Colors["$random"], 
        	$this -> Colors["$random"], $this -> Colors["$random"]);
        imagesetpixel( $image, $x, $y , $temp_color );
    }
}

The result of the above code:

BG1.png

Then we should write the characters in our image:

//e.g $this->Characters is the string that we're writing in the image
//Font
$font = "tahomabd.ttf";
$font_size = 33;
//\\
$char = $this -> Characters[0];
$random_x = mt_rand(10 , 20);
$random_y = mt_rand(35 , 45);
$random_angle = mt_rand(-20 , 20);
//Writes the given text  into the image using TrueType fonts. 
imagettftext($image, $font_size, $random_angle, $random_x, $random_y, 
	$char_color, $font, $char);

We repeat it to fill our image with characters.
The result is as follows:

CAPTCHA-2.png

But I guess it is a little plain yet, so we can add an effect to our image for creating a more complex CAPTCHA.
I've added a wave effect with a pure mathematic algorithm:

private $applyWave = true;
.
.
.
private function apply_wave($image, $width, $height)
{		
    $x_period = 10;
    $y_period = 10;
    $y_amplitude = 5;
    $x_amplitude = 5;
    
    $xp = $x_period*rand(1,3);
    $k = rand(0,100);
    for ($a = 0; $a<$width; $a++)
        imagecopy($image, $image, $a-1, sin($k+$a/$xp)*$x_amplitude, 
        	$a, 0, 1, $height);
        
    $yp = $y_period*rand(1,2);
    $k = rand(0,100);
    for ($a = 0; $a<$height; $a++)
        imagecopy($image, $image, sin($k+$a/$yp)*$y_amplitude, 
        	$a-1, 0, $a, $width, 1);
    
    return $image;
}

You can change the intensity of waves by changing these variables:

  • $x_period
  • $y_period
  • $y_amplitude
  • $x_amplitude

Let's see the result:

CAPTCHA.png

I've also added some lines to the image :

private $showLine = true;
.
.
.
//draws lines
if ($this -> showLine)
{
    for ($i=0; $i<$this->winWidth; $i++ )
    {
        if ($i%10 == 0)
        {
            imageline ( $image, $i, 0, 
            	$i+10, 50, $char_color );
            imageline ( $image, $i, 0, 
            	$i-10, 50, $char_color );
        }
    }
}

The latest result:

CAPTCHA-lines.png

That's all.
Good luck.

How To: Using Phpbb3 CAPTCHA
How to: Using PHP Fusion 7 CAPTCHA

Dayyan CAPTCHA Class

Source Code:

<?php
/*
Created by Mohammad Dayyan (C)- 1387/3/2
http://www.mds-soft.persianblog.ir/
*/

if ( !defined('MohammadDayyan') )
{
	die ("Hacking attempt <br /> <b>" . __FILE__ . 
    	"<br /> Line " .  __LINE__  . "</b>" );
	exit;
}

class DayyanConfirmImage
{
	private $showLine = true;
	private $applyWave = true;
	private $winHeight = 50;
	private $winWidth = 320;
	
	private $Characters; // random characters
	
	private $Colors =  array (	'0' => '145',
								'1' => '204',
								'2' => '177',
								'3' => '184',
								'4' => '199',
								'5' => '255');

////////////////////////////////////////////////////////////////////////////////
	public function __construct($ConfirmCode)
	{
		$this -> Characters = $ConfirmCode;
	}

////////////////////////////////////////////////////////////////////////////////
	public function ShowImage()
	{
		//detect server operation system
		if ( strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' )//windows detected
			$this -> win();
		else	//linux detected
			$this -> linux();
	}

////////////////////////////////////////////////////////////////////////////////
	private function win()
	{
		////////////////////////////////////
		//background image
		$image = imagecreatetruecolor($this -> winWidth, $this -> winHeight) 
        	or die("<b>" . __FILE__ . "</b><br />" . __LINE__ . " : 
            	" ."Cannot Initialize new GD image stream");
		$bg = imagecolorallocate($image, 255, 255, 255);
		imagefill($image, 10, 10, $bg);

		for ($x=0; $x < $this -> winWidth; $x++)
		{
			for ($y=0; $y < $this -> winHeight; $y++)
			{
				$random = mt_rand(0 , 5);
				$temp_color = imagecolorallocate($image, 
                	$this -> Colors["$random"], 
                	$this -> Colors["$random"], $this -> Colors["$random"]);
				imagesetpixel( $image, $x, $y , $temp_color );
			}
		}

		$char_color = imagecolorallocatealpha($image, 0, 0, 0, 90);

		//Font
		$font = "tahomabd.ttf";
		$font_size = 33;
		////////////////////////////////////
		//Image characters

		$char = "";

		$char = $this -> Characters[0];
		$random_x = mt_rand(10 , 20);
		$random_y = mt_rand(35 , 45);
		$random_angle = mt_rand(-20 , 20);
		imagettftext($image, $font_size, $random_angle, 
        	$random_x, $random_y, $char_color, $font, $char);

		$char = $this -> Characters[1];
		$random_x = mt_rand(50 , 70);
		$random_y = mt_rand(35 , 45);
		$random_angle = mt_rand(-20 , 20);
		imagettftext($image, $font_size, $random_angle, 
        	$random_x, $random_y, $char_color, $font, $char);

		$char = $this -> Characters[2];
		$random_x = mt_rand(100 , 120);
		$random_y = mt_rand(35 , 45);
		$random_angle = mt_rand(-20 , 20);
		imagettftext($image, $font_size, $random_angle, 
        	$random_x, $random_y, $char_color, $font, $char);

		$char = $this -> Characters[3];
		$random_x = mt_rand(150 , 170);
		$random_y = mt_rand(35 , 45);
		$random_angle = mt_rand(-20 , 20);
		imagettftext($image, $font_size, $random_angle, 
        	$random_x, $random_y, $char_color, $font, $char);

		$char = $this -> Characters[4];
		$random_x = mt_rand(200 , 220);
		$random_y = mt_rand(35 , 45);
		$random_angle = mt_rand(-20 , 20);
		imagettftext($image, $font_size, $random_angle, 
        	$random_x, $random_y, $char_color, $font, $char);

		$char = $this -> Characters[5];
		$random_x = mt_rand(250 , 270);
		$random_y = mt_rand(35 , 45);
		$random_angle = mt_rand(-20 , 20);
		imagettftext($image, $font_size, $random_angle, 
        	$random_x, $random_y, $char_color, $font, $char);

		////////////////////////////////////
		if ($this -> applyWave)
			$image = $this -> apply_wave($image, $this -> winWidth, 
            	$this -> winHeight);
			
		////////////////////////////////////
		//lines
		if ($this -> showLine)
		{
			for ($i=0; $i<$this->winWidth; $i++ )
			{
				if ($i%10 == 0)
				{
					imageline ( $image, $i, 0, 
                    	$i+10, 50, $char_color );
					imageline ( $image, $i, 0, 
                    	$i-10, 50, $char_color );
				}
			}
		}
			
		////////////////////////////////////
		return imagepng($image);
		imagedestroy($image);
	}

/////////////////////////////////////////////////////////////
	private function linux()
	{
		////////////////////////////////////
		//Background image
		$image = imagecreatetruecolor(150, 50) or 
        	die("<b>" . __FILE__ . "</b><br />" . __LINE__ . " : " 
            	."Cannot Initialize new GD image stream");
		$bg = imagecolorallocate($image, 255, 255, 255);
		imagefill($image, 10, 10, $bg);

		for ($x=0; $x < 150; $x++)
		{
			for ($y=0; $y < 50; $y++)
			{
				$random = mt_rand(0 , 5);
				$temp_color = imagecolorallocate($image, $this -> 
                	Colors["$random"], $this -> Colors["$random"], $this -> 
                    Colors["$random"]);
				imagesetpixel( $image, $x, $y , $temp_color );
			}
		}

		$char_color = imagecolorallocatealpha($image, 0, 0, 0, 60);

		////////////////////////////////////
		//Image Info
		$font = 5;

		////////////////////////////////////
		//Image characters
		$char = $this -> Characters[0];
		$random_x = mt_rand(10 , 20);
		$random_y = mt_rand(15,25);
		imagestring($image, $font, $random_x, $random_y, $char, $char_color);

		$char = $this -> Characters[1];
		$random_x = mt_rand(30 , 40);
		$random_y = mt_rand(15,25);
		imagestring($image, $font, $random_x, $random_y, $char, $char_color);

		$char = $this -> Characters[2];
		$random_x = mt_rand(50 , 60);
		$random_y = mt_rand(15,25);
		imagestring($image, $font, $random_x, $random_y, $char, $char_color);

		$char = $this -> Characters[3];
		$random_x = mt_rand(70 , 80);
		$random_y = mt_rand(15,25);
		imagestring($image, $font, $random_x, $random_y, $char, $char_color);

		$char = $this -> Characters[4];
		$random_x = mt_rand(90 , 100);
		$random_y = mt_rand(15,25);
		imagestring($image, $font, $random_x, $random_y, $char, $char_color);

		$char = $this -> Characters[5];
		$random_x = mt_rand(110 , 120);
		$random_y = mt_rand(15,25);
		imagestring($image, $font, $random_x, $random_y, $char, $char_color);

		///////////////////////
		return imagepng($image);
		imagedestroy($image);
	}

///////////////////////////////////////////////////////////
	private function apply_wave($image, $width, $height)
	{		
		$x_period = 10;
		$y_period = 10;
		$y_amplitude = 5;
		$x_amplitude = 5;
		
		$xp = $x_period*rand(1,3);
		$k = rand(0,100);
		for ($a = 0; $a<$width; $a++)
			imagecopy($image, $image, $a-1, sin($k+$a/$xp)*$x_amplitude, 
            	$a, 0, 1, $height);
			
		$yp = $y_period*rand(1,2);
		$k = rand(0,100);
		for ($a = 0; $a<$height; $a++)
			imagecopy($image, $image, sin($k+$a/$yp)*$y_amplitude, 
            	$a-1, 0, $a, $width, 1);
		
		return $image;
	}
}

?>

History

  • 3rd January, 2008: First post
  • 23rd February, 2009: Last update

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)