□PHPでフォーム入力時の画像認証(CAPTCHA認証)を導入
登録、投稿、コメントなど、とにかくフォームを設置するとあらゆる方法で
機械的に登録してくる輩がいる。そもそも登録してもお前らには意味がない
のだといっても全く聞く耳を持っていない。そりゃそうだ、自動処理をして
いるのだから。
そこでその自動処理を防ぐために(DBその他に無駄な処理をさせないために)
フォーム入力時の画像認証(CAPTCHA認証)を導入したいのだけど、どれも懲り
すぎていたりするのであんまり気に入らない…ので自分で作りました。
スクリプトは二つ。
一つは「POST」で渡された文字列をPNG画像で表示するスクリプト。(keydata.php)
もう一つは、keydata.phpに対してどのように文字を渡し、どのように結果
の画像を表示するかのスクリプト。
前者は表示するだけのスクリプトだけど、POSTで渡さないといけないところ
がミソ。だってGETで渡すようにしたら簡単に機械処理されてしまうからね。
ここでは5文字を想定していますので、もっと長いほうがよかったり短い方
がよかったり、画像を合成したいとかさらに見難くしたいという場合には、
GDの処理をいろいろ調べてあれこれ加工して下さい。
後者は実際に普段の処理側のこと。生で送られてくるPNGデータをどうしたら
PHP処理内で表示できるのがあれこれ見てみたら、こんな方法がありました。
目からうろこでした。
ただ、IE6までは×(FFやChromeとかOperaならぜんぜんOK)というのと、携帯系
は全然使えませんのであしからず。(スマフォはいけました、Androidレグザで)
こちらは画像を表示する(出力する)スクリプト。
<? // ------------------------------------------------------------ // POSTで送信された文字(または数字)をJPEGで返すスクリプト(画像側) // 2011.11.01 T.Kabu/Future Versatile Group // // ・GDライブラリが組み込まれたPHPでないと動きません // ・このスクリプトに対してkeydataという変数に文字を入れてPOSTして下さい // ・読めば判るレベルですが、とりあえず5文字を想定しています // ・フォントはあえて読みにくい文字にするといいと思います // ここではYAKITORIフォントを使っています。 // http://www.forest.impress.co.jp/docs/review/20110117_420882.html // ------------------------------------------------------------ ?> <? // ------------------------------ // 初期処理 // ------------------------------ // 画像サイズ設定 $P_W = 128; $P_H = 36; // フォントサイズ設定 $F_S = 28; // ------------------------------ // データ取得 // ------------------------------ // ポストデータでない場合には if (!isset($_POST['keydata'])) { $KEYDATA = 'ERROR'; } // ポストデータ elseif(strlen($_POST['keydata']) == 0) { $KEYDATA = 'NONE'; } elseif(strlen($_POST['keydata']) < 3) { $KEYDATA = 'SHORT'; } else { $KEYDATA = $_POST['keydata']; } // 画像パレットを生成 $IMG_P = imagecreatetruecolor($P_W, $P_H); // 白色の背景、オレンジのテキストとして設定 $background_color = imagecolorallocate($IMG_P, 240, 240, 240); $text_color = imagecolorallocate($IMG_P, 255, 137, 0); // 背景を赤にします imagefilledrectangle($IMG_P, 0, 0, $P_W - 1 , $P_H - 1, $background_color); // ttf フォントファイルへのパスを設定します //$font_file = '/usr/share/fonts/TrueType-vlgothic/VL-PGothic-Regular.ttf'; $font_file = './Yakitori.otf'; // フォントサイズ 13 で 'PHP Manual' というテキストを描画します imagefttext($IMG_P, $F_S, 0, 3, $P_H - 3, $text_color, $font_file, $KEYDATA); // ヘッダ出力(単独で呼び出された時などに上記メッセージの画像を出すため header('Content-Type: image/jpeg'); // 画像データ出力(劣化させるとますます機械認識は厳しい…かな? imagejpeg($IMG_P, NULL, 25); // 画像データ破棄 imagedestroy($IMG_P); ?>
こちらは呼び出すほうのスクリプト。
<? // ------------------------------------------------------------ // POSTで任意の文字を渡して帰ってきたJPEGデータをbase64エンコードで表示するスクリプト(呼び出し側) // 2011.11.01 T.Kabu/Future Versatile Group // // ・ポストする方法はあちこちにあるけど、今回はこちらを参考にしました // http://www.programming-magic.com/20080226023511/ // ・で、画像を表示するには…なるほど、こんな方法あったのねー、です。 // http://kaworu.jpn.org/kaworu/2008-04-06-1.php // ------------------------------------------------------------ ?> <? // 表示したいデータを生成 $KEYDATA = sprintf("%05d", rand(100,99999)); // 表示するデータのクリプトデータを生成 $CRYPTKEY = crypt($KEYDATA, 'HOGEHOGE'); // フルパスで「POSTで送信された文字(または数字)をJPEGで返すスクリプト(画像側)」を指定 $KEYDATA_URL = 'http://hogehoge.comm/keydata.php'; // 画像生成用のキーデータを設定 $REQUEST_PARAM = array('keydata' => $KEYDATA); // リクエストを生成 $REQUEST_DATA = array('http' => array( 'method' => 'POST', 'content' => http_build_query($REQUEST_PARAM), )); // 画像データをリクエストして帰ってきたデータをBASE64でエンコード $BASE64_IMG = base64_encode(file_get_contents($KEYDATA_URL, false, stream_context_create($REQUEST_DATA))); ?> <img src="data:image/jpeg;base64,<? print $BASE64_IMG; ?>"> <BR> <BR> <FORM action="./" method="post"> <INPUT type="hidden" name="CRYPTKEY" value="<? print $CRYPTKEY; ?>"> <INPUT type="text" name="CHECKKEY" value="" size="10" maxlength="5"> <INPUT type="submit" name="SUBMIT" value="CHECK"> </FORM> <? // クリプトキーとチェックキーがあるなら…チェックをする if (isset($_POST['CRYPTKEY']) && isset($_POST['CHECKKEY'])) { // クリプトチェックがOKなら if (crypt($_POST['CHECKKEY'], $_POST['CRYPTKEY']) == $_POST['CRYPTKEY']) { print "チェックOKです!!<BR>\n"; } else { print "違うみたいです!?<BR>\n"; } } ?>
あとは必要に応じていろいろいじって下さい。
追記:2011/11.01 -1-
yum -y install php-gd
…忘れずに。(肝心のターゲットシステムに入ってなかった)
非常にシンプルでわかりやすく参考になりました。
ありがとうございました。