|
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-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 */ |
|
21 |
|
22 /** @see Zend_Captcha_Base */ |
|
23 require_once 'Zend/Captcha/Base.php'; |
|
24 |
|
25 /** |
|
26 * Word-based captcha adapter |
|
27 * |
|
28 * Generates random word which user should recognise |
|
29 * |
|
30 * @category Zend |
|
31 * @package Zend_Captcha |
|
32 * @subpackage Adapter |
|
33 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
34 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
35 * @version $Id: Word.php 21793 2010-04-08 00:51:31Z stas $ |
|
36 */ |
|
37 abstract class Zend_Captcha_Word extends Zend_Captcha_Base |
|
38 { |
|
39 /**#@+ |
|
40 * @var array Character sets |
|
41 */ |
|
42 static $V = array("a", "e", "i", "o", "u", "y"); |
|
43 static $VN = array("a", "e", "i", "o", "u", "y","2","3","4","5","6","7","8","9"); |
|
44 static $C = array("b","c","d","f","g","h","j","k","m","n","p","q","r","s","t","u","v","w","x","z"); |
|
45 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"); |
|
46 /**#@-*/ |
|
47 |
|
48 /** |
|
49 * Random session ID |
|
50 * |
|
51 * @var string |
|
52 */ |
|
53 protected $_id; |
|
54 |
|
55 /** |
|
56 * Generated word |
|
57 * |
|
58 * @var string |
|
59 */ |
|
60 protected $_word; |
|
61 |
|
62 /** |
|
63 * Session |
|
64 * |
|
65 * @var Zend_Session_Namespace |
|
66 */ |
|
67 protected $_session; |
|
68 |
|
69 /** |
|
70 * Class name for sessions |
|
71 * |
|
72 * @var string |
|
73 */ |
|
74 protected $_sessionClass = 'Zend_Session_Namespace'; |
|
75 |
|
76 /** |
|
77 * Should the numbers be used or only letters |
|
78 * |
|
79 * @var boolean |
|
80 */ |
|
81 protected $_useNumbers = true; |
|
82 |
|
83 /** |
|
84 * Should both cases be used or only lowercase |
|
85 * |
|
86 * @var boolean |
|
87 */ |
|
88 // protected $_useCase = false; |
|
89 |
|
90 /** |
|
91 * Session lifetime for the captcha data |
|
92 * |
|
93 * @var integer |
|
94 */ |
|
95 protected $_timeout = 300; |
|
96 |
|
97 /** |
|
98 * Should generate() keep session or create a new one? |
|
99 * |
|
100 * @var boolean |
|
101 */ |
|
102 protected $_keepSession = false; |
|
103 |
|
104 /**#@+ |
|
105 * Error codes |
|
106 */ |
|
107 const MISSING_VALUE = 'missingValue'; |
|
108 const MISSING_ID = 'missingID'; |
|
109 const BAD_CAPTCHA = 'badCaptcha'; |
|
110 /**#@-*/ |
|
111 |
|
112 /** |
|
113 * Error messages |
|
114 * @var array |
|
115 */ |
|
116 protected $_messageTemplates = array( |
|
117 self::MISSING_VALUE => 'Empty captcha value', |
|
118 self::MISSING_ID => 'Captcha ID field is missing', |
|
119 self::BAD_CAPTCHA => 'Captcha value is wrong', |
|
120 ); |
|
121 |
|
122 /** |
|
123 * Length of the word to generate |
|
124 * |
|
125 * @var integer |
|
126 */ |
|
127 protected $_wordlen = 8; |
|
128 |
|
129 /** |
|
130 * Retrieve session class to utilize |
|
131 * |
|
132 * @return string |
|
133 */ |
|
134 public function getSessionClass() |
|
135 { |
|
136 return $this->_sessionClass; |
|
137 } |
|
138 |
|
139 /** |
|
140 * Set session class for persistence |
|
141 * |
|
142 * @param string $_sessionClass |
|
143 * @return Zend_Captcha_Word |
|
144 */ |
|
145 public function setSessionClass($_sessionClass) |
|
146 { |
|
147 $this->_sessionClass = $_sessionClass; |
|
148 return $this; |
|
149 } |
|
150 |
|
151 /** |
|
152 * Retrieve word length to use when genrating captcha |
|
153 * |
|
154 * @return integer |
|
155 */ |
|
156 public function getWordlen() |
|
157 { |
|
158 return $this->_wordlen; |
|
159 } |
|
160 |
|
161 /** |
|
162 * Set word length of captcha |
|
163 * |
|
164 * @param integer $wordlen |
|
165 * @return Zend_Captcha_Word |
|
166 */ |
|
167 public function setWordlen($wordlen) |
|
168 { |
|
169 $this->_wordlen = $wordlen; |
|
170 return $this; |
|
171 } |
|
172 |
|
173 /** |
|
174 * Retrieve captcha ID |
|
175 * |
|
176 * @return string |
|
177 */ |
|
178 public function getId () |
|
179 { |
|
180 if (null === $this->_id) { |
|
181 $this->_setId($this->_generateRandomId()); |
|
182 } |
|
183 return $this->_id; |
|
184 } |
|
185 |
|
186 /** |
|
187 * Set captcha identifier |
|
188 * |
|
189 * @param string $id |
|
190 * return Zend_Captcha_Word |
|
191 */ |
|
192 protected function _setId ($id) |
|
193 { |
|
194 $this->_id = $id; |
|
195 return $this; |
|
196 } |
|
197 |
|
198 /** |
|
199 * Set timeout for session token |
|
200 * |
|
201 * @param int $ttl |
|
202 * @return Zend_Captcha_Word |
|
203 */ |
|
204 public function setTimeout($ttl) |
|
205 { |
|
206 $this->_timeout = (int) $ttl; |
|
207 return $this; |
|
208 } |
|
209 |
|
210 /** |
|
211 * Get session token timeout |
|
212 * |
|
213 * @return int |
|
214 */ |
|
215 public function getTimeout() |
|
216 { |
|
217 return $this->_timeout; |
|
218 } |
|
219 |
|
220 /** |
|
221 * Sets if session should be preserved on generate() |
|
222 * |
|
223 * @param $keepSession Should session be kept on generate()? |
|
224 * @return Zend_Captcha_Word |
|
225 */ |
|
226 public function setKeepSession($keepSession) |
|
227 { |
|
228 $this->_keepSession = $keepSession; |
|
229 return $this; |
|
230 } |
|
231 |
|
232 /** |
|
233 * Numbers should be included in the pattern? |
|
234 * |
|
235 * @return bool |
|
236 */ |
|
237 public function getUseNumbers() |
|
238 { |
|
239 return $this->_useNumbers; |
|
240 } |
|
241 |
|
242 /** |
|
243 * Set if numbers should be included in the pattern |
|
244 * |
|
245 * @param $_useNumbers numbers should be included in the pattern? |
|
246 * @return Zend_Captcha_Word |
|
247 */ |
|
248 public function setUseNumbers($_useNumbers) |
|
249 { |
|
250 $this->_useNumbers = $_useNumbers; |
|
251 return $this; |
|
252 } |
|
253 |
|
254 /** |
|
255 * Get session object |
|
256 * |
|
257 * @return Zend_Session_Namespace |
|
258 */ |
|
259 public function getSession() |
|
260 { |
|
261 if (!isset($this->_session) || (null === $this->_session)) { |
|
262 $id = $this->getId(); |
|
263 if (!class_exists($this->_sessionClass)) { |
|
264 require_once 'Zend/Loader.php'; |
|
265 Zend_Loader::loadClass($this->_sessionClass); |
|
266 } |
|
267 $this->_session = new $this->_sessionClass('Zend_Form_Captcha_' . $id); |
|
268 $this->_session->setExpirationHops(1, null, true); |
|
269 $this->_session->setExpirationSeconds($this->getTimeout()); |
|
270 } |
|
271 return $this->_session; |
|
272 } |
|
273 |
|
274 /** |
|
275 * Set session namespace object |
|
276 * |
|
277 * @param Zend_Session_Namespace $session |
|
278 * @return Zend_Captcha_Word |
|
279 */ |
|
280 public function setSession(Zend_Session_Namespace $session) |
|
281 { |
|
282 $this->_session = $session; |
|
283 if($session) { |
|
284 $this->_keepSession = true; |
|
285 } |
|
286 return $this; |
|
287 } |
|
288 |
|
289 /** |
|
290 * Get captcha word |
|
291 * |
|
292 * @return string |
|
293 */ |
|
294 public function getWord() |
|
295 { |
|
296 if (empty($this->_word)) { |
|
297 $session = $this->getSession(); |
|
298 $this->_word = $session->word; |
|
299 } |
|
300 return $this->_word; |
|
301 } |
|
302 |
|
303 /** |
|
304 * Set captcha word |
|
305 * |
|
306 * @param string $word |
|
307 * @return Zend_Captcha_Word |
|
308 */ |
|
309 protected function _setWord($word) |
|
310 { |
|
311 $session = $this->getSession(); |
|
312 $session->word = $word; |
|
313 $this->_word = $word; |
|
314 return $this; |
|
315 } |
|
316 |
|
317 /** |
|
318 * Generate new random word |
|
319 * |
|
320 * @return string |
|
321 */ |
|
322 protected function _generateWord() |
|
323 { |
|
324 $word = ''; |
|
325 $wordLen = $this->getWordLen(); |
|
326 $vowels = $this->_useNumbers ? self::$VN : self::$V; |
|
327 $consonants = $this->_useNumbers ? self::$CN : self::$C; |
|
328 |
|
329 for ($i=0; $i < $wordLen; $i = $i + 2) { |
|
330 // generate word with mix of vowels and consonants |
|
331 $consonant = $consonants[array_rand($consonants)]; |
|
332 $vowel = $vowels[array_rand($vowels)]; |
|
333 $word .= $consonant . $vowel; |
|
334 } |
|
335 |
|
336 if (strlen($word) > $wordLen) { |
|
337 $word = substr($word, 0, $wordLen); |
|
338 } |
|
339 |
|
340 return $word; |
|
341 } |
|
342 |
|
343 /** |
|
344 * Generate new session ID and new word |
|
345 * |
|
346 * @return string session ID |
|
347 */ |
|
348 public function generate() |
|
349 { |
|
350 if(!$this->_keepSession) { |
|
351 $this->_session = null; |
|
352 } |
|
353 $id = $this->_generateRandomId(); |
|
354 $this->_setId($id); |
|
355 $word = $this->_generateWord(); |
|
356 $this->_setWord($word); |
|
357 return $id; |
|
358 } |
|
359 |
|
360 protected function _generateRandomId() |
|
361 { |
|
362 return md5(mt_rand(0, 1000) . microtime(true)); |
|
363 } |
|
364 |
|
365 /** |
|
366 * Validate the word |
|
367 * |
|
368 * @see Zend_Validate_Interface::isValid() |
|
369 * @param mixed $value |
|
370 * @return boolean |
|
371 */ |
|
372 public function isValid($value, $context = null) |
|
373 { |
|
374 if (!is_array($value) && !is_array($context)) { |
|
375 $this->_error(self::MISSING_VALUE); |
|
376 return false; |
|
377 } |
|
378 if (!is_array($value) && is_array($context)) { |
|
379 $value = $context; |
|
380 } |
|
381 |
|
382 $name = $this->getName(); |
|
383 |
|
384 if (isset($value[$name])) { |
|
385 $value = $value[$name]; |
|
386 } |
|
387 |
|
388 if (!isset($value['input'])) { |
|
389 $this->_error(self::MISSING_VALUE); |
|
390 return false; |
|
391 } |
|
392 $input = strtolower($value['input']); |
|
393 $this->_setValue($input); |
|
394 |
|
395 if (!isset($value['id'])) { |
|
396 $this->_error(self::MISSING_ID); |
|
397 return false; |
|
398 } |
|
399 |
|
400 $this->_id = $value['id']; |
|
401 if ($input !== $this->getWord()) { |
|
402 $this->_error(self::BAD_CAPTCHA); |
|
403 return false; |
|
404 } |
|
405 |
|
406 return true; |
|
407 } |
|
408 |
|
409 /** |
|
410 * Get captcha decorator |
|
411 * |
|
412 * @return string |
|
413 */ |
|
414 public function getDecorator() |
|
415 { |
|
416 return "Captcha_Word"; |
|
417 } |
|
418 } |