PageRenderTime 52ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/core/Mage/Captcha/Model/Zend.php

https://bitbucket.org/jokusafet/magento2
PHP | 539 lines | 241 code | 55 blank | 243 comment | 38 complexity | 0553b1d5ffdc97d1c43519d8829cc4b2 MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  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@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Captcha
  23. * @copyright Copyright (c) 2012 X.commerce, Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Implementation of Zend_Captcha
  28. *
  29. * @category Mage
  30. * @package Mage_Captcha
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_Captcha_Model_Zend extends Zend_Captcha_Image implements Mage_Captcha_Model_Interface
  34. {
  35. /**
  36. * Key in session for captcha code
  37. */
  38. const SESSION_WORD = 'word';
  39. /**
  40. * Min captcha lengths default value
  41. */
  42. const DEFAULT_WORD_LENGTH_FROM = 3;
  43. /**
  44. * Max captcha lengths default value
  45. */
  46. const DEFAULT_WORD_LENGTH_TO = 5;
  47. /**
  48. * Helper Instance
  49. * @var Mage_Captcha_Helper_Data
  50. */
  51. protected $_helper = null;
  52. /**
  53. * Captcha expire time
  54. * @var int
  55. */
  56. protected $_expiration;
  57. /**
  58. * Override default value to prevent a captcha cut off
  59. * @var int
  60. * @see Zend_Captcha_Image::$_fsize
  61. */
  62. protected $_fsize = 22;
  63. /**
  64. * Captcha form id
  65. * @var string
  66. */
  67. protected $_formId;
  68. /**
  69. * @var Mage_Captcha_Model_Resource_Log
  70. */
  71. protected $_resourceModel;
  72. /**
  73. * @var
  74. */
  75. protected $_session;
  76. /**
  77. * Zend captcha constructor
  78. *
  79. * @param array $params
  80. */
  81. public function __construct($params)
  82. {
  83. if (!is_array($params) || !isset($params['formId'])) {
  84. throw new Exception('formId is mandatory');
  85. }
  86. $this->_formId = $params['formId'];
  87. $this->_helper = isset($params['helper']) ? $params['helper'] : null;
  88. $this->_resourceModel = isset($params['resourceModel']) ? $params['resourceModel'] : null;
  89. $this->_session = isset($params['session']) ? $params['session'] : null;
  90. }
  91. /**
  92. * Returns key with respect of current form ID
  93. *
  94. * @param string $key
  95. * @return string
  96. */
  97. protected function _getFormIdKey($key)
  98. {
  99. return $this->_formId . '_' . $key;
  100. }
  101. /**
  102. * Get Block Name
  103. *
  104. * @return string
  105. */
  106. public function getBlockName()
  107. {
  108. return 'Mage_Captcha_Block_Captcha_Zend';
  109. }
  110. /**
  111. * Whether captcha is required to be inserted to this form
  112. *
  113. * @param null|string $login
  114. * @return bool
  115. */
  116. public function isRequired($login = null)
  117. {
  118. if ($this->_isUserAuth() || !$this->_isEnabled() || !in_array($this->_formId, $this->_getTargetForms())) {
  119. return false;
  120. }
  121. return ($this->_isShowAlways() || $this->_isOverLimitAttempts($login)
  122. || $this->getSession()->getData($this->_getFormIdKey('show_captcha'))
  123. );
  124. }
  125. /**
  126. * Check is overlimit attempts
  127. *
  128. * @param string $login
  129. * @return bool
  130. */
  131. protected function _isOverLimitAttempts($login)
  132. {
  133. return ($this->_isOverLimitIpAttempt() || $this->_isOverLimitLoginAttempts($login));
  134. }
  135. /**
  136. * Returns number of allowed attempts for same login
  137. *
  138. * @return int
  139. */
  140. protected function _getAllowedAttemptsForSameLogin()
  141. {
  142. return (int)$this->_getHelper()->getConfigNode('failed_attempts_login');
  143. }
  144. /**
  145. * Returns number of allowed attempts from same IP
  146. *
  147. * @return int
  148. */
  149. protected function _getAllowedAttemptsFromSameIp()
  150. {
  151. return (int)$this->_getHelper()->getConfigNode('failed_attempts_ip');
  152. }
  153. /**
  154. * Check is overlimit saved attempts from one ip
  155. *
  156. * @return bool
  157. */
  158. protected function _isOverLimitIpAttempt()
  159. {
  160. $countAttemptsByIp = $this->_getResourceModel()->countAttemptsByRemoteAddress();
  161. return $countAttemptsByIp >= $this->_getAllowedAttemptsFromSameIp();
  162. }
  163. /**
  164. * Is Over Limit Login Attempts
  165. *
  166. * @param string $login
  167. * @return bool
  168. */
  169. protected function _isOverLimitLoginAttempts($login)
  170. {
  171. if ($login != false) {
  172. $countAttemptsByLogin = $this->_getResourceModel()->countAttemptsByUserLogin($login);
  173. return ($countAttemptsByLogin >= $this->_getAllowedAttemptsForSameLogin());
  174. }
  175. return false;
  176. }
  177. /**
  178. * Check is user auth
  179. *
  180. * @return bool
  181. */
  182. protected function _isUserAuth()
  183. {
  184. return $this->getSession()->isLoggedIn();
  185. }
  186. /**
  187. * Whether to respect case while checking the answer
  188. *
  189. * @return bool
  190. */
  191. public function isCaseSensitive()
  192. {
  193. return (string)$this->_getHelper()->getConfigNode('case_sensitive');
  194. }
  195. /**
  196. * Get font to use when generating captcha
  197. *
  198. * @return string
  199. */
  200. public function getFont()
  201. {
  202. $font = (string)$this->_getHelper()->getConfigNode('font');
  203. $fonts = $this->_getHelper()->getFonts();
  204. if (isset($fonts[$font])) {
  205. $fontPath = $fonts[$font]['path'];
  206. } else {
  207. $fontData = array_shift($fonts);
  208. $fontPath = $fontData['path'];
  209. }
  210. return $fontPath;
  211. }
  212. /**
  213. * After this time isCorrect() is going to return FALSE even if word was guessed correctly
  214. *
  215. * @return int
  216. */
  217. public function getExpiration()
  218. {
  219. if (!$this->_expiration) {
  220. /**
  221. * as "timeout" configuration parameter specifies timeout in minutes - we multiply it on 60 to set
  222. * expiration in seconds
  223. */
  224. $this->_expiration = (int)$this->_getHelper()->getConfigNode('timeout') * 60;
  225. }
  226. return $this->_expiration;
  227. }
  228. /**
  229. * Get timeout for session token
  230. *
  231. * @return int
  232. */
  233. public function getTimeout()
  234. {
  235. return $this->getExpiration();
  236. }
  237. /**
  238. * Get captcha image directory
  239. *
  240. * @return string
  241. */
  242. public function getImgDir()
  243. {
  244. return $this->_getHelper()->getImgDir();
  245. }
  246. /**
  247. * Get captcha image base URL
  248. *
  249. * @return string
  250. */
  251. public function getImgUrl()
  252. {
  253. return $this->_getHelper()->getImgUrl();
  254. }
  255. /**
  256. * Checks whether captcha was guessed correctly by user
  257. *
  258. * @param string $word
  259. * @return bool
  260. */
  261. public function isCorrect($word)
  262. {
  263. $storedWord = $this->getWord();
  264. $this->_clearWord();
  265. if (!$word || !$storedWord){
  266. return false;
  267. }
  268. if (!$this->isCaseSensitive()) {
  269. $storedWord = strtolower($storedWord);
  270. $word = strtolower($word);
  271. }
  272. return $word === $storedWord;
  273. }
  274. /**
  275. * Returns session instance
  276. *
  277. * @return Mage_Customer_Model_Session|Mage_Backend_Model_Auth_Session
  278. */
  279. public function getSession()
  280. {
  281. if (empty($this->_session)) {
  282. $this->_session = Mage::app()->getStore()->isAdmin()
  283. ? Mage::getSingleton('Mage_Backend_Model_Auth_Session')
  284. : Mage::getSingleton('Mage_Customer_Model_Session');
  285. }
  286. return $this->_session;
  287. }
  288. /**
  289. * Return full URL to captcha image
  290. *
  291. * @return string
  292. */
  293. public function getImgSrc()
  294. {
  295. return $this->getImgUrl() . $this->getId() . $this->getSuffix();
  296. }
  297. /**
  298. * log Attempt
  299. *
  300. * @param string $login
  301. * @return Mage_Captcha_Model_Zend
  302. */
  303. public function logAttempt($login)
  304. {
  305. if ($this->_isEnabled() && in_array($this->_formId, $this->_getTargetForms())) {
  306. $this->_getResourceModel()->logAttempt($login);
  307. if ($this->_isOverLimitLoginAttempts($login)) {
  308. $this->getSession()->setData($this->_getFormIdKey('show_captcha'), 1);
  309. }
  310. }
  311. return $this;
  312. }
  313. /**
  314. * Returns captcha helper
  315. *
  316. * @return Mage_Captcha_Helper_Data
  317. */
  318. protected function _getHelper()
  319. {
  320. if (empty($this->_helper)) {
  321. $this->_helper = Mage::helper('Mage_Captcha_Helper_Data');
  322. }
  323. return $this->_helper;
  324. }
  325. /**
  326. * Generate word used for captcha render
  327. *
  328. * @return string
  329. */
  330. protected function _generateWord()
  331. {
  332. $word = '';
  333. $symbols = $this->_getSymbols();
  334. $wordLen = $this->_getWordLen();
  335. for ($i = 0; $i < $wordLen; $i++) {
  336. $word .= $symbols[array_rand($symbols)];
  337. }
  338. return $word;
  339. }
  340. /**
  341. * Get symbols array to use for word generation
  342. *
  343. * @return array
  344. */
  345. protected function _getSymbols()
  346. {
  347. return str_split((string)$this->_getHelper()->getConfigNode('symbols'));
  348. }
  349. /**
  350. * Returns length for generating captcha word. This value may be dynamic.
  351. *
  352. * @return int
  353. */
  354. protected function _getWordLen()
  355. {
  356. $from = 0;
  357. $to = 0;
  358. $length = (string)$this->_getHelper()->getConfigNode('length');
  359. if (!is_numeric($length)) {
  360. if (preg_match('/(\d+)-(\d+)/', $length, $matches)) {
  361. $from = (int)$matches[1];
  362. $to = (int)$matches[2];
  363. }
  364. } else {
  365. $from = (int)$length;
  366. $to = (int)$length;
  367. }
  368. if (($to < $from) || ($from < 1) || ($to < 1)) {
  369. $from = self::DEFAULT_WORD_LENGTH_FROM;
  370. $to = self::DEFAULT_WORD_LENGTH_TO;
  371. }
  372. return mt_rand($from, $to);
  373. }
  374. /**
  375. * Whether to show captcha for this form every time
  376. *
  377. * @return bool
  378. */
  379. protected function _isShowAlways()
  380. {
  381. if ((string)$this->_getHelper()->getConfigNode('mode') == Mage_Captcha_Helper_Data::MODE_ALWAYS) {
  382. return true;
  383. }
  384. if ((string)$this->_getHelper()->getConfigNode('mode') == Mage_Captcha_Helper_Data::MODE_AFTER_FAIL
  385. && $this->_getAllowedAttemptsForSameLogin() == 0
  386. ) {
  387. return true;
  388. }
  389. $alwaysFor = $this->_getHelper()->getConfigNode('always_for');
  390. foreach ($alwaysFor as $nodeFormId => $isAlwaysFor) {
  391. if ($isAlwaysFor && $this->_formId == $nodeFormId) {
  392. return true;
  393. }
  394. }
  395. return false;
  396. }
  397. /**
  398. * Whether captcha is enabled at this area
  399. *
  400. * @return bool
  401. */
  402. protected function _isEnabled()
  403. {
  404. return (string)$this->_getHelper()->getConfigNode('enable');
  405. }
  406. /**
  407. * Retrieve list of forms where captcha must be shown
  408. *
  409. * For frontend this list is based on current website
  410. *
  411. * @return array
  412. */
  413. protected function _getTargetForms()
  414. {
  415. $formsString = (string) $this->_getHelper()->getConfigNode('forms');
  416. return explode(',', $formsString);
  417. }
  418. /**
  419. * Get captcha word
  420. *
  421. * @return string
  422. */
  423. public function getWord()
  424. {
  425. $sessionData = $this->getSession()->getData($this->_getFormIdKey(self::SESSION_WORD));
  426. return time() < $sessionData['expires'] ? $sessionData['data'] : null;
  427. }
  428. /**
  429. * Set captcha word
  430. *
  431. * @param string $word
  432. * @return Zend_Captcha_Word
  433. */
  434. protected function _setWord($word)
  435. {
  436. $this->getSession()->setData($this->_getFormIdKey(self::SESSION_WORD),
  437. array('data' => $word, 'expires' => time() + $this->getTimeout())
  438. );
  439. $this->_word = $word;
  440. return $this;
  441. }
  442. /**
  443. * Set captcha word
  444. *
  445. * @return Mage_Captcha_Model_Zend
  446. */
  447. protected function _clearWord()
  448. {
  449. $this->getSession()->unsetData($this->_getFormIdKey(self::SESSION_WORD));
  450. $this->_word = null;
  451. return $this;
  452. }
  453. /**
  454. * Override function to generate less curly captcha that will not cut off
  455. *
  456. * @see Zend_Captcha_Image::_randomSize()
  457. * @return int
  458. */
  459. protected function _randomSize()
  460. {
  461. return mt_rand(280, 300) / 100;
  462. }
  463. /**
  464. * Overlap of the parent method
  465. *
  466. * Now deleting old captcha images make crontab script
  467. * @see Mage_Captcha_Model_Observer::deleteExpiredImages
  468. */
  469. protected function _gc()
  470. {
  471. //do nothing
  472. }
  473. /**
  474. * Get Resource Model
  475. * @return Mage_Captcha_Model_Resource_Log
  476. */
  477. protected function _getResourceModel()
  478. {
  479. if (empty($this->_resourceModel)) {
  480. $this->_resourceModel = Mage::getResourceModel('Mage_Captcha_Model_Resource_Log');
  481. }
  482. return $this->_resourceModel;
  483. }
  484. }