トップへ(mam-mam.net/)

Image‑based CAPTCHA in PHP (Hiragana, Numbers, Alphabet) — Source Code Included

Japanese

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];
}

PHP | Samples