Image‑based CAPTCHA in PHP (Hiragana, Numbers, Alphabet) — Source Code Included
This page provides PHP source code for implementing image‑based CAPTCHA for bot protection, including hiragana, numbers, and alphabet verification.
Try it out
To test the CAPTCHA, click the link below:
Sample Site(Japanese Only)
Source Code
PHP GD must be enabled
In most environments GD is enabled by default, but if it is not,
edit your php.ini file and enable the GD extension.
A TrueType font file is required
A TrueType font file is necessary.
You can download and use the free IPA font (https://moji.or.jp/ipafont/ipaex00401/) in accordance with its license.
File for displaying the CAPTCHA image and input form
php_auth_image.php
<?php
include("./mam_auth_image.php");
[$auth_char,$auth_img]=getCharImg();
//Start the session
session_start();
// Store the correct CAPTCHA string in the session.
// After POST, compare the user input with this stored value.
$_SESSION["img_auth_char"]=$auth_char;
if(isset($_GET["result"])&&$_GET["result"]=="failed"){$err="<p style='color:red;'>Authentication failed</p>";}else{$err="";}
?>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>CAPTCHA Input Screen for BOT Protection</title>
</head>
<body style="margin:0;background-color:#ffffff">
<form method="post" action="php_auth_image_confirm.php">
<?=$err?>
<img id="char" src="<?=$auth_img?>"><br>
Please enter the numbers shown in the image above.<br>
<input type="text" maxlength="10" size="20" style="ime-mode:disabled;" name="input_char"><br>
<input type="submit" value="Verify">
</form>
</body>
</html>
File for validating the user’s input
php_auth_image_confirm.php
<?php
//Start the session
session_start();
//Retrieve the correct CAPTCHA string from the session
if(isset($_SESSION["img_auth_char"])){
$img_auth_char=$_SESSION["img_auth_char"];
}else{
die();
}
//Retrieve the posted input value
if(isset($_POST["input_char"])){
$input_char=$_POST["input_char"];
}else{
$input_char="";
}
//Validate the CAPTCHA
if($input_char!==$img_auth_char){
header("location: ./php_auth_image.php?result=failed";
exit;
}
?>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>CAPTCHA Verification Result</title>
</head>
<body style="margin:0;background-color:#ffffff">
Authentication successful
</body>
</html>
PHP library file that generates the CAPTCHA image
mam_auth_image.php
Calling the getCharImg() function returns an array containing:
["authentication string", "authentication image"].
<?php //Specify the path to the TrueType font file define("TrueTypeFontPath",__DIR__."/ipaexg.ttf"); define("ImageHeight",80); //Height of the generated image (px) function getCharImg(){ //Define the list of characters used for CAPTCHA //Half‑width numbers //1 and 7 are commented out because they become hard to recognize when rotated $carr=[/*"1",*/"2","3","4","5","6",/*"7",*/"8","9","0",]; //Half‑width uppercase alphabet (I and L are commented out) //$carr=[ //"A","B","C","D","E","F","G","H",/*"I",*/"J","K",/*"L",*/ //"M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" //]; //全角ひらがなの場合 //Full‑width Hiragana (く, て, へ are commented out because rotation makes them hard to distinguish) //$carr=[ //"あ","い","う","え","お","か","き",/*"く",*/"け","こ", //"さ","し","す","せ","そ","た","ち","つ",/*"て",*/"と", //"な","に","ぬ","ね","の","は","ひ","ふ",/*"へ",*/"ほ", //"ま","み","む","め","も","や","ゆ","よ", //"ら","り","る","れ","ろ","わ","を","ん", //]; $cnum=random_int(6,6); //Number of characters used for CAPTCHA (fixed at 6) $cc=''; $c=[]; for($i=0;$i<$cnum;$i++){ $c[$i]=[]; $c[$i]['chr']=$carr[random_int(0,count($carr)-1)]; $cc.=$c[$i]['chr']; } $lt=floor(ImageHeight*0.1); //Calculate total image width $img=imagecreatetruecolor(100,100); $dpi=96; //Resolution imageresolution($img, $dpi, $dpi); $pt= floor(ImageHeight*0.6*72/$dpi); $col=imagecolorallocate($img,0,0,0); for($i=0;$i<$cnum;$i++){ //Rotation angle $c[$i]['r']=random_int(-45,45); $arr=imagettftext( $img,$pt, $c[$i]['r'],0,0, $col,TrueTypeFontPath,$c[$i]['chr'] ); $xmin=min($arr[0],$arr[2],$arr[4],$arr[6]); $xmax=max($arr[0],$arr[2],$arr[4],$arr[6]); $ymin=min($arr[1],$arr[3],$arr[5],$arr[7]); $ymax=max($arr[1],$arr[3],$arr[5],$arr[7]); $c[$i]['x']=$lt-round($xmin*$dpi/72); $char_w=($xmax-$xmin)*$dpi/72; $lt=round($c[$i]['x']+$char_w); //Slightly overlap characters $lt-=random_int($char_w*0.1,$char_w*0.4); $c[$i]['y']=random_int(floor(ImageHeight*0.1),floor(ImageHeight*0.3))-$ymin; } $lt+=floor(ImageHeight*0.1); //Final image width imagedestroy($img); $im=imagecreatetruecolor($lt,ImageHeight); imageresolution($im, $dpi, $dpi); $tranColor = imagecolorallocate($im, 254, 253, 252);//Background color imagefill($im, 0, 0, $tranColor); //Fill background imagecolortransparent($im,$tranColor);//Make background transparent //Draw random rectangles as background noise $rnd=random_int(40,50); for($i=0;$i<$rnd;$i++){ $col=imagecolorallocate($im,random_int(192,255),random_int(192,255),random_int(192,255)); $x1=random_int(0,$lt); $y1=random_int(0,ImageHeight); $x2=random_int($x1,$lt); $y2=random_int($y1,ImageHeight); imagefilledrectangle($im, $x1, $y1, $x2, $y2, $col); } //Draw distorted characters for($i=0;$i<$cnum;$i++){ $col = imagecolorallocate($im, random_int(0,80), random_int(0,80), random_int(0,80));//色 imagettftext( $im, $pt, $c[$i]['r'],$c[$i]['x'],$c[$i]['y'], $col, TrueTypeFontPath, $c[$i]['chr'] ); } //Draw dot noise $rnd=random_int(ImageHeight*6,ImageHeight*8); for($i=0;$i<$rnd;$i++){ $col=imagecolorallocate($im,random_int(0,80),random_int(0,80),random_int(0,80)); imagesetpixel($im,random_int(0,$lt),random_int(0,ImageHeight),$col); } //Draw line noise $rnd=random_int(round(ImageHeight*0.8),round(ImageHeight*0.9)); for($i=0;$i<$rnd;$i++){ $col=imagecolorallocate($im,random_int(0,100),random_int(0,100),random_int(0,100)); imageline($im,random_int(0,$lt),random_int(0,ImageHeight),random_int(0,$lt),random_int(0,ImageHeight),$col); } //Capture output buffer and convert to data URI ob_start(); imagejpeg($im,NULL,30); $con = base64_encode(ob_get_contents()); ob_end_clean(); imagedestroy($im); $src="data:image/jpeg;base64,".$con; //Return the correct string and the generated image return [$cc,$src]; }
