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

PHPで画像認証(ひらがな、数字認証等)~ソースコード公開

PHPで画像認証(ひらがな、数字認証等)~ソースコード公開

PHPでBOT対策用の画像認証(ひらがな、数字、アルファベット認証)のソースコードを公開しています。

まずは試してみる

試してみたい場合は、次のURLリンクをクリック サンプルサイト

ソースコード

PHPのGDが有効でなければなりません

通常、GDが有効だと思いますが、有効でない場合は、
php.iniファイルを編集して拡張機能「GD」を有効にしてください。

TrueTypeFontファイルが必要

TrueTypeFontファイルが必要です。
無料のipaフォント(https://moji.or.jp/ipafont/ipaex00401/)をライセンスに準拠してダウンロードして使用しましょう

認証画像表示と入力フォームの ファイル

php_auth_image.php

<?php
  include("./mam_auth_image.php");
  [$auth_char,$auth_img]=getCharImg();
  //セッションを開始
  session_start();
  //セッション変数に正解の認証文字列を入れて、POST後に入力値とPOST値を比較して認証する
  $_SESSION["img_auth_char"]=$auth_char;
  if(isset($_GET["result"])&&$_GET["result"]=="failed"){$err="<p style='color:red;'>認証失敗</p>";}else{$err="";}
?>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>BOT対策用画像認証入力画面</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>
    上記画像に表示された数字を入力してください。<br>
    <input type="text" maxlength="10" size="20" style="ime-mode:disabled;" name="input_char"><br>
    <input type="submit" value="認証">
  </form>
</body>
</html>

入力値を認証する画面の ファイル

php_auth_image_confirm.php

<?php
  //セッションを開始
  session_start();

  //セッション変数の正解の文字列を取得
  if(isset($_SESSION["img_auth_char"])){
    $img_auth_char=$_SESSION["img_auth_char"];
  }else{
    die();
  }

  //postされた文字列を取得
  if(isset($_POST["input_char"])){
    $input_char=$_POST["input_char"];
  }else{
    $input_char="";
  }

  //認証の検証
  if($input_char!==$img_auth_char){
    header("location: ./php_auth_image.php?result=failed";
    exit;
  }
?>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>BOT対策用画像認証結果</title>
</head>
<body style="margin:0;background-color:#ffffff">
  認証しました
</body>
</html>

認証画像を生成するPHPライブラリ ファイル

mam_auth_image.php
getCharImg() 関数を呼び出すと、配列 ["認証文字","認証画像"] を返してきます。

<?php
  //TrueTypeFontファイルのパスを指定
  define("TrueTypeFontPath",__DIR__."/ipaexg.ttf");
  define("ImageHeight",80);//出力される画像の高さ(px)

function getCharImg(){
  //認証に使用する文字一覧を指定

  //半角数字の場合
  //1,7は回転すると分かりにくいのでコメントアウト
  $carr=[/*"1",*/"2","3","4","5","6",/*"7",*/"8","9","0",];

  //半角大文字アルファベットの場合 I,Lはコメントアウト
  //$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"
  //];

  //全角ひらがなの場合
  //「く,て,へ」は回転すると判別しにくいのでコメントアウト
  //$carr=[
  //"あ","い","う","え","お","か","き",/*"く",*/"け","こ",
  //"さ","し","す","せ","そ","た","ち","つ",/*"て",*/"と",
  //"な","に","ぬ","ね","の","は","ひ","ふ",/*"へ",*/"ほ",
  //"ま","み","む","め","も","や","ゆ","よ",
  //"ら","り","る","れ","ろ","わ","を","ん",
  //];

  $cnum=random_int(6,6);//認証に使用する文字数を指定、とりあえず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);//総画像幅の計算
  $img=imagecreatetruecolor(100,100);
  $dpi=96;//解像度の設定
  imageresolution($img, $dpi, $dpi);
  $pt= floor(ImageHeight*0.6*72/$dpi);
  $col=imagecolorallocate($img,0,0,0);
  for($i=0;$i<$cnum;$i++){
    //回転角の設定
    $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);
    //若干文字をかぶせる
    $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);//総画像幅の計算
  imagedestroy($img);
  $im=imagecreatetruecolor($lt,ImageHeight);
  imageresolution($im, $dpi, $dpi);

  $tranColor = imagecolorallocate($im, 254, 253, 252);//背景色セット
  imagefill($im, 0, 0, $tranColor);     //背景を塗る
  imagecolortransparent($im,$tranColor);//透明化
  //背景にランダムな四角形を描く
  $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);
  }
  //変形文字を描画する
  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']
    );
  }
  //点ノイズの描画
  $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);
  }
  //線ノイズの描画
  $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);
  }
  //出力のバッファリングから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;
  
  //わざと少し待つ
  //usleep(500000);
  
  //正解の文字列と、画像の配列を返す
  return [$cc,$src];
}

PHPサンプル集一覧へ