PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/lib/Zend/Captcha/Image.php

https://bitbucket.org/mkrasuski/magento-ce
PHP | 625 lines | 281 code | 52 blank | 292 comment | 47 complexity | 8f1bb1448407f673d986cc387846bf3f MD5 | raw file
  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-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /** @see Zend_Captcha_Word */
  23. #require_once 'Zend/Captcha/Word.php';
  24. /**
  25. * Image-based captcha element
  26. *
  27. * Generates image displaying random word
  28. *
  29. * @category Zend
  30. * @package Zend_Captcha
  31. * @subpackage Adapter
  32. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. class Zend_Captcha_Image extends Zend_Captcha_Word
  36. {
  37. /**
  38. * Directory for generated images
  39. *
  40. * @var string
  41. */
  42. protected $_imgDir = "./images/captcha/";
  43. /**
  44. * URL for accessing images
  45. *
  46. * @var string
  47. */
  48. protected $_imgUrl = "/images/captcha/";
  49. /**
  50. * Image's alt tag content
  51. *
  52. * @var string
  53. */
  54. protected $_imgAlt = "";
  55. /**
  56. * Image suffix (including dot)
  57. *
  58. * @var string
  59. */
  60. protected $_suffix = ".png";
  61. /**
  62. * Image width
  63. *
  64. * @var int
  65. */
  66. protected $_width = 200;
  67. /**
  68. * Image height
  69. *
  70. * @var int
  71. */
  72. protected $_height = 50;
  73. /**
  74. * Font size
  75. *
  76. * @var int
  77. */
  78. protected $_fsize = 24;
  79. /**
  80. * Image font file
  81. *
  82. * @var string
  83. */
  84. protected $_font;
  85. /**
  86. * Image to use as starting point
  87. * Default is blank image. If provided, should be PNG image.
  88. *
  89. * @var string
  90. */
  91. protected $_startImage;
  92. /**
  93. * How frequently to execute garbage collection
  94. *
  95. * @var int
  96. */
  97. protected $_gcFreq = 10;
  98. /**
  99. * How long to keep generated images
  100. *
  101. * @var int
  102. */
  103. protected $_expiration = 600;
  104. /**
  105. * Number of noise dots on image
  106. * Used twice - before and after transform
  107. *
  108. * @var int
  109. */
  110. protected $_dotNoiseLevel = 100;
  111. /**
  112. * Number of noise lines on image
  113. * Used twice - before and after transform
  114. *
  115. * @var int
  116. */
  117. protected $_lineNoiseLevel = 5;
  118. /**
  119. * @return string
  120. */
  121. public function getImgAlt ()
  122. {
  123. return $this->_imgAlt;
  124. }
  125. /**
  126. * @return string
  127. */
  128. public function getStartImage ()
  129. {
  130. return $this->_startImage;
  131. }
  132. /**
  133. * @return int
  134. */
  135. public function getDotNoiseLevel ()
  136. {
  137. return $this->_dotNoiseLevel;
  138. }
  139. /**
  140. * @return int
  141. */
  142. public function getLineNoiseLevel ()
  143. {
  144. return $this->_lineNoiseLevel;
  145. }
  146. /**
  147. * Get captcha expiration
  148. *
  149. * @return int
  150. */
  151. public function getExpiration()
  152. {
  153. return $this->_expiration;
  154. }
  155. /**
  156. * Get garbage collection frequency
  157. *
  158. * @return int
  159. */
  160. public function getGcFreq()
  161. {
  162. return $this->_gcFreq;
  163. }
  164. /**
  165. * Get font to use when generating captcha
  166. *
  167. * @return string
  168. */
  169. public function getFont()
  170. {
  171. return $this->_font;
  172. }
  173. /**
  174. * Get font size
  175. *
  176. * @return int
  177. */
  178. public function getFontSize()
  179. {
  180. return $this->_fsize;
  181. }
  182. /**
  183. * Get captcha image height
  184. *
  185. * @return int
  186. */
  187. public function getHeight()
  188. {
  189. return $this->_height;
  190. }
  191. /**
  192. * Get captcha image directory
  193. *
  194. * @return string
  195. */
  196. public function getImgDir()
  197. {
  198. return $this->_imgDir;
  199. }
  200. /**
  201. * Get captcha image base URL
  202. *
  203. * @return string
  204. */
  205. public function getImgUrl()
  206. {
  207. return $this->_imgUrl;
  208. }
  209. /**
  210. * Get captcha image file suffix
  211. *
  212. * @return string
  213. */
  214. public function getSuffix()
  215. {
  216. return $this->_suffix;
  217. }
  218. /**
  219. * Get captcha image width
  220. *
  221. * @return int
  222. */
  223. public function getWidth()
  224. {
  225. return $this->_width;
  226. }
  227. /**
  228. * Set start image
  229. *
  230. * @param string $startImage
  231. * @return Zend_Captcha_Image
  232. */
  233. public function setStartImage ($startImage)
  234. {
  235. $this->_startImage = $startImage;
  236. return $this;
  237. }
  238. /**
  239. * Set dot noise level
  240. *
  241. * @param int $dotNoiseLevel
  242. * @return Zend_Captcha_Image
  243. */
  244. public function setDotNoiseLevel ($dotNoiseLevel)
  245. {
  246. $this->_dotNoiseLevel = $dotNoiseLevel;
  247. return $this;
  248. }
  249. /**
  250. * Set line noise level
  251. *
  252. * @param int $lineNoiseLevel
  253. * @return Zend_Captcha_Image
  254. */
  255. public function setLineNoiseLevel ($lineNoiseLevel)
  256. {
  257. $this->_lineNoiseLevel = $lineNoiseLevel;
  258. return $this;
  259. }
  260. /**
  261. * Set captcha expiration
  262. *
  263. * @param int $expiration
  264. * @return Zend_Captcha_Image
  265. */
  266. public function setExpiration($expiration)
  267. {
  268. $this->_expiration = $expiration;
  269. return $this;
  270. }
  271. /**
  272. * Set garbage collection frequency
  273. *
  274. * @param int $gcFreq
  275. * @return Zend_Captcha_Image
  276. */
  277. public function setGcFreq($gcFreq)
  278. {
  279. $this->_gcFreq = $gcFreq;
  280. return $this;
  281. }
  282. /**
  283. * Set captcha font
  284. *
  285. * @param string $font
  286. * @return Zend_Captcha_Image
  287. */
  288. public function setFont($font)
  289. {
  290. $this->_font = $font;
  291. return $this;
  292. }
  293. /**
  294. * Set captcha font size
  295. *
  296. * @param int $fsize
  297. * @return Zend_Captcha_Image
  298. */
  299. public function setFontSize($fsize)
  300. {
  301. $this->_fsize = $fsize;
  302. return $this;
  303. }
  304. /**
  305. * Set captcha image height
  306. *
  307. * @param int $height
  308. * @return Zend_Captcha_Image
  309. */
  310. public function setHeight($height)
  311. {
  312. $this->_height = $height;
  313. return $this;
  314. }
  315. /**
  316. * Set captcha image storage directory
  317. *
  318. * @param string $imgDir
  319. * @return Zend_Captcha_Image
  320. */
  321. public function setImgDir($imgDir)
  322. {
  323. $this->_imgDir = rtrim($imgDir, "/\\") . '/';
  324. return $this;
  325. }
  326. /**
  327. * Set captcha image base URL
  328. *
  329. * @param string $imgUrl
  330. * @return Zend_Captcha_Image
  331. */
  332. public function setImgUrl($imgUrl)
  333. {
  334. $this->_imgUrl = rtrim($imgUrl, "/\\") . '/';
  335. return $this;
  336. }
  337. /**
  338. * Set image alternative text
  339. *
  340. * @param string $imgAlt
  341. * @return Zend_Captcha_Image
  342. */
  343. public function setImgAlt ($imgAlt)
  344. {
  345. $this->_imgAlt = $imgAlt;
  346. return $this;
  347. }
  348. /**
  349. * Set captch image filename suffix
  350. *
  351. * @param string $suffix
  352. * @return Zend_Captcha_Image
  353. */
  354. public function setSuffix($suffix)
  355. {
  356. $this->_suffix = $suffix;
  357. return $this;
  358. }
  359. /**
  360. * Set captcha image width
  361. *
  362. * @param int $width
  363. * @return Zend_Captcha_Image
  364. */
  365. public function setWidth($width)
  366. {
  367. $this->_width = $width;
  368. return $this;
  369. }
  370. /**
  371. * Generate random frequency
  372. *
  373. * @return float
  374. */
  375. protected function _randomFreq()
  376. {
  377. return mt_rand(700000, 1000000) / 15000000;
  378. }
  379. /**
  380. * Generate random phase
  381. *
  382. * @return float
  383. */
  384. protected function _randomPhase()
  385. {
  386. // random phase from 0 to pi
  387. return mt_rand(0, 3141592) / 1000000;
  388. }
  389. /**
  390. * Generate random character size
  391. *
  392. * @return int
  393. */
  394. protected function _randomSize()
  395. {
  396. return mt_rand(300, 700) / 100;
  397. }
  398. /**
  399. * Generate captcha
  400. *
  401. * @return string captcha ID
  402. */
  403. public function generate()
  404. {
  405. $id = parent::generate();
  406. $tries = 5;
  407. // If there's already such file, try creating a new ID
  408. while($tries-- && file_exists($this->getImgDir() . $id . $this->getSuffix())) {
  409. $id = $this->_generateRandomId();
  410. $this->_setId($id);
  411. }
  412. $this->_generateImage($id, $this->getWord());
  413. if (mt_rand(1, $this->getGcFreq()) == 1) {
  414. $this->_gc();
  415. }
  416. return $id;
  417. }
  418. /**
  419. * Generate image captcha
  420. *
  421. * Override this function if you want different image generator
  422. * Wave transform from http://www.captcha.ru/captchas/multiwave/
  423. *
  424. * @param string $id Captcha ID
  425. * @param string $word Captcha word
  426. * @throws Zend_Captcha_Exception
  427. */
  428. protected function _generateImage($id, $word)
  429. {
  430. if (!extension_loaded("gd")) {
  431. #require_once 'Zend/Captcha/Exception.php';
  432. throw new Zend_Captcha_Exception("Image CAPTCHA requires GD extension");
  433. }
  434. if (!function_exists("imagepng")) {
  435. #require_once 'Zend/Captcha/Exception.php';
  436. throw new Zend_Captcha_Exception("Image CAPTCHA requires PNG support");
  437. }
  438. if (!function_exists("imageftbbox")) {
  439. #require_once 'Zend/Captcha/Exception.php';
  440. throw new Zend_Captcha_Exception("Image CAPTCHA requires FT fonts support");
  441. }
  442. $font = $this->getFont();
  443. if (empty($font)) {
  444. #require_once 'Zend/Captcha/Exception.php';
  445. throw new Zend_Captcha_Exception("Image CAPTCHA requires font");
  446. }
  447. $w = $this->getWidth();
  448. $h = $this->getHeight();
  449. $fsize = $this->getFontSize();
  450. $img_file = $this->getImgDir() . $id . $this->getSuffix();
  451. if(empty($this->_startImage)) {
  452. $img = imagecreatetruecolor($w, $h);
  453. } else {
  454. $img = imagecreatefrompng($this->_startImage);
  455. if(!$img) {
  456. #require_once 'Zend/Captcha/Exception.php';
  457. throw new Zend_Captcha_Exception("Can not load start image");
  458. }
  459. $w = imagesx($img);
  460. $h = imagesy($img);
  461. }
  462. $text_color = imagecolorallocate($img, 0, 0, 0);
  463. $bg_color = imagecolorallocate($img, 255, 255, 255);
  464. imagefilledrectangle($img, 0, 0, $w-1, $h-1, $bg_color);
  465. $textbox = imageftbbox($fsize, 0, $font, $word);
  466. $x = ($w - ($textbox[2] - $textbox[0])) / 2;
  467. $y = ($h - ($textbox[7] - $textbox[1])) / 2;
  468. imagefttext($img, $fsize, 0, $x, $y, $text_color, $font, $word);
  469. // generate noise
  470. for ($i=0; $i<$this->_dotNoiseLevel; $i++) {
  471. imagefilledellipse($img, mt_rand(0,$w), mt_rand(0,$h), 2, 2, $text_color);
  472. }
  473. for($i=0; $i<$this->_lineNoiseLevel; $i++) {
  474. imageline($img, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), mt_rand(0,$h), $text_color);
  475. }
  476. // transformed image
  477. $img2 = imagecreatetruecolor($w, $h);
  478. $bg_color = imagecolorallocate($img2, 255, 255, 255);
  479. imagefilledrectangle($img2, 0, 0, $w-1, $h-1, $bg_color);
  480. // apply wave transforms
  481. $freq1 = $this->_randomFreq();
  482. $freq2 = $this->_randomFreq();
  483. $freq3 = $this->_randomFreq();
  484. $freq4 = $this->_randomFreq();
  485. $ph1 = $this->_randomPhase();
  486. $ph2 = $this->_randomPhase();
  487. $ph3 = $this->_randomPhase();
  488. $ph4 = $this->_randomPhase();
  489. $szx = $this->_randomSize();
  490. $szy = $this->_randomSize();
  491. for ($x = 0; $x < $w; $x++) {
  492. for ($y = 0; $y < $h; $y++) {
  493. $sx = $x + (sin($x*$freq1 + $ph1) + sin($y*$freq3 + $ph3)) * $szx;
  494. $sy = $y + (sin($x*$freq2 + $ph2) + sin($y*$freq4 + $ph4)) * $szy;
  495. if ($sx < 0 || $sy < 0 || $sx >= $w - 1 || $sy >= $h - 1) {
  496. continue;
  497. } else {
  498. $color = (imagecolorat($img, $sx, $sy) >> 16) & 0xFF;
  499. $color_x = (imagecolorat($img, $sx + 1, $sy) >> 16) & 0xFF;
  500. $color_y = (imagecolorat($img, $sx, $sy + 1) >> 16) & 0xFF;
  501. $color_xy = (imagecolorat($img, $sx + 1, $sy + 1) >> 16) & 0xFF;
  502. }
  503. if ($color == 255 && $color_x == 255 && $color_y == 255 && $color_xy == 255) {
  504. // ignore background
  505. continue;
  506. } elseif ($color == 0 && $color_x == 0 && $color_y == 0 && $color_xy == 0) {
  507. // transfer inside of the image as-is
  508. $newcolor = 0;
  509. } else {
  510. // do antialiasing for border items
  511. $frac_x = $sx-floor($sx);
  512. $frac_y = $sy-floor($sy);
  513. $frac_x1 = 1-$frac_x;
  514. $frac_y1 = 1-$frac_y;
  515. $newcolor = $color * $frac_x1 * $frac_y1
  516. + $color_x * $frac_x * $frac_y1
  517. + $color_y * $frac_x1 * $frac_y
  518. + $color_xy * $frac_x * $frac_y;
  519. }
  520. imagesetpixel($img2, $x, $y, imagecolorallocate($img2, $newcolor, $newcolor, $newcolor));
  521. }
  522. }
  523. // generate noise
  524. for ($i=0; $i<$this->_dotNoiseLevel; $i++) {
  525. imagefilledellipse($img2, mt_rand(0,$w), mt_rand(0,$h), 2, 2, $text_color);
  526. }
  527. for ($i=0; $i<$this->_lineNoiseLevel; $i++) {
  528. imageline($img2, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), mt_rand(0,$h), $text_color);
  529. }
  530. imagepng($img2, $img_file);
  531. imagedestroy($img);
  532. imagedestroy($img2);
  533. }
  534. /**
  535. * Remove old files from image directory
  536. */
  537. protected function _gc()
  538. {
  539. $expire = time() - $this->getExpiration();
  540. $imgdir = $this->getImgDir();
  541. if(!$imgdir || strlen($imgdir) < 2) {
  542. // safety guard
  543. return;
  544. }
  545. $suffixLength = strlen($this->_suffix);
  546. foreach (new DirectoryIterator($imgdir) as $file) {
  547. if (!$file->isDot() && !$file->isDir()) {
  548. if (file_exists($file->getPathname()) && $file->getMTime() < $expire) {
  549. // only deletes files ending with $this->_suffix
  550. if (substr($file->getFilename(), -($suffixLength)) == $this->_suffix) {
  551. unlink($file->getPathname());
  552. }
  553. }
  554. }
  555. }
  556. }
  557. /**
  558. * Display the captcha
  559. *
  560. * @param Zend_View_Interface $view
  561. * @param mixed $element
  562. * @return string
  563. */
  564. public function render(Zend_View_Interface $view = null, $element = null)
  565. {
  566. $endTag = ' />';
  567. if (($view instanceof Zend_View_Abstract) && !$view->doctype()->isXhtml()) {
  568. $endTag = '>';
  569. }
  570. return '<img width="' . $this->getWidth() . '" height="' . $this->getHeight() . '" alt="' . $this->getImgAlt()
  571. . '" src="' . $this->getImgUrl() . $this->getId() . $this->getSuffix() . '"' . $endTag;
  572. }
  573. }