cft

Create A Simple Image Captcha using PHP

Using imagecreate() and imageccolorallocate() you can create a simple Captcha with PHP. You would need to hash the captcha's token and store in a Session.


user

Simon Ugorji

2 years ago | 12 min read

I recently created a custom image captcha using PHP, and I will show you how you can too.

OUR FILE STRUCTURE

  • Let's start with the core folder.

We will create two files. One of them will generate the captcha image for us and the other will enable us to verify the generated captcha

Captcha_image.php

We need to generate our captcha text, hash it with md5(), then store the hashed value in a session for verification.

In our function, you may specify how many characters the user gets to fill out.

//Start session
session_start();

//Generate random captcha text
function generateRandomString($length = 10) {
/*
* @length: The length of the Captcha Text
*/
$characters = 'a0bcde1fghi2jklm3nopq4rstu5vwx6yzA7BCDE8FGHIJ9KLMN3OPQRS2TUVW1XYZ0';
$charactersLength = strlen($characters);

$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}

//we need 5 characters max
$captcha_txt = generateRandomString(5);

Now, there's an interesting something I did with this script.

We will generate an image using PHP, create an array that will store the random background colors of the generated image, then we will pick a random color from the array.

//Start session
session_start();

//Generate random captcha text
function generateRandomString($length = 10) {
/*
* @length: The length of the Captcha Text
*/
$characters = 'a0bcde1fghi2jklm3nopq4rstu5vwx6yzA7BCDE8FGHIJ9KLMN3OPQRS2TUVW1XYZ0';
$charactersLength = strlen($characters);

$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}

//we need 5 characters max
$captcha_txt = generateRandomString(5);

//generate image with a width of 200px and height of 20px
$image = imagecreate(200, 20);

//random background image
$a=array(
"red"=>[255, 0, 0],
"green"=>[0, 155, 6],
"blue"=>[0, 0, 255],
"black"=>[0,0,0]
);
//pick random color from the array
$color_index= (array_rand($a,1));

Now we will use the function imagecolorallocate() to allocate the background color of our image, keeping in mind our array indexes.

//Start session
session_start();

//Generate random captcha text
function generateRandomString($length = 10) {
/*
* @length: The length of the Captcha Text
*/
$characters = 'a0bcde1fghi2jklm3nopq4rstu5vwx6yzA7BCDE8FGHIJ9KLMN3OPQRS2TUVW1XYZ0';
$charactersLength = strlen($characters);

$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}

//we need 5 characters max
$captcha_txt = generateRandomString(5);

//generate image with a width of 200px and height of 20px
$image = imagecreate(200, 20);

//random background image
$a=array(
"red"=>[255, 0, 0],
"green"=>[0, 155, 6],
"blue"=>[0, 0, 255],
"black"=>[0,0,0]
);

//pick random color from the array
$color_index= (array_rand($a,1));

//allocate background color with indexes from variable $color_index
$bk_clr = imagecolorallocate($image, $a[$color_index][0], $a[$color_index][1], $a[$color_index][2]);
//Final image color, set the text color to white
$img_clr = imagecolorallocate($image, 255, 255, 255); //this will include the background color and the text color

Now we need to draw our image string using the function imagestring().

We will pass in the parameters;

  • $image - the generated image
  • 5 - Inbuilt font selection
  • 50 - the x coordinate of the upper left corner
  • 0 - the y coordinate of the upper left corner ( we need it to be centered )
  • $captcha_txt - the captcha text challenge
  • $img_clr - the captcha image color

//Start session
session_start();

//Generate random captcha text
function generateRandomString($length = 10) {
/*
* @length: The length of the Captcha Text
*/
$characters = 'a0bcde1fghi2jklm3nopq4rstu5vwx6yzA7BCDE8FGHIJ9KLMN3OPQRS2TUVW1XYZ0';
$charactersLength = strlen($characters);

$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}

//we need 5 characters max
$captcha_txt = generateRandomString(5);

//generate image with a width of 200px and height of 20px
$image = imagecreate(200, 20);

//random background image
$a=array(
"red"=>[255, 0, 0],
"green"=>[0, 155, 6],
"blue"=>[0, 0, 255],
"black"=>[0,0,0]
);

//pick random color from the array
$color_index= (array_rand($a,1));

//allocate background color with indexes from variable $color_index
$bk_clr = imagecolorallocate($image, $a[$color_index][0], $a[$color_index][1], $a[$color_index][2]);
//Final image color, set the text color to white
$img_clr = imagecolorallocate($image, 255, 255, 255); //this will include the background color and the text color

//Draw the image
imagestring($image, 5, 50, 0, $captcha_txt, $img_clr);

Now, we need to set up an expiry time for the captcha text, hash the expiry time with the captcha text, then store it in a session variable.

//Start session
session_start();

//Generate random captcha text
function generateRandomString($length = 10) {
/*
* @length: The length of the Captcha Text
*/
$characters = 'a0bcde1fghi2jklm3nopq4rstu5vwx6yzA7BCDE8FGHIJ9KLMN3OPQRS2TUVW1XYZ0';
$charactersLength = strlen($characters);

$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}

//we need 5 characters max
$captcha_txt = generateRandomString(5);

//generate image with a width of 200px and height of 20px
$image = imagecreate(200, 20);

//random background image
$a=array(
"red"=>[255, 0, 0],
"green"=>[0, 155, 6],
"blue"=>[0, 0, 255],
"black"=>[0,0,0]
);

//pick random color from the array
$color_index= (array_rand($a,1));

//allocate background color with indexes from variable $color_index
$bk_clr = imagecolorallocate($image, $a[$color_index][0], $a[$color_index][1], $a[$color_index][2]);
//Final image color, set the text color to white
$img_clr = imagecolorallocate($image, 255, 255, 255); //this will include the background color and the text color

//Draw the image
imagestring($image, 5, 50, 0, $captcha_txt, $img_clr);

//Expiry time of 3 minutes
$expire = gmdate(strtotime('+3 minutes', time()));
//concatenate the expiry time with the captcha text
$tmp_hash = $captcha_txt.$expire;

$_SESSION['captcha_set'] = TRUE; //makes sure that the captcha your'e verifying is set
$_SESSION['captcha_token'] = md5($tmp_hash); //hash the captcha
$_SESSION['captcha_expire'] = $expire; //expiry time

Lastly, we need to convert the image string we had generated using imagestring() to a png image, then free any memory related to the image by destroying our image.

//Start session
session_start();

//Generate random captcha text
function generateRandomString($length = 10) {
/*
* @length: The length of the Captcha Text
*/
$characters = 'a0bcde1fghi2jklm3nopq4rstu5vwx6yzA7BCDE8FGHIJ9KLMN3OPQRS2TUVW1XYZ0';
$charactersLength = strlen($characters);

$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}

//we need 5 characters max
$captcha_txt = generateRandomString(5);

//generate image with a width of 200px and height of 20px
$image = imagecreate(200, 20);

//random background image
$a=array(
"red"=>[255, 0, 0],
"green"=>[0, 155, 6],
"blue"=>[0, 0, 255],
"black"=>[0,0,0]
);

//pick random color from the array
$color_index= (array_rand($a,1));

//allocate background color with indexes from variable $color_index
$bk_clr = imagecolorallocate($image, $a[$color_index][0], $a[$color_index][1], $a[$color_index][2]);
//Final image color, set the text color to white
$img_clr = imagecolorallocate($image, 255, 255, 255); //this will include the background color and the text color

//Draw the image
imagestring($image, 5, 50, 0, $captcha_txt, $img_clr);

//Expiry time of 3 minutes
$expire = gmdate(strtotime('+3 minutes', time()));
//concatenate the expiry time with the captcha text
$tmp_hash = $captcha_txt.$expire;

$_SESSION['captcha_set'] = TRUE; //makes sure that the captcha your'e verifying is set
$_SESSION['captcha_token'] = md5($tmp_hash); //hash the captcha
$_SESSION['captcha_expire'] = $expire; //expiry time

//convert the image string to a png
imagepng($image);
//Free memory
imagedestroy($image);

At this point, we are done with captcha_image file.

Let's save the file now, and create a new one to verify our captcha.

Captcha_verify.php

We will declare a function that will accept just one parameter which is the user input, then set status codes as our return value.

//start session
session_start();

function verifyCaptcha($input = "abc") {
/**
* verifyCaptcha : This function verifies the validity of Captcha Images
* @input : The user input
* @return : 407 (captcha expired), 200 (captcha verified), 400 (captcha unverified), 500 (Server Error)
**/
}

STEP 1

Check if the 3 session variables exist, then assign their values to our local variables.

//start session
session_start();

function verifyCaptcha($input = "abc") {
/**
* verifyCaptcha : This function verifies the validity of Captcha Images
* @input : The user input
* @return : 407 (captcha expired), 200 (captcha verified), 400 (captcha unverified), 500 (Server Error)
**/

$date = time();
if(isset($_SESSION['captcha_set']) &&
isset($_SESSION['captcha_token']) &&
isset($_SESSION['captcha_expire'])) {
//assign values
$captcha_expire = $_SESSION['captcha_expire'] ;
$captcha_token = $_SESSION['captcha_token'];
}else{
$return = array(
"captcha_status" => 500,
"captcha_message" => "Session Invalid!",
);
return json_encode($return);
}
}

STEP 2

  • We will check if the captcha is still valid ( ie it hasn't expired ).
  • Rehash the user input md5($input.$captcha_expire).
  • Then compare it with the one from our session.

If it matches, we will return a status code of 200 which means that our captcha verification was successful. But if it doesn't match, we will return a status code of 400.

//start session
session_start();

function verifyCaptcha($input = "abc") {
/**
* verifyCaptcha : This function verifies the validity of Captcha Images
* @input : The user input
* @return : 407 (captcha expired), 200 (captcha verified), 400 (captcha unverified), 500 (Server Error)
**/

$date = time();
if($_SESSION['captcha_set'] &&
isset($_SESSION['captcha_token']) &&
isset($_SESSION['captcha_expire'])) {
//assign values
$captcha_expire = $_SESSION['captcha_expire'] ;
$captcha_token = $_SESSION['captcha_token'];
//check if captcha has expired
if($date < $_SESSION['captcha_expire']){
if(md5($input.$captcha_expire) == $captcha_token){
unset( $_SESSION['captcha_expire'] );
unset( $_SESSION['captcha_token']);
unset($_SESSION['captcha_set']);
$return = array(
"captcha_status" => 200,
"captcha_message" => "Captcha Verified!",
);
return json_encode($return);
} else {
$return = array(
"captcha_status" => 400,
"captcha_message" => "Captcha Verification Failed!",
);
return json_encode($return);
}

}else{
$return = array(
"captcha_status" => 407,
"captcha_message" => "Captcha Expired!",
);
return json_encode($return);
}
}else{
$return = array(
"captcha_status" => 500,
"captcha_message" => "Session Invalid!",
);
return json_encode($return);
}
}

Now save the file and create an index page where we will display our captcha to the user

Index.php

Here are the things we will do

  • We will create an image tag and set the src to core/captcha_image.php.
  • We will create a form for the user to fill in the text from the image they see.
  • We will process the form input as soon as the user hits the submit button, then show the result of our verification to the user

<?php
//require the verification file
require_once 'core/captcha_verify.php';

if(isset($_POST)&& isset($_POST['submit'])){
//call the function by binding it to a variable
$verify_captcha = json_decode(verifyCaptcha($_POST['captcha']), true);

if ($verify_captcha['captcha_status'] == 200) {
//If captcha verification is Successful
echo '<script>
document.addEventListener(\'DOMContentLoaded\', (event) => {
alert("'.$verify_captcha['captcha_message'].'");
})</script>';
} else {
//If Unsuccessful
echo '<script>
document.addEventListener(\'DOMContentLoaded\', (event) => {
alert("'.$verify_captcha['captcha_message'].'");
})</script>';
}
}
?>
<html>

<div id="captcha_img_house" style="text-align:center;margin-bottom:10px">
<img id="captcha_img" src="core/captcha_image.php">
</div>

<form method="post" style="style="text-align: center;">
<label id="captcha_form_label">Enter the Text You See</label>
<br>
<input id="captcha_key" name="captcha">
<button id="btn_captcha_submit" type="submit" name="submit">Verify</button>
</form>

</html>

Now, let's test our script.

Now I will provide two different inputs and purposely leave the captcha unattended for 4 minutes so I will show you how the function works.

  • The Captcha Challenge



  • Failed Challenge



  • Successful challenge



  • Expired Challenge



ASSETS FOLDER

I have shown you the basic functions that we need. However, you may expand your captcha script to automatically switch images, in case the user can't see through the current image.

You may also define some styling for your captcha.

Visit my GitHub Repo to see how I customized and styled mine.

Here are the status codes you should be aware of.

//Output 1
$return = [
'captcha_status' => 200,
'captcha_message' => 'Captcha Verified'
];

//Output 2
$return = [
'captcha_status' => 400,
'captcha_message' => 'Captcha Verification failed'
];

//Output 3
$return = [
'captcha_status' => 407,
'captcha_message' => 'Captcha Expired'
];

//Output 4
$return = [
'captcha_status' => 500,
'captcha_message' => 'Session Invalid'
];

You may visit a live preview of this script Here.

Let me know if there's anything related to this script I can help you out with!

Thank You!

Upvote


user
Created by

Simon Ugorji

Backend Developer | PHP | JS


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles