March 03, 2019
Generate CAPTCHA Image in PHP
gd php
CAPTCHA images are used to prevent automated form submission. In this post I am going to demonstrate how you can add an extra layer to your HTML forms using custom CAPTCHA images to prevent automated form submission.
So we will first create a php class captcha.php, which will contain the methods to create a captcha image, add random text to image, add noise to image and blur captcha image. image-captcha.php will be used to use methods from captcha class and will this file be used a source attribute for html image element. index.php will hold the html form and style.css will apply styling to form.
captcha.php
<?php class captcha{ private $image; private $color; public $width; public $height; function __construct($width = 120,$height = 60,$background = "#4F5B93",$color = "#ffffff"){ // Create captcha image, Set height & width, text color when object is initialized $this->image = imagecreatetruecolor($width, $height); $this->width = intval($width); $this->height = intval($height); $color = $this->decimal_color($color); // Get decimal color value from hex color value $this->color = $this->true_color($color); // Set true color from decimal color $background = $this->decimal_color($background); $background = $this->true_color($background); // Fill background color to image imagefill($this->image, 0, 0, $background); } /***************************************************************** | Function to add noise to captcha image ** @param : (hex) Noise color ******************************************************************/ public function captcha_noise($color = "#8892BF"){ $font_color = $this->decimal_color($color); $font_color = $this->true_color($font_color); // Loop x co-ordinates of image for($r = 0; $r < $this->width; $r++) { // Loop y co-ordinates of image for($c = 0; $c < $this->height; $c++) { // Add noise on step of 1 pixel, skipping one pixel and noise to next pixel if (mt_rand(0,1) == 1) imagesetpixel($this->image, $r, $c, $font_color); } } } /***************************************************************** | Function to blur captcha image * @param : (int) Number of times image should be blurred ******************************************************************/ public function captcha_blur($count = 3){ $count = intval($count) > 10 ? 10 : $count; for($i = 1; $i <= $count; $i++){ imagefilter($this->image, IMG_FILTER_GAUSSIAN_BLUR); } } /***************************************************************** | Function to return created captcha image ******************************************************************/ public function captcha_image(){ $this->captcha_text(); ob_start(); header("Content-Type: image/jpeg"); imagejpeg($this->image,NULL,100); $captcha = ob_get_clean(); imagedestroy($this->image); return $captcha; } /***************************************************************** | Function to blur captcha image * @param : (hex) Hexadecimal color value ******************************************************************/ private function decimal_color($color){ $color = strpos($color, "#") !== FALSE ? substr($color, 1) : $color; if(strlen($color) === 6){ $red = substr($color, 0,2); $green = substr($color, 2,2); $blue = substr($color, 4,2); }else{ $red = substr($color, 0,1).substr($color, 0,1); $green = substr($color, 1,1).substr($color, 1,1); $blue = substr($color, 2,1).substr($color, 1,1); } $red = hexdec($red); $green = hexdec($green); $blue = hexdec($blue); return ["red" => $red, "green" => $green, "blue" => $blue]; } /***************************************************************** | Function to convert decimal color to true color * @param : (array) Array of decimal color value for red,green,blue ******************************************************************/ private function true_color($color){ return imagecolorallocate($this->image, $color["red"], $color["green"], $color["blue"]); } /***************************************************************** | Function to generate random string for captcha * @param : (int)Length of characters ******************************************************************/ private function random_string($length){ $characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; $random_string = ""; for($i = 0; $i < $length; $i++){ $random_string .= $characters[mt_rand(0,strlen($characters) - 1)]; } return $random_string; } /***************************************************************** | Function to add random string to captcha image ******************************************************************/ private function captcha_text(){ $font_file = realpath(dirname(__FILE__)."/sketch_block.ttf"); $font_size = $this->height * 0.6; $font_color = $this->color; $random_string = $this->random_string(5); $ttf_box = imagettfbbox($font_size, 0, $font_file, $random_string); $xr = abs( max( $ttf_box[2], $ttf_box[4] ) ); $xy = abs( max( $ttf_box[5], $ttf_box[7] ) ); $x = ( $this->width - $xr ) / 2; $y = ( $this->height + $xy ) / 2; imagettftext($this->image, $font_size, 0, $x, $y, $font_color, $font_file, $random_string); $_SESSION["captcha"] = $random_string; } } ?>
captcha-image.php
<?php session_start(); include_once("captcha.php"); $captcha = new captcha(280,60); $captcha->captcha_noise(); // Add noise to captcha image $captcha->captcha_blur(); // Blur captcha image echo $captcha->captcha_image(); ?>
index.php
<?php session_start(); if(!empty($_POST)){ if($_POST['captcha'] === $_SESSION["captcha"]){ $success = 1; }else{ $success = 0; } $_SESSION["captcha_status"] = $success; header("Location: ".$_SERVER["REQUEST_URI"]); exit(); } ?> <!DOCTYPE html> <html> <head> <title>Generate Captcha Image in PHP - Demo</title> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <link rel="stylesheet" href="css/style.css" /> <script type="text/javascript"> function refresh_captcha(){ var random = Math.random(); document.querySelector(".captcha-image").src = "captcha-image.php?" + random; } </script> </head> <body> <div class="main-container"> <div class="section"> <div class="captcha-box"> <?php if(isset($_SESSION["captcha_status"])){ $success = $_SESSION["captcha_status"]; if($success){?> <div class="captcha-message">Captcha verified</div> <?php }else{?> <div class="captcha-message error">Captcha verification failed</div> <?php } unset($_SESSION["captcha_status"]); }?> <form name="captcha_form" method="POST"> <img class="captcha-image" src="captcha-image.php" /> <div><input type="text" name="captcha" class="form-control" /></div> <p>Can't read? Click <a href="javascript:refresh_captcha();">here</a> to refresh</p> <button type="submit" class="btn btn-green btn-block">Verify</button> </form> </div> </div> </div> </body> </html>
style.css
*{ box-sizing: border-box; } html,body{ margin: 0px; padding: 0px; } body{ background: #f0f0f0; font: normal normal 14px Open Sans,Verdana, Arial; } .main-container{ max-width: 1024px; margin: 0px auto; } .section { padding: 15px; } .form-control { padding: 10px; border: 1px solid #ddd; width: 100%; margin-bottom: 5px; color: #444; } .btn-green{ display: inline-block; padding: 5px 10px; cursor: pointer; background: #00a65a; border: 1px solid #009549; color: #fff; width: 100%; } .captcha-box{ max-width: 300px; background: #ddd; padding: 10px; } .captcha-message{ background: #fff; padding: 5px; text-align: center; color: #009549; border: 1px solid #009549; margin-bottom: 10px; } .captcha-message.error{ color: #DD1A16; border: 1px solid #DD1A16; }