<?php
/* SVN FILE: $Id: CAPTCHA.php 336 2008-05-11 01:39:36Z bb_yujiro $ */
/**
 * CAPTCHA認証
 *
 * PHP versions 5
 *
 *      hitSuji : Social Network Service <http://rakuto.net/rktSNS/>
 *      Copyright (c) 2007 Yujiro Takahashi
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @package         hitSuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 336 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-05-11 10:39:36 +0900 (日, 11 5 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */

/**
 * CAPTCHA認証
 *
 * @category        Authentication
 * @package         hitSuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 336 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-05-11 10:39:36 +0900 (日, 11 5 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */
class Auth_CAPTCHA
{
    /**
     * Phrase
     * @var string
     */
    private $_phrase;

    /**
     * 選択肢
     * @var array
     */
    private $_option = null;

    /**
     * 選択肢数
     * @var integer
     */
    private $_number = null;

    /**
     * コンストラクタ
     *
     * @access public
     * @return void
     */
    public function __construct($number = 5)
    {
        $this->_number = $number;

        $this->_setOption();
    }

    /**
     * 認証結果を取得する
     *
     * @access  public
     * @param string $phrase
     * @param array $selected
     * @return  boolean
     */
    public static function getAuth($phrase, $selected)
    {
        if (empty($phrase)){
            return false;
        }
        if (!is_array($selected)){
            return false;
        }
        $hashed = md5(implode(',', $selected));

        return ($phrase === $hashed);
    }

    /**
     * 認証用キーの取得
     *
     * @access  public
     * @return  string
     */
    public function getPhrase()
    {
        return $this->_phrase;
    }

    /**
     * オプション配列の取得
     *
     * @access  public
     * @return  array
     */
    public function getOption()
    {
        return $this->_option;
    }

    /**
     * Nonceデータの取得
     *
     * @access public
     * @param string $seed
     * @return string Nonceデータ
     */
    public static function getNonce($seed='')
    {
        $timer = ceil(time() / 10);        
        $hashed = md5($timer.$seed);

        return substr($hashed, -14, 10);
    }

    /**
     * 画像の出力
     *
     * @access public
     * @param string $file
     * @return void
     */
    public function outputImage($file)
    {
        $dir = dirname(__FILE__).DIRECTORY_SEPARATOR.
                                    'CAPTCHA'.DIRECTORY_SEPARATOR;

        if (empty($file)){
            $dir     .= 'source'.DIRECTORY_SEPARATOR;
            $basename = 'source.gif';
        } else {
            $rnonce = substr($file, 1, 10);
            $len    = strlen($file) - 16;
            $seed   = substr($file, 12, $len);
            $nonce  = self::getNonce($seed);

            if ($rnonce === $nonce){
                $dir .= 'source'.DIRECTORY_SEPARATOR;
            } else {
                $dir .= 'dummy'.DIRECTORY_SEPARATOR;
            }
            $basename = rand (1, 15).'.gif';
        }
        header ('Content-Type: image/gif');
        header ('Content-Transfer-Encoding: binary');
        header ('Content-Length: ' . filesize($dir.$basename));
        header ('Content-Disposition: inline; filename='. $basename);
        readfile($dir.$basename);
    }

    /**
     * オプションの設定
     *
     * @access private
     * @return void
     */
    private function _setOption()
    {
        $check = 0;
        $this->_option = array();
        $selected = array();
        for ($row=0; $row<$this->_number; $row++){
            $type = rand (0, 1);
            $check += $type;
            $nonce = '';
            $key   = md5(microtime() . $row . $type);
                        
            if ($type){
                $nonce = $this->getNonce($row);
                $selected[] = $key;
            } else {
                $nonce = $this->getNonce($key);
            }
            $this->_option[] = array(
                'key'=>  $key,
                'file'=> $nonce.'/'.$row.'.gif'
            );
        }
        if ($check < 1){
            $this->_setOption();
        }
        $this->_phrase = md5(implode(',', $selected));
    }
} // Auth_CAPTCHA
?>