忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2024/04/26 10:39 |
PHP1-19:CAPTCHA認証

Text_CAPTCHA 0.3.1
Text_CAPTCHA_Numeral 1.2.0
Image_Text 0.6.0beta

コメント投稿欄をフリーパスにしておいたらコメントスパムされ放題です。
まあここも認証はありませんが、弱小サイト故に飛んできていません。
めでたしめでたし?

というわけでコメントスパム防止のため、文字を画像として表示し、それを入力させるCAPTCHA認証技術があります。
PHPではPear::Text_CAPTCHAというライブラリが存在するので使ってみましょう。

ただ、Text_CAPTCHAはGDという画像ライブラリを使用します。
phpinfoで使用できることを確認しておきます。

とりあえずText_CAPTCHAをダウンロード、解凍したらいつものようにpear/Text_CAPTCHAフォルダに入れます。
表示用にフォントが必要になるのでとりあえずWindows/Fontsあたりからcour.ttfを拾って↓と同じフォルダに入れておきます。

まずは動作確認のために最低限のモデルクラス。

captcha.class.php

<?php
    //初期設定
    define('PEAR_DIR',$_SERVER['DOCUMENT_ROOT'].'/src/php/pear/');
    ini_set('include_path',PEAR_DIR.PATH_SEPARATOR.ini_get('include_path'));
    require_once(PEAR_DIR.'Text_CAPTCHA/CAPTCHA.php');

    class pearCaptchaModel {
        //メンバ変数
        private $imageOptions = array();
       
        //コンストラクタ
        public function __construct(){
           
            //出力テキスト設定
            $imageOptions = array(
                'font_size'        => 24,
                'font_path'        => './',
                'font_file'        => 'COUR.TTF',
                'text_color'       => '#DDFF99',
            );
        $c = Text_CAPTCHA::factory('Image');
    }


captcha.php 

<?php
    require_once('./captcha.class.php');
    $rss = new pearCaptchaModel();


見つからないエラー。

Warning: Text_CAPTCHA::include_once(Text/CAPTCHA/Driver/Image.php) [function.Text-CAPTCHA-include-once]: failed to open stream: No such file or directory in C:\xampp\htdocs\src\php\pear\Text_CAPTCHA\CAPTCHA.php on line 166

Warning: Text_CAPTCHA::include_once() [function.include]: Failed opening 'Text/CAPTCHA/Driver/Image.php' for inclusion (include_path='C:/xampp/htdocs/src/php/pear/;.;C:\xampp\php\pear\') in C:\xampp\htdocs\src\php\pear\Text_CAPTCHA\CAPTCHA.php on line 166

Fatal error: Class 'Text_CAPTCHA_Driver_Image' not found in C:\xampp\htdocs\src\php\pear\Text_CAPTCHA\CAPTCHA.php on line 169


全体的に、PearからのパスがTextでハードコートされてしまっているので、Text_CAPTCHAフォルダの名前をTextに変更します。
また、Pear::Image_Textを利用しているようなので、これもダウンロードし、pear/Image/Text.phpに配置します。

ついでに作成した画像を入れる用にimagesフォルダを作成しておきます。

エラーが出なくなったら適当にメソッドを追加していきます。
 
captcha.class.php

<?php
    //初期設定
    define('IMAGE_DIR',getcwd().'/images/');
    define('PEAR_DIR',$_SERVER['DOCUMENT_ROOT'].'/src/php/pear/');
    ini_set('include_path',PEAR_DIR.PATH_SEPARATOR.ini_get('include_path'));
    require_once(PEAR_DIR.'Text/CAPTCHA.php');

    class pearCaptchaModel {
        //メンバ変数
        private $options = array();
        private $filename = '';
        private $c = '';
       
        //コンストラクタ
        public function __construct(){
            //前回の画像を削除
            $image_file=scandir(IMAGE_DIR);
            foreach($image_file as $val){
                if($val=='.' || $val=='..'){continue;}
                unlink(IMAGE_DIR.$val);
            }
            //デフォルトの出力テキスト設定
            $imageOptions = array(
                'font_size'        => 24,
                'font_path'        => './',
                'font_file'        => 'COUR.TTF',
                'text_color'       => '#DDFF99',
            );
            //デフォルトの出力画像設定
            $this->options = array(
                'width' => 200,
                'height' => 80,
                'output' => 'png',
                //'phrase' => 'aaaaa',
                'imageOptions' => $imageOptions
            );
        }
       
        //出力テキスト設定を上書きセット
        public function setImageOptions($imageOptions=array()){
            foreach($imageOptions as $key=>$val){
                $this->options['imageOptions'][$key]=$val;
            }
            return true;
        }
       
        //出力画像設定を上書きセット
        public function setOptions($options=array()){
            foreach($options as $key=>$val){
                $this->options[$key]=$val;
            }
            return true;
        }
       
        //イメージを作成
        public function makeImage(){
            $this->c = Text_CAPTCHA::factory('Image');
            $retval = $this->c->init($this->options);
            if (PEAR::isError($retval)) {
                printf('CAPTCHA 作成時にエラー: %s!',
                    $retval->getMessage());
                exit;
            }
            return true;
        }
       
        //作成したフレーズを取得
        public function getPhrase(){
            return $this->c->getPhrase();
        }
       
        //画像を取得
        public function getImageFile(){
            $image = $this->c->getCAPTCHA();
            if (PEAR::isError($image)) {
                echo 'CAPTCHA 作成時にエラー!';
                echo $image->getMessage();
                exit;
            }
            $this->filename=IMAGE_DIR.md5(session_id()).'.'.$this->options['output'];
            file_put_contents($this->filename,$image);
            return $this->filename;
        }
    #↓クラスのおわり
    }


captcha.php 

<?php
    #初期設定
    session_start();
    require_once('./captcha.class.php');
    $captcha = new pearCaptchaModel();
    
    #オプション変更方法
    //$captcha->setOptions(array('output'=>'jpg'));
    //$captcha->setImageOptions(array('text_color'=>'#ff00ff'));
   
    #画像作成
    $cap['image']=$captcha->makeImage();
    $cap['phrase']=$captcha->getPhrase();
    $cap['filename']=$captcha->getImageFile();
   
    #セッションに入れる
    $_SESSION['phrase']=$cap['phrase'];

    #表示
    print('<img src="'.$cap['filename'].'">');
    print("<pre>");var_dump($cap);die();


導入さえうまくいけば、画像認証機能が簡単に作成できます。
画像作成に最低限必要なオプションは$options['output']だけで、他は何も入っていなければCAPTCHAが適当にデフォルト値を使ってくれます。
$options['phrase']で表示する値を設定できます。
固定値を与えると認証の意味が全くありませんが。

画像を作成するばかりだとセッションがくるたびに際限なく画像が増えていくので、コンストラクタで画像削除処理を入れています。
本当はデストラクタでファイル名を指定して削除できるといいのですが、デストラクタで削除するとimgタグで表示も出来なくなってしまいます。
もしかしたらob_end_flushとsleepとかでできるかもしれません。

あとは投稿後の画面で$_SESSION['phrase']と入力値を比較するだけです。
簡単にCAPTCHA認証を設置できました。
めでたし。
 

PR


2008/08/25 14:54 | Comments(0) | TrackBack() | PHP

トラックバック

トラックバックURL:

コメント

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<PHP1-20:Pear::Text_CAPTCHA_Numeralのようなもの | HOME | PHP1-18:AjaxでRSSリーダ>>
忍者ブログ[PR]