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.
16
* @package Zend_Captcha
18
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
19
* @license http://framework.zend.com/license/new-bsd New BSD License
22
/** Zend_Captcha_Word */
23
require_once 'Zend/Captcha/Word.php';
26
* Image-based captcha element
28
* Generates image displaying random word
31
* @package Zend_Captcha
33
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
34
* @license http://framework.zend.com/license/new-bsd New BSD License
37
class Zend_Captcha_Image extends Zend_Captcha_Word
40
* Directory for generated images
44
protected $_imgDir = "./images/captcha/";
47
* URL for accessing images
51
protected $_imgUrl = "/images/captcha/";
54
* Image's alt tag content
58
protected $_imgAlt = "";
61
* Image suffix (including dot)
65
protected $_suffix = ".png";
72
protected $_width = 200;
79
protected $_height = 50;
86
protected $_fsize = 24;
96
* Image to use as starting point
97
* Default is blank image. If ptovided, should be PNG image.
101
protected $_startImage;
103
* How frequently to execute garbage collection
107
protected $_gcFreq = 10;
110
* How long to keep generated images
114
protected $_expiration = 600;
117
* Number of noise dots on image
118
* Used twice - before and after transform
122
protected $_dotNoiseLevel = 100;
124
* Number of noise lines on image
125
* Used twice - before and after transform
129
protected $_lineNoiseLevel = 5;
133
public function getImgAlt ()
135
return $this->_imgAlt;
140
public function getStartImage ()
142
return $this->_startImage;
147
public function getDotNoiseLevel ()
149
return $this->_dotNoiseLevel;
154
public function getLineNoiseLevel ()
156
return $this->_lineNoiseLevel;
159
* Get captcha expiration
163
public function getExpiration()
165
return $this->_expiration;
169
* Get garbage collection frequency
173
public function getGcFreq()
175
return $this->_gcFreq;
178
* Get font to use when generating captcha
182
public function getFont()
192
public function getFontSize()
194
return $this->_fsize;
198
* Get captcha image height
202
public function getHeight()
204
return $this->_height;
208
* Get captcha image directory
212
public function getImgDir()
214
return $this->_imgDir;
217
* Get captcha image base URL
221
public function getImgUrl()
223
return $this->_imgUrl;
226
* Get captcha image file suffix
230
public function getSuffix()
232
return $this->_suffix;
235
* Get captcha image width
239
public function getWidth()
241
return $this->_width;
244
* @param string $startImage
246
public function setStartImage ($startImage)
248
$this->_startImage = $startImage;
252
* @param int $dotNoiseLevel
254
public function setDotNoiseLevel ($dotNoiseLevel)
256
$this->_dotNoiseLevel = $dotNoiseLevel;
260
* @param int $lineNoiseLevel
262
public function setLineNoiseLevel ($lineNoiseLevel)
264
$this->_lineNoiseLevel = $lineNoiseLevel;
269
* Set captcha expiration
271
* @param int $expiration
272
* @return Zend_Captcha_Image
274
public function setExpiration($expiration)
276
$this->_expiration = $expiration;
281
* Set garbage collection frequency
284
* @return Zend_Captcha_Image
286
public function setGcFreq($gcFreq)
288
$this->_gcFreq = $gcFreq;
295
* @param string $font
296
* @return Zend_Captcha_Image
298
public function setFont($font)
300
$this->_font = $font;
305
* Set captcha font size
308
* @return Zend_Captcha_Image
310
public function setFontSize($fsize)
312
$this->_fsize = $fsize;
317
* Set captcha image height
320
* @return Zend_Captcha_Image
322
public function setHeight($height)
324
$this->_height = $height;
329
* Set captcha image storage directory
331
* @param string $imgDir
332
* @return Zend_Captcha_Image
334
public function setImgDir($imgDir)
336
$this->_imgDir = rtrim($imgDir, "/\\") . '/';
341
* Set captcha image base URL
343
* @param string $imgUrl
344
* @return Zend_Captcha_Image
346
public function setImgUrl($imgUrl)
348
$this->_imgUrl = rtrim($imgUrl, "/\\") . '/';
352
* @param string $imgAlt
354
public function setImgAlt ($imgAlt)
356
$this->_imgAlt = $imgAlt;
361
* Set captch image filename suffix
363
* @param string $suffix
364
* @return Zend_Captcha_Image
366
public function setSuffix($suffix)
368
$this->_suffix = $suffix;
373
* Set captcha image width
376
* @return Zend_Captcha_Image
378
public function setWidth($width)
380
$this->_width = $width;
385
* Generate random frequency
389
protected function _randomFreq()
391
return mt_rand(700000, 1000000) / 15000000;
395
* Generate random phase
399
protected function _randomPhase()
401
// random phase from 0 to pi
402
return mt_rand(0, 3141592) / 1000000;
406
* Generate random character size
410
protected function _randomSize()
412
return mt_rand(300, 700) / 100;
418
* @return string captcha ID
420
public function generate()
422
$id = parent::generate();
423
$this->_generateImage($id, $this->getWord());
425
if (mt_rand(0, $this->getGcFreq()) == 1) {
432
* Generate image captcha
434
* Override this function if you want different image generator
435
* Wave transform from http://www.captcha.ru/captchas/multiwave/
437
* @param string $id Captcha ID
438
* @param string $word Captcha word
440
protected function _generateImage($id, $word)
442
if (!extension_loaded("gd")) {
443
require_once 'Zend/Captcha/Exception.php';
444
throw new Zend_Captcha_Exception("Image CAPTCHA requires GD extension");
447
if (!function_exists("imagepng")) {
448
require_once 'Zend/Captcha/Exception.php';
449
throw new Zend_Captcha_Exception("Image CAPTCHA requires PNG support");
452
if (!function_exists("imageftbbox")) {
453
require_once 'Zend/Captcha/Exception.php';
454
throw new Zend_Captcha_Exception("Image CAPTCHA requires FT fonts support");
457
$font = $this->getFont();
460
require_once 'Zend/Captcha/Exception.php';
461
throw new Zend_Captcha_Exception("Image CAPTCHA requires font");
464
$w = $this->getWidth();
465
$h = $this->getHeight();
466
$fsize = $this->getFontSize();
468
$img_file = $this->getImgDir() . $id . $this->getSuffix();
469
if(empty($this->_startImage)) {
470
$img = imagecreatetruecolor($w, $h);
472
$img = imagecreatefrompng($this->_startImage);
474
require_once 'Zend/Captcha/Exception.php';
475
throw new Zend_Captcha_Exception("Can not load start image");
480
$text_color = imagecolorallocate($img, 0, 0, 0);
481
$bg_color = imagecolorallocate($img, 255, 255, 255);
482
imagefilledrectangle($img, 0, 0, $w-1, $h-1, $bg_color);
483
$textbox = imageftbbox($fsize, 0, $font, $word);
484
$x = ($w - ($textbox[2] - $textbox[0])) / 2;
485
$y = ($h - ($textbox[7] - $textbox[1])) / 2;
486
imagefttext($img, $fsize, 0, $x, $y, $text_color, $font, $word);
489
for ($i=0; $i<$this->_dotNoiseLevel; $i++) {
490
imagefilledellipse($img, mt_rand(0,$w), mt_rand(0,$h), 2, 2, $text_color);
492
for($i=0; $i<$this->_lineNoiseLevel; $i++) {
493
imageline($img, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), mt_rand(0,$h), $text_color);
497
$img2 = imagecreatetruecolor($w, $h);
498
$bg_color = imagecolorallocate($img2, 255, 255, 255);
499
imagefilledrectangle($img2, 0, 0, $w-1, $h-1, $bg_color);
500
// apply wave transforms
501
$freq1 = $this->_randomFreq();
502
$freq2 = $this->_randomFreq();
503
$freq3 = $this->_randomFreq();
504
$freq4 = $this->_randomFreq();
506
$ph1 = $this->_randomPhase();
507
$ph2 = $this->_randomPhase();
508
$ph3 = $this->_randomPhase();
509
$ph4 = $this->_randomPhase();
511
$szx = $this->_randomSize();
512
$szy = $this->_randomSize();
514
for ($x = 0; $x < $w; $x++) {
515
for ($y = 0; $y < $h; $y++) {
516
$sx = $x + (sin($x*$freq1 + $ph1) + sin($y*$freq3 + $ph3)) * $szx;
517
$sy = $y + (sin($x*$freq2 + $ph2) + sin($y*$freq4 + $ph4)) * $szy;
519
if ($sx < 0 || $sy < 0 || $sx >= $w - 1 || $sy >= $h - 1) {
522
$color = (imagecolorat($img, $sx, $sy) >> 16) & 0xFF;
523
$color_x = (imagecolorat($img, $sx + 1, $sy) >> 16) & 0xFF;
524
$color_y = (imagecolorat($img, $sx, $sy + 1) >> 16) & 0xFF;
525
$color_xy = (imagecolorat($img, $sx + 1, $sy + 1) >> 16) & 0xFF;
527
if ($color == 255 && $color_x == 255 && $color_y == 255 && $color_xy == 255) {
530
} elseif ($color == 0 && $color_x == 0 && $color_y == 0 && $color_xy == 0) {
531
// transfer inside of the image as-is
534
// do antialiasing for border items
535
$frac_x = $sx-floor($sx);
536
$frac_y = $sy-floor($sy);
537
$frac_x1 = 1-$frac_x;
538
$frac_y1 = 1-$frac_y;
540
$newcolor = $color * $frac_x1 * $frac_y1
541
+ $color_x * $frac_x * $frac_y1
542
+ $color_y * $frac_x1 * $frac_y
543
+ $color_xy * $frac_x * $frac_y;
545
imagesetpixel($img2, $x, $y, imagecolorallocate($img2, $newcolor, $newcolor, $newcolor));
550
for ($i=0; $i<$this->_dotNoiseLevel; $i++) {
551
imagefilledellipse($img2, mt_rand(0,$w), mt_rand(0,$h), 2, 2, $text_color);
553
for ($i=0; $i<$this->_lineNoiseLevel; $i++) {
554
imageline($img2, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), mt_rand(0,$h), $text_color);
557
imagepng($img2, $img_file);
563
* Remove old files from image directory
566
protected function _gc()
568
$expire = time() - $this->getExpiration();
569
foreach (new DirectoryIterator($this->getImgDir()) as $file) {
570
if (!$file->isDot() && !$file->isDir()) {
571
if ($file->getMTime() < $expire) {
572
unlink($file->getPathname());
579
* Display the captcha
581
* @param Zend_View $view
582
* @param mixed $element
585
public function render(Zend_View_Interface $view, $element = null)
587
return '<img alt="'.$this->getImgAlt().'" src="' . $this->getImgUrl() . $this->getId() . $this->getSuffix() . '"/><br/>';