Word.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Captcha
  17. * @subpackage Adapter
  18. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /** @see Zend_Captcha_Base */
  22. require_once 'Zend/Captcha/Base.php';
  23. /**
  24. * Word-based captcha adapter
  25. *
  26. * Generates random word which user should recognise
  27. *
  28. * @category Zend
  29. * @package Zend_Captcha
  30. * @subpackage Adapter
  31. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  32. * @license http://framework.zend.com/license/new-bsd New BSD License
  33. * @version $Id$
  34. */
  35. abstract class Zend_Captcha_Word extends Zend_Captcha_Base
  36. {
  37. /**#@+
  38. * @var array Character sets
  39. */
  40. static $V = array("a", "e", "i", "o", "u", "y");
  41. static $VN = array("a", "e", "i", "o", "u", "y","2","3","4","5","6","7","8","9");
  42. static $C = array("b","c","d","f","g","h","j","k","m","n","p","q","r","s","t","u","v","w","x","z");
  43. static $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");
  44. /**#@-*/
  45. /**
  46. * Random session ID
  47. *
  48. * @var string
  49. */
  50. protected $_id;
  51. /**
  52. * Generated word
  53. *
  54. * @var string
  55. */
  56. protected $_word;
  57. /**
  58. * Session
  59. *
  60. * @var Zend_Session_Namespace
  61. */
  62. protected $_session;
  63. /**
  64. * Class name for sessions
  65. *
  66. * @var string
  67. */
  68. protected $_sessionClass = 'Zend_Session_Namespace';
  69. /**
  70. * Should the numbers be used or only letters
  71. *
  72. * @var boolean
  73. */
  74. protected $_useNumbers = true;
  75. /**
  76. * Should both cases be used or only lowercase
  77. *
  78. * @var boolean
  79. */
  80. // protected $_useCase = false;
  81. /**
  82. * Session lifetime for the captcha data
  83. *
  84. * @var integer
  85. */
  86. protected $_timeout = 300;
  87. /**#@+
  88. * Error codes
  89. */
  90. const MISSING_VALUE = 'missingValue';
  91. const MISSING_ID = 'missingID';
  92. const BAD_CAPTCHA = 'badCaptcha';
  93. /**#@-*/
  94. /**
  95. * Error messages
  96. * @var array
  97. */
  98. protected $_messageTemplates = array(
  99. self::MISSING_VALUE => 'Empty captcha value',
  100. self::MISSING_ID => 'Captcha ID field is missing',
  101. self::BAD_CAPTCHA => 'Captcha value is wrong',
  102. );
  103. /**
  104. * Length of the word to generate
  105. *
  106. * @var integer
  107. */
  108. protected $_wordlen = 8;
  109. /**
  110. * Retrieve session class to utilize
  111. *
  112. * @return string
  113. */
  114. public function getSessionClass()
  115. {
  116. return $this->_sessionClass;
  117. }
  118. /**
  119. * Set session class for persistence
  120. *
  121. * @param string $_sessionClass
  122. * @return Zend_Captcha_Word
  123. */
  124. public function setSessionClass($_sessionClass)
  125. {
  126. $this->_sessionClass = $_sessionClass;
  127. return $this;
  128. }
  129. /**
  130. * Retrieve word length to use when genrating captcha
  131. *
  132. * @return integer
  133. */
  134. public function getWordlen()
  135. {
  136. return $this->_wordlen;
  137. }
  138. /**
  139. * Set word length of captcha
  140. *
  141. * @param integer $wordlen
  142. * @return Zend_Captcha_Word
  143. */
  144. public function setWordlen($wordlen)
  145. {
  146. $this->_wordlen = $wordlen;
  147. return $this;
  148. }
  149. /**
  150. * Retrieve captcha ID
  151. *
  152. * @return string
  153. */
  154. public function getId ()
  155. {
  156. if (null === $this->_id) {
  157. $this->_setId($this->_generateRandomId());
  158. }
  159. return $this->_id;
  160. }
  161. /**
  162. * Set captcha identifier
  163. *
  164. * @param string $id
  165. * return Zend_Captcha_Word
  166. */
  167. protected function _setId ($id)
  168. {
  169. $this->_id = $id;
  170. return $this;
  171. }
  172. /**
  173. * Set timeout for session token
  174. *
  175. * @param int $ttl
  176. * @return Zend_Captcha_Word
  177. */
  178. public function setTimeout($ttl)
  179. {
  180. $this->_timeout = (int) $ttl;
  181. return $this;
  182. }
  183. /**
  184. * Get session token timeout
  185. *
  186. * @return int
  187. */
  188. public function getTimeout()
  189. {
  190. return $this->_timeout;
  191. }
  192. /**
  193. * Get session object
  194. *
  195. * @return Zend_Session_Namespace
  196. */
  197. public function getSession()
  198. {
  199. if (!isset($this->_session) || (null === $this->_session)) {
  200. $id = $this->getId();
  201. if (!class_exists($this->_sessionClass)) {
  202. require_once 'Zend/Loader.php';
  203. Zend_Loader::loadClass($this->_sessionClass);
  204. }
  205. $this->_session = new $this->_sessionClass('Zend_Form_Captcha_' . $id);
  206. $this->_session->setExpirationHops(1, null, true);
  207. $this->_session->setExpirationSeconds($this->getTimeout());
  208. }
  209. return $this->_session;
  210. }
  211. /**
  212. * Set session namespace object
  213. *
  214. * @param Zend_Session_Namespace $session
  215. * @return Zend_Captcha_Word
  216. */
  217. public function setSession(Zend_Session_Namespace $session)
  218. {
  219. $this->_session = $session;
  220. return $this;
  221. }
  222. /**
  223. * Get captcha word
  224. *
  225. * @return string
  226. */
  227. public function getWord()
  228. {
  229. if (empty($this->_word)) {
  230. $session = $this->getSession();
  231. $this->_word = $session->word;
  232. }
  233. return $this->_word;
  234. }
  235. /**
  236. * Set captcha word
  237. *
  238. * @param string $word
  239. * @return Zend_Captcha_Word
  240. */
  241. protected function _setWord($word)
  242. {
  243. $session = $this->getSession();
  244. $session->word = $word;
  245. $this->_word = $word;
  246. return $this;
  247. }
  248. /**
  249. * Generate new random word
  250. *
  251. * @return string
  252. */
  253. protected function _generateWord()
  254. {
  255. $word = '';
  256. $wordLen = $this->getWordLen();
  257. $vowels = $this->_useNumbers ? self::$VN : self::$V;
  258. $consonants = $this->_useNumbers ? self::$CN : self::$C;
  259. for ($i=0; $i < $wordLen; $i = $i + 2) {
  260. // generate word with mix of vowels and consonants
  261. $consonant = $consonants[array_rand($consonants)];
  262. $vowel = $vowels[array_rand($vowels)];
  263. $word .= $consonant . $vowel;
  264. }
  265. if (strlen($word) > $wordLen) {
  266. $word = substr($word, 0, $wordLen);
  267. }
  268. return $word;
  269. }
  270. /**
  271. * Generate new session ID and new word
  272. *
  273. * @return string session ID
  274. */
  275. public function generate()
  276. {
  277. $this->_session = null;
  278. $id = $this->_generateRandomId();
  279. $this->_setId($id);
  280. $word = $this->_generateWord();
  281. $this->_setWord($word);
  282. return $id;
  283. }
  284. protected function _generateRandomId()
  285. {
  286. return md5(mt_rand(0, 1000) . microtime(true));
  287. }
  288. /**
  289. * Validate the word
  290. *
  291. * @see Zend_Validate_Interface::isValid()
  292. * @param mixed $value
  293. * @return boolean
  294. */
  295. public function isValid($value, $context = null)
  296. {
  297. if (!is_array($value) && !is_array($context)) {
  298. $this->_error(self::MISSING_VALUE);
  299. return false;
  300. }
  301. if (!is_array($value) && is_array($context)) {
  302. $value = $context;
  303. }
  304. $name = $this->getName();
  305. if (isset($value[$name])) {
  306. $value = $value[$name];
  307. }
  308. if (!isset($value['input'])) {
  309. $this->_error(self::MISSING_VALUE);
  310. return false;
  311. }
  312. $input = strtolower($value['input']);
  313. $this->_setValue($input);
  314. if (!isset($value['id'])) {
  315. $this->_error(self::MISSING_ID);
  316. return false;
  317. }
  318. $this->_id = $value['id'];
  319. if ($input !== $this->getWord()) {
  320. $this->_error(self::BAD_CAPTCHA);
  321. return false;
  322. }
  323. return true;
  324. }
  325. /**
  326. * Get captcha decorator
  327. *
  328. * @return string
  329. */
  330. public function getDecorator()
  331. {
  332. return "Captcha_Word";
  333. }
  334. }