File indexing completed on 2024-12-22 05:36:30

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Captcha
0017  * @subpackage Adapter
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  */
0021 
0022 /** @see Zend_Captcha_Base */
0023 // require_once 'Zend/Captcha/Base.php';
0024 
0025 /** @see Zend_Crypt_Math */
0026 // require_once 'Zend/Crypt/Math.php';
0027 
0028 /**
0029  * Word-based captcha adapter
0030  *
0031  * Generates random word which user should recognise
0032  *
0033  * @category   Zend
0034  * @package    Zend_Captcha
0035  * @subpackage Adapter
0036  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0037  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0038  * @version    $Id$
0039  */
0040 abstract class Zend_Captcha_Word extends Zend_Captcha_Base
0041 {
0042     /**#@+
0043      * @var array Character sets
0044      */
0045     static public $V  = array("a", "e", "i", "o", "u", "y");
0046     static public $VN = array("a", "e", "i", "o", "u", "y","2","3","4","5","6","7","8","9");
0047     static public $C  = array("b","c","d","f","g","h","j","k","m","n","p","q","r","s","t","u","v","w","x","z");
0048     static public $CN = array("b","c","d","f","g","h","j","k","m","n","p","q","r","s","t","u","v","w","x","z","2","3","4","5","6","7","8","9");
0049     /**#@-*/
0050 
0051     /**
0052      * Random session ID
0053      *
0054      * @var string
0055      */
0056     protected $_id;
0057 
0058     /**
0059      * Generated word
0060      *
0061      * @var string
0062      */
0063     protected $_word;
0064 
0065     /**
0066      * Session
0067      *
0068      * @var Zend_Session_Namespace
0069      */
0070     protected $_session;
0071 
0072     /**
0073      * Class name for sessions
0074      *
0075      * @var string
0076      */
0077     protected $_sessionClass = 'Zend_Session_Namespace';
0078 
0079     /**
0080      * Should the numbers be used or only letters
0081      *
0082      * @var boolean
0083      */
0084     protected $_useNumbers = true;
0085 
0086     /**
0087      * Should both cases be used or only lowercase
0088      *
0089      * @var boolean
0090      */
0091     // protected $_useCase = false;
0092 
0093     /**
0094      * Session lifetime for the captcha data
0095      *
0096      * @var integer
0097      */
0098     protected $_timeout = 300;
0099 
0100     /**
0101      * Should generate() keep session or create a new one?
0102      *
0103      * @var boolean
0104      */
0105     protected $_keepSession = false;
0106 
0107     /**#@+
0108      * Error codes
0109      */
0110     const MISSING_VALUE = 'missingValue';
0111     const MISSING_ID    = 'missingID';
0112     const BAD_CAPTCHA   = 'badCaptcha';
0113     /**#@-*/
0114 
0115     /**
0116      * Error messages
0117      * @var array
0118      */
0119     protected $_messageTemplates = array(
0120         self::MISSING_VALUE => 'Empty captcha value',
0121         self::MISSING_ID    => 'Captcha ID field is missing',
0122         self::BAD_CAPTCHA   => 'Captcha value is wrong',
0123     );
0124 
0125     /**
0126      * Length of the word to generate
0127      *
0128      * @var integer
0129      */
0130     protected $_wordlen = 8;
0131 
0132     /**
0133      * Retrieve session class to utilize
0134      *
0135      * @return string
0136      */
0137     public function getSessionClass()
0138     {
0139         return $this->_sessionClass;
0140     }
0141 
0142     /**
0143      * Set session class for persistence
0144      *
0145      * @param  string $_sessionClass
0146      * @return Zend_Captcha_Word
0147      */
0148     public function setSessionClass($_sessionClass)
0149     {
0150         $this->_sessionClass = $_sessionClass;
0151         return $this;
0152     }
0153 
0154     /**
0155      * Retrieve word length to use when genrating captcha
0156      *
0157      * @return integer
0158      */
0159     public function getWordlen()
0160     {
0161         return $this->_wordlen;
0162     }
0163 
0164     /**
0165      * Set word length of captcha
0166      *
0167      * @param integer $wordlen
0168      * @return Zend_Captcha_Word
0169      */
0170     public function setWordlen($wordlen)
0171     {
0172         $this->_wordlen = $wordlen;
0173         return $this;
0174     }
0175 
0176     /**
0177      * Retrieve captcha ID
0178      *
0179      * @return string
0180      */
0181     public function getId()
0182     {
0183         if (null === $this->_id) {
0184             $this->_setId($this->_generateRandomId());
0185         }
0186         return $this->_id;
0187     }
0188 
0189     /**
0190      * Set captcha identifier
0191      *
0192      * @param string $id
0193      * @return Zend_Captcha_Word
0194      */
0195     protected function _setId($id)
0196     {
0197         $this->_id = $id;
0198         return $this;
0199     }
0200 
0201     /**
0202      * Set timeout for session token
0203      *
0204      * @param  int $ttl
0205      * @return Zend_Captcha_Word
0206      */
0207     public function setTimeout($ttl)
0208     {
0209         $this->_timeout = (int) $ttl;
0210         return $this;
0211     }
0212 
0213     /**
0214      * Get session token timeout
0215      *
0216      * @return int
0217      */
0218     public function getTimeout()
0219     {
0220         return $this->_timeout;
0221     }
0222 
0223     /**
0224      * Sets if session should be preserved on generate()
0225      *
0226      * @param bool $keepSession Should session be kept on generate()?
0227      * @return Zend_Captcha_Word
0228      */
0229     public function setKeepSession($keepSession)
0230     {
0231         $this->_keepSession = $keepSession;
0232         return $this;
0233     }
0234 
0235     /**
0236      * Numbers should be included in the pattern?
0237      *
0238      * @return bool
0239      */
0240     public function getUseNumbers()
0241     {
0242         return $this->_useNumbers;
0243     }
0244 
0245     /**
0246      * Set if numbers should be included in the pattern
0247      *
0248      * @param bool $_useNumbers numbers should be included in the pattern?
0249      * @return Zend_Captcha_Word
0250      */
0251     public function setUseNumbers($_useNumbers)
0252     {
0253         $this->_useNumbers = $_useNumbers;
0254         return $this;
0255     }
0256 
0257     /**
0258      * Get session object
0259      *
0260      * @return Zend_Session_Namespace
0261      */
0262     public function getSession()
0263     {
0264         if (!isset($this->_session) || (null === $this->_session)) {
0265             $id = $this->getId();
0266             if (!class_exists($this->_sessionClass)) {
0267                 // require_once 'Zend/Loader.php';
0268                 Zend_Loader::loadClass($this->_sessionClass);
0269             }
0270             $this->_session = new $this->_sessionClass('Zend_Form_Captcha_' . $id);
0271             $this->_session->setExpirationHops(1, null, true);
0272             $this->_session->setExpirationSeconds($this->getTimeout());
0273         }
0274         return $this->_session;
0275     }
0276 
0277     /**
0278      * Set session namespace object
0279      *
0280      * @param  Zend_Session_Namespace $session
0281      * @return Zend_Captcha_Word
0282      */
0283     public function setSession(Zend_Session_Namespace $session)
0284     {
0285         $this->_session = $session;
0286         if ($session) {
0287             $this->_keepSession = true;
0288         }
0289         return $this;
0290     }
0291 
0292     /**
0293      * Get captcha word
0294      *
0295      * @return string
0296      */
0297     public function getWord()
0298     {
0299         if (empty($this->_word)) {
0300             $session     = $this->getSession();
0301             $this->_word = $session->word;
0302         }
0303         return $this->_word;
0304     }
0305 
0306     /**
0307      * Set captcha word
0308      *
0309      * @param  string $word
0310      * @return Zend_Captcha_Word
0311      */
0312     protected function _setWord($word)
0313     {
0314         $session       = $this->getSession();
0315         $session->word = $word;
0316         $this->_word   = $word;
0317         return $this;
0318     }
0319 
0320     /**
0321      * Generate new random word
0322      *
0323      * @return string
0324      */
0325     protected function _generateWord()
0326     {
0327         $word       = '';
0328         $wordLen    = $this->getWordLen();
0329         $vowels     = $this->_useNumbers ? self::$VN : self::$V;
0330         $consonants = $this->_useNumbers ? self::$CN : self::$C;
0331 
0332         $totIndexCon = count($consonants) - 1;
0333         $totIndexVow = count($vowels) - 1;
0334         for ($i=0; $i < $wordLen; $i = $i + 2) {
0335             // generate word with mix of vowels and consonants
0336             $consonant = $consonants[Zend_Crypt_Math::randInteger(0, $totIndexCon, true)];
0337             $vowel     = $vowels[Zend_Crypt_Math::randInteger(0, $totIndexVow, true)];
0338             $word     .= $consonant . $vowel;
0339         }
0340 
0341         if (strlen($word) > $wordLen) {
0342             $word = substr($word, 0, $wordLen);
0343         }
0344 
0345         return $word;
0346     }
0347 
0348     /**
0349      * Generate new session ID and new word
0350      *
0351      * @return string session ID
0352      */
0353     public function generate()
0354     {
0355         if (!$this->_keepSession) {
0356             $this->_session = null;
0357         }
0358         $id = $this->_generateRandomId();
0359         $this->_setId($id);
0360         $word = $this->_generateWord();
0361         $this->_setWord($word);
0362         return $id;
0363     }
0364 
0365     protected function _generateRandomId()
0366     {
0367         return md5(Zend_Crypt_Math::randBytes(32));
0368     }
0369 
0370     /**
0371      * Validate the word
0372      *
0373      * @see    Zend_Validate_Interface::isValid()
0374      * @param  mixed      $value
0375      * @param  array|null $context
0376      * @return boolean
0377      */
0378     public function isValid($value, $context = null)
0379     {
0380         if (!is_array($value) && !is_array($context)) {
0381             $this->_error(self::MISSING_VALUE);
0382             return false;
0383         }
0384         if (!is_array($value) && is_array($context)) {
0385             $value = $context;
0386         }
0387 
0388         $name = $this->getName();
0389 
0390         if (isset($value[$name])) {
0391             $value = $value[$name];
0392         }
0393 
0394         if (!isset($value['input'])) {
0395             $this->_error(self::MISSING_VALUE);
0396             return false;
0397         }
0398         $input = strtolower($value['input']);
0399         $this->_setValue($input);
0400 
0401         if (!isset($value['id'])) {
0402             $this->_error(self::MISSING_ID);
0403             return false;
0404         }
0405 
0406         $this->_id = $value['id'];
0407         if ($input !== $this->getWord()) {
0408             $this->_error(self::BAD_CAPTCHA);
0409             return false;
0410         }
0411 
0412         return true;
0413     }
0414 
0415     /**
0416      * Get captcha decorator
0417      *
0418      * @return string
0419      */
0420     public function getDecorator()
0421     {
0422         return "Captcha_Word";
0423     }
0424 }