PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/www/system/library/Zend/Captcha/Image.php

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