Let’s create a simple captcha plugin using nothing else just PHP script. First generate a 5 digit random number between 10000 and 99999; call it $randNum
.
1 2 |
// Generate a random 5 digit number (Captcha) $randNum = rand(10000, 99999); |
The random number can be saved into the server’s session for later use, e.g to match the user’s input and the saved value for validation.
The
session_start();
must be launched before the usage of the session.
1 2 |
// Copy Captcha into session $_SESSION['captcha'] = $randNum; |
Drawing with PHP
Before starting to draw with PHP, the base needs to be created with the specified sizes.
1 2 |
// Create image instance (width, height) $imgInst = imagecreatetruecolor(57, 27); |
This will create a black image with the width of 57 pixels and height 27 pixels. Having black background with black numbers will make it impossible to read the captcha’s value. Therefore colors are allocated to them.
1 2 3 4 5 |
// Color of the text string (RGB) $txtColor = imagecolorallocate($imgInst, 100, 100, 100); // Color of the background (RGB) $bkgColor = imagecolorallocate($imgInst, 240, 240, 240); |
The colors are composed with the RGB color model. For the text I picked a middle gray (R 100, G 100, B 100) color and the background is a bright grey (R 240, G240 B240), nearly white.
Once the colors are defined, they can be added to the image. Starting with the background, the PHP function will “flood fill” the image instance with the given starting coordinates (top, left).
1 2 |
// Flood fill the image instance starting with x, y position with the background color imagefill($imgInst, 0, 0, $bkgColor); |
Now we have an image with a bright gray background. The following line will draw the captcha string (random number).
1 2 |
// Add string (captcha) to the image instance (image, font, x, y, string, color) imagestring($imgInst, 5, 6, 6, $randNum, $txtColor); |
The $imgInst
must be the return value of imagecreatetruecolor()
which was created earlier. The font size is 5, the maximum of the built-in fonts in ‘latin2’ encoding. X and Y coordinates are 6, their starting point is the upper left corner. The Y-coordinate is inverted, therefore its positive value is pointing downwards and visa versa. The $randNum
is the previously generated random number, the string which is written using the defined color of $txtColor
.
The captcha image instance is created but it’s too easy to read. Let’s draw some diagonal lines over the existing picture with the same text color.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Draw diagonal lines (image, x1, y1, x2, y2, color) imageline($imgInst, 0, 20, 7, 27, $txtColor); imageline($imgInst, 0, 10, 17, 27, $txtColor); imageline($imgInst, 0, 0, 27, 27, $txtColor); imageline($imgInst, 10, 0, 37, 27, $txtColor); imageline($imgInst, 20, 0, 47, 27, $txtColor); imageline($imgInst, 30, 0, 57, 27, $txtColor); imageline($imgInst, 40, 0, 67, 27, $txtColor); imageline($imgInst, 50, 0, 77, 27, $txtColor); imageline($imgInst, 0, 10, 10, 0, $txtColor); imageline($imgInst, 0, 20, 20, 0, $txtColor); imageline($imgInst, 0, 30, 30, 0, $txtColor); imageline($imgInst, 0, 40, 40, 0, $txtColor); imageline($imgInst, 0, 50, 50, 0, $txtColor); imageline($imgInst, 0, 60, 60, 0, $txtColor); imageline($imgInst, 0, 70, 70, 0, $txtColor); imageline($imgInst, 0, 80, 80, 0, $txtColor); |
In total there are 16 diagonal lines are drawn over the image. X1 and Y1 are the starting coordinates and X2 and Y2 are the end points of the line.
Output The Image Instance
The captcha’s image instance is now ready to be displayed.There are two ways to do it.
1. Turn PHP script into a PNG image file
The PHP script file can be used as an image source pasted in just like a JPEG or a PNG file. Doing it, the HTTP header needs to be declared.
1 2 3 |
// Set the client's HTTP header header("Cache-Control: no-cache, must-revalidate"); header('Content-type: image/png'); |
It is important to turn of the caching otherwise it is likely that the browser saves the image and will display the same after every reload. The content type must be specified as well.
The final step using this method is to output the image to the browser the destroy the instance.
1 2 3 4 5 |
// Output the image instance as PNG on the screen imagepng($imgInst); // Destroy image instance imagedestroy($imgInst); |
So how to display the image? Just simply use the PHP file as the image source.
1 |
<img src="gellai-captcha.php" /> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
<?php /* * Simple PHP Captcha Plugin * ------------------------- * * gellai.com 2017 * * Just simply include this file as the image source. * <img src="gellai-captcha.php" /> * */ /* * * Get the first 3 digits of the current PHP Version (eg 5.6) * */ $phpVersion = substr(phpversion(), 0, 3); /* * * Check PHP Version and check if the session is already started. * If not then start it. * */ if($phpVersion > 5.4) { if(session_status() == PHP_SESSION_NONE) { session_start(); } } else { if(session_id() == '') { session_start(); } } // Generate a random 5 digit number (Captcha) $randNum = rand(10000, 99999); // Copy Captcha into session $_SESSION['captcha'] = $randNum; // Create image instance (width, height) $imgInst = imagecreatetruecolor(57, 27); // Color of the text string $txtColor = imagecolorallocate($imgInst, 100, 100, 100); // Color of the background (RGB) $bkgColor = imagecolorallocate($imgInst, 240, 240, 240); // Flood fill the image instance starting with x, y position with the background colour imagefill($imgInst, 0, 0, $bkgColor); // Add string (captcha) to the image instance (image, font, x, y, string, colour) imagestring($imgInst, 5, 6, 6, $randNum, $txtColor); // Draw diagonal lines (image, x1, y1, x2, y2, colour) imageline($imgInst, 0, 20, 7, 27, $txtColor); imageline($imgInst, 0, 10, 17, 27, $txtColor); imageline($imgInst, 0, 0, 27, 27, $txtColor); imageline($imgInst, 10, 0, 37, 27, $txtColor); imageline($imgInst, 20, 0, 47, 27, $txtColor); imageline($imgInst, 30, 0, 57, 27, $txtColor); imageline($imgInst, 40, 0, 67, 27, $txtColor); imageline($imgInst, 50, 0, 77, 27, $txtColor); imageline($imgInst, 0, 10, 10, 0, $txtColor); imageline($imgInst, 0, 20, 20, 0, $txtColor); imageline($imgInst, 0, 30, 30, 0, $txtColor); imageline($imgInst, 0, 40, 40, 0, $txtColor); imageline($imgInst, 0, 50, 50, 0, $txtColor); imageline($imgInst, 0, 60, 60, 0, $txtColor); imageline($imgInst, 0, 70, 70, 0, $txtColor); imageline($imgInst, 0, 80, 80, 0, $txtColor); // Set the client's HTTP header header("Cache-Control: no-cache, must-revalidate"); header('Content-type: image/png'); // Output the image instance as PNG on the screen imagepng($imgInst); // Destroy image instance imagedestroy($imgInst); ?> |
2. Output as Base64 source
Sometimes the first method is not functional due to the server’s security or its settings. To get around it, the output of the image instance is put into the buffer, the content of the buffer is encoded into Base64 and added to a variable.
Start with turning on the output buffering.
1 2 |
// Start buffering the output ob_start(); |
Add the instance to the buffer.
1 2 |
// Output image instance as PNG to buffer imagepng($imgInst, null, 0, PNG_NO_FILTER); |
Read out the content of the buffer, encode its content to Base64 and add to a variable.
1 2 |
// Get buffer and convert image to base64 $b64Img = base64_encode(ob_get_contents()); |
Destroy the image instance and clean up the buffer.
1 2 3 4 5 |
// Destroy instance imagedestroy($imgInst); // Empty buffer ob_end_clean(); |
The $b64Img
variable contains the Base64 encoded raw image. This can be displayed with the following methods.
1 |
echo '<img src="data:image/png;base64,' . $b64Img . '" />'; |
…or…
1 |
<img src="data:image/png;base64,<?php echo $b64Img; ?>" /> |
The complete PHP source code for the Base64 encoded mode:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
<?php /* * Simple PHP Captcha Plugin * ------------------------- * * gellai.com 2017 * * On the top of the page include the source PHP file. * * Example: * include_once('gellai_captcha.php'); * * Then just simply include $b64Img variable as the image source. * <img src="data:image/png;base64,<?php echo $b64Img; ?>" /> * */ /* * * Get the first 3 digits of the current PHP Version (eg 5.6) * */ $phpVersion = substr(phpversion(), 0, 3); /* * * Check PHP Version and check if the session is already started. * If not then start it. * */ if($phpVersion > 5.4) { if(session_status() == PHP_SESSION_NONE) { session_start(); } } else { if(session_id() == '') { session_start(); } } // Generate a random 5 digit number (Captcha) $randNum = rand(10000, 99999); // Copy Captcha into session $_SESSION['captcha'] = $randNum; // Create image instance (width, height) $imgInst = imagecreatetruecolor(57, 27); // Color of the text string $txtColor = imagecolorallocate($imgInst, 100, 100, 100); // Color of the background (RGB) $bkgColor = imagecolorallocate($imgInst, 240, 240, 240); // Flood fill the image instance starting with x, y position with the background colour imagefill($imgInst, 0, 0, $bkgColor); // Add string (captcha) to the image instance (image, font, x, y, string, colour) imagestring($imgInst, 5, 6, 6, $randNum, $txtColor); // Draw diagonal lines (image, x1, y1, x2, y2, colour) imageline($imgInst, 0, 20, 7, 27, $txtColor); imageline($imgInst, 0, 10, 17, 27, $txtColor); imageline($imgInst, 0, 0, 27, 27, $txtColor); imageline($imgInst, 10, 0, 37, 27, $txtColor); imageline($imgInst, 20, 0, 47, 27, $txtColor); imageline($imgInst, 30, 0, 57, 27, $txtColor); imageline($imgInst, 40, 0, 67, 27, $txtColor); imageline($imgInst, 50, 0, 77, 27, $txtColor); imageline($imgInst, 0, 10, 10, 0, $txtColor); imageline($imgInst, 0, 20, 20, 0, $txtColor); imageline($imgInst, 0, 30, 30, 0, $txtColor); imageline($imgInst, 0, 40, 40, 0, $txtColor); imageline($imgInst, 0, 50, 50, 0, $txtColor); imageline($imgInst, 0, 60, 60, 0, $txtColor); imageline($imgInst, 0, 70, 70, 0, $txtColor); imageline($imgInst, 0, 80, 80, 0, $txtColor); // Start buffering the output ob_start(); // Output image instance as PNG to buffer imagepng($imgInst, null, 0, PNG_NO_FILTER); // Get buffer and convert image to base64 $b64Img = base64_encode(ob_get_contents()); // Destroy instance imagedestroy($imgInst); // Empty buffer ob_end_clean(); ?> |
Update
I have updated this project by adding some extra features to it.
Extra features:
- Selecting between raw and base64 mode
- Setting the length of the generated random number within a range of 1-20
- Rendering types: png, jpeg, gif
- Custom colour of the random number
- Custom background colour
- Custom colour of the radial lines
How does it work? To find out more please visit this project’s repository on