cakephp 用 CAPTCHA コンポーネント(日本語対応)
8月 5th, 2008
スパムや不正登録防止のために CAPTCHA を使うことはよくあることですが、特に外国からの不正アクセスに関しては日本語(漢字)を入力させる CAPTCHA が有効であるという記事を目にしました。
そこで、漢字やひらがなの表示に対応した、CAPTCHA の cakephp のコンポーネントを作成しました。
MIT ライセンスで公開いたします。
動作イメージ
ひらがなと、小学校一年生で習うレベルの漢字を使った CAPTCHA です。簡単な漢字しか使わないので分かったような分からないような面白い日本語が出力されるのも魅力の一つです
スクリプトを動作させるには mbstring, freetype, gd に対応した PHP がインストールされている必要があります。日本語の表示には日本語のフォントが必要で、ライセンス上問題ないものを こちら から入手することができます。
作成に際しては以下のサイトを参考にさせていただきました。
http://rossoft.wordpress.com/2006/03/16/image-auth-component/
http://php.to/tips/8/
コンポーネントの使用方法は こちら に詳しく載っていますので参考にしてください。
app/controllers/components/image_auth.php
<?php
/*
* Image Auth component.
* Real human verification system for forms with japanese characters
*
* @author RosSoft
* @author Infosia, Inc.
* @version 0.1
* @license MIT
*
* @link http://rossoft.wordpress.com/2006/03/16/image-auth-component/
* @link http://www.infosia.co.jp/posts/157
* @link http://php.to/tips/8/
*/
class ImageAuthComponent extends Object {
var $components = array('session');
var $controller;
var $font = 'ipam';
var $imageWidth = 170;
var $imageHeight = 50;
var $fontSize = 16;
var $letterSpace = 10;
var $strLength = 4;
var $bgColors = array(
'176.196.222', // Blue
'204.153.204', // Purple
'204.204.204', // Gray
'227.81.82', // Red
'150.200.162' // Green
);
var $fontColors = array(
'0.0.139', // Blue
'104.34.139', // Purple
'79.79.79', // Gray
'128.0.0', // Red
'59.94.15' // Green
);
function startup(&$controller) {
$this->controller = $controller;
}
function generate($regenerate = true) {
if (!$regenerate) {
$regenerate= ! $this->session->check('image_auth_string');
}
if ($regenerate) {
$string = $this->_generateString($this->strLength);
$this->session->write('image_auth_string', $string);
}
}
function check($str) {
return ($str === $this->session->read('image_auth_string'));
}
function show() {
$this->generate(false);
$string = $this->session->read('image_auth_string');
putenv('GDFONTPATH=' . realpath(VENDORS . 'image_auth'));
$img = imagecreate($this->imageWidth, $this->imageHeight) or die('Can not initialize GD Image Library');
list($br, $bg, $bb) = explode('.', $this->bgColors[rand(0, count($this->bgColors)-1)]);
list($tr, $tg, $tb) = explode('.', $this->fontColors[rand(0, count($this->fontColors)-1)]);
$bgColor = imagecolorallocate($img, $br, $bg, $bb);
$txtColor = imagecolorallocate($img, $tr, $tg, $tb);
$lineColor = imagecolorallocate($img, 0, 0, 0);
imageline($img, 0, 0, $this->imageWidth, 0, $lineColor);
imageline($img, 0, 0, 0, $this->imageHeight, $lineColor);
imageline($img, 0, $this->imageHeight-1, $this->imageWidth, $this->imageHeight -1, $lineColor);
imageline($img, $this->imageWidth-1, 0, $this->imageWidth-1, $this->imageHeight, $lineColor);
for($i=0; $i<strlen($string); $i++) {
imagettftext($img, (rand() % $this->fontSize / 1.5) + $this->fontSize, rand(-40, 00), (($i * $this->fontSize * 2) + $this->letterSpace), rand($this->fontSize+15, ($this->imageHeight - $this->fontSize-15)), $txtColor, $this->font, mb_substr($string, $i, 1, "UTF-8"));
}
if (function_exists('imagefilter')) {
imagefilter($img, IMG_FILTER_GAUSSIAN_BLUR, 200);
}
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: no-store, no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
if (function_exists('imagepng')) {
header("Content-type: image/png");
imagepng($img);
} else {
header("Content-type: image/jpeg");
imagejpeg($img);
}
$this->controller->autoRender=false;
}
function _generateString($length = 6) {
$string = '';
srand(getmicrotime());
$s = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをんがぎぐげござじずぜぞだぢづでど一右雨円王音下火花貝学気九休玉金空月犬見五口校左三山子四糸字耳七車手十出女小上森人水正生青夕石赤千川先早草足村大男竹中虫町天田土二日入年白八百文木本名目立力林六";
for($i=0; $i < $length; $i++) {
$string .= mb_substr($s, rand(1, mb_strlen($s, 'UTF-8') -1), 1, 'UTF-8');
}
return $string;
}
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$sec + (float)$usec);
}
}
?>
ログインコントローラ(サンプル)
<?php
class UsersController extends AppController {
var $helpers = array('Html', 'Form');
var $components = array('imageAuth');
function add() {
if (!empty($this->data)) {
// snip...
if (!$this->imageAuth->check($this->data['User']['image_auth'])) {
$this->flash('画像に表示されている文字と一致しません', 'javascript:history.back();');
return;
}
}
}
// snip...
function image_auth() {
$this->imageAuth->show();
}
}
?>
登録フォームテンプレート(サンプル)
<?php
echo $form->create('User', array('action' => 'add'));
echo 'メールアドレス: ';
echo $form->input('User.username', array('type'=>'text', 'label'=>false));
echo 'パスワード: ';
echo $form->input('User.password', array('type'=>'password', 'label'=>false, 'value'=>''));
?>
画像に表示されている文字を入力してください
<div class="input text"><img src="<?php echo $html->url('/users/image_auth') ?>" /></div>
<?php
echo $form->input('User.image_auth', array('type'=>'text', 'label'=>false, 'value'=>''));
echo $form->submit("新規登録");
echo $form->end();
?>