/library/Zend/Captcha/Image.php
PHP | 600 lines | 279 code | 48 blank | 273 comment | 42 complexity | 03ab1bc75a0dd15d0f80e8e63447af83 MD5 | raw file
- <?php
- /**
- * Zend Framework
- *
- * LICENSE
- *
- * This source file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://framework.zend.com/license/new-bsd
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@zend.com so we can send you a copy immediately.
- *
- * @category Zend
- * @package Zend_Captcha
- * @subpackage Adapter
- * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- * @version $Id: Image.php 20096 2010-01-06 02:05:09Z bkarwin $
- */
- /** @see Zend_Captcha_Word */
- require_once 'Zend/Captcha/Word.php';
- /**
- * Image-based captcha element
- *
- * Generates image displaying random word
- *
- * @category Zend
- * @package Zend_Captcha
- * @subpackage Adapter
- * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
- class Zend_Captcha_Image extends Zend_Captcha_Word
- {
- /**
- * Directory for generated images
- *
- * @var string
- */
- protected $_imgDir = "./images/captcha/";
- /**
- * URL for accessing images
- *
- * @var string
- */
- protected $_imgUrl = "/images/captcha/";
- /**
- * Image's alt tag content
- *
- * @var string
- */
- protected $_imgAlt = "";
- /**
- * Image suffix (including dot)
- *
- * @var string
- */
- protected $_suffix = ".png";
- /**
- * Image width
- *
- * @var int
- */
- protected $_width = 200;
- /**
- * Image height
- *
- * @var int
- */
- protected $_height = 50;
- /**
- * Font size
- *
- * @var int
- */
- protected $_fsize = 24;
- /**
- * Image font file
- *
- * @var string
- */
- protected $_font;
- /**
- * Image to use as starting point
- * Default is blank image. If provided, should be PNG image.
- *
- * @var string
- */
- protected $_startImage;
- /**
- * How frequently to execute garbage collection
- *
- * @var int
- */
- protected $_gcFreq = 10;
- /**
- * How long to keep generated images
- *
- * @var int
- */
- protected $_expiration = 600;
- /**
- * Number of noise dots on image
- * Used twice - before and after transform
- *
- * @var int
- */
- protected $_dotNoiseLevel = 100;
- /**
- * Number of noise lines on image
- * Used twice - before and after transform
- *
- * @var int
- */
- protected $_lineNoiseLevel = 5;
- /**
- * @return string
- */
- public function getImgAlt ()
- {
- return $this->_imgAlt;
- }
- /**
- * @return string
- */
- public function getStartImage ()
- {
- return $this->_startImage;
- }
- /**
- * @return int
- */
- public function getDotNoiseLevel ()
- {
- return $this->_dotNoiseLevel;
- }
- /**
- * @return int
- */
- public function getLineNoiseLevel ()
- {
- return $this->_lineNoiseLevel;
- }
- /**
- * Get captcha expiration
- *
- * @return int
- */
- public function getExpiration()
- {
- return $this->_expiration;
- }
- /**
- * Get garbage collection frequency
- *
- * @return int
- */
- public function getGcFreq()
- {
- return $this->_gcFreq;
- }
- /**
- * Get font to use when generating captcha
- *
- * @return string
- */
- public function getFont()
- {
- return $this->_font;
- }
- /**
- * Get font size
- *
- * @return int
- */
- public function getFontSize()
- {
- return $this->_fsize;
- }
- /**
- * Get captcha image height
- *
- * @return int
- */
- public function getHeight()
- {
- return $this->_height;
- }
- /**
- * Get captcha image directory
- *
- * @return string
- */
- public function getImgDir()
- {
- return $this->_imgDir;
- }
- /**
- * Get captcha image base URL
- *
- * @return string
- */
- public function getImgUrl()
- {
- return $this->_imgUrl;
- }
- /**
- * Get captcha image file suffix
- *
- * @return string
- */
- public function getSuffix()
- {
- return $this->_suffix;
- }
- /**
- * Get captcha image width
- *
- * @return int
- */
- public function getWidth()
- {
- return $this->_width;
- }
- /**
- * @param string $startImage
- */
- public function setStartImage ($startImage)
- {
- $this->_startImage = $startImage;
- return $this;
- }
- /**
- * @param int $dotNoiseLevel
- */
- public function setDotNoiseLevel ($dotNoiseLevel)
- {
- $this->_dotNoiseLevel = $dotNoiseLevel;
- return $this;
- }
- /**
- * @param int $lineNoiseLevel
- */
- public function setLineNoiseLevel ($lineNoiseLevel)
- {
- $this->_lineNoiseLevel = $lineNoiseLevel;
- return $this;
- }
- /**
- * Set captcha expiration
- *
- * @param int $expiration
- * @return Zend_Captcha_Image
- */
- public function setExpiration($expiration)
- {
- $this->_expiration = $expiration;
- return $this;
- }
- /**
- * Set garbage collection frequency
- *
- * @param int $gcFreq
- * @return Zend_Captcha_Image
- */
- public function setGcFreq($gcFreq)
- {
- $this->_gcFreq = $gcFreq;
- return $this;
- }
- /**
- * Set captcha font
- *
- * @param string $font
- * @return Zend_Captcha_Image
- */
- public function setFont($font)
- {
- $this->_font = $font;
- return $this;
- }
- /**
- * Set captcha font size
- *
- * @param int $fsize
- * @return Zend_Captcha_Image
- */
- public function setFontSize($fsize)
- {
- $this->_fsize = $fsize;
- return $this;
- }
- /**
- * Set captcha image height
- *
- * @param int $height
- * @return Zend_Captcha_Image
- */
- public function setHeight($height)
- {
- $this->_height = $height;
- return $this;
- }
- /**
- * Set captcha image storage directory
- *
- * @param string $imgDir
- * @return Zend_Captcha_Image
- */
- public function setImgDir($imgDir)
- {
- $this->_imgDir = rtrim($imgDir, "/\\") . '/';
- return $this;
- }
- /**
- * Set captcha image base URL
- *
- * @param string $imgUrl
- * @return Zend_Captcha_Image
- */
- public function setImgUrl($imgUrl)
- {
- $this->_imgUrl = rtrim($imgUrl, "/\\") . '/';
- return $this;
- }
- /**
- * @param string $imgAlt
- */
- public function setImgAlt ($imgAlt)
- {
- $this->_imgAlt = $imgAlt;
- return $this;
- }
- /**
- * Set captch image filename suffix
- *
- * @param string $suffix
- * @return Zend_Captcha_Image
- */
- public function setSuffix($suffix)
- {
- $this->_suffix = $suffix;
- return $this;
- }
- /**
- * Set captcha image width
- *
- * @param int $width
- * @return Zend_Captcha_Image
- */
- public function setWidth($width)
- {
- $this->_width = $width;
- return $this;
- }
- /**
- * Generate random frequency
- *
- * @return float
- */
- protected function _randomFreq()
- {
- return mt_rand(700000, 1000000) / 15000000;
- }
- /**
- * Generate random phase
- *
- * @return float
- */
- protected function _randomPhase()
- {
- // random phase from 0 to pi
- return mt_rand(0, 3141592) / 1000000;
- }
- /**
- * Generate random character size
- *
- * @return int
- */
- protected function _randomSize()
- {
- return mt_rand(300, 700) / 100;
- }
- /**
- * Generate captcha
- *
- * @return string captcha ID
- */
- public function generate()
- {
- $id = parent::generate();
- $tries = 5;
- // If there's already such file, try creating a new ID
- while($tries-- && file_exists($this->getImgDir() . $id . $this->getSuffix())) {
- $id = $this->_generateRandomId();
- $this->_setId($id);
- }
- $this->_generateImage($id, $this->getWord());
- if (mt_rand(1, $this->getGcFreq()) == 1) {
- $this->_gc();
- }
- return $id;
- }
- /**
- * Generate image captcha
- *
- * Override this function if you want different image generator
- * Wave transform from http://www.captcha.ru/captchas/multiwave/
- *
- * @param string $id Captcha ID
- * @param string $word Captcha word
- */
- protected function _generateImage($id, $word)
- {
- if (!extension_loaded("gd")) {
- require_once 'Zend/Captcha/Exception.php';
- throw new Zend_Captcha_Exception("Image CAPTCHA requires GD extension");
- }
- if (!function_exists("imagepng")) {
- require_once 'Zend/Captcha/Exception.php';
- throw new Zend_Captcha_Exception("Image CAPTCHA requires PNG support");
- }
- if (!function_exists("imageftbbox")) {
- require_once 'Zend/Captcha/Exception.php';
- throw new Zend_Captcha_Exception("Image CAPTCHA requires FT fonts support");
- }
- $font = $this->getFont();
- if (empty($font)) {
- require_once 'Zend/Captcha/Exception.php';
- throw new Zend_Captcha_Exception("Image CAPTCHA requires font");
- }
- $w = $this->getWidth();
- $h = $this->getHeight();
- $fsize = $this->getFontSize();
- $img_file = $this->getImgDir() . $id . $this->getSuffix();
- if(empty($this->_startImage)) {
- $img = imagecreatetruecolor($w, $h);
- } else {
- $img = imagecreatefrompng($this->_startImage);
- if(!$img) {
- require_once 'Zend/Captcha/Exception.php';
- throw new Zend_Captcha_Exception("Can not load start image");
- }
- $w = imagesx($img);
- $h = imagesy($img);
- }
- $text_color = imagecolorallocate($img, 0, 0, 0);
- $bg_color = imagecolorallocate($img, 255, 255, 255);
- imagefilledrectangle($img, 0, 0, $w-1, $h-1, $bg_color);
- $textbox = imageftbbox($fsize, 0, $font, $word);
- $x = ($w - ($textbox[2] - $textbox[0])) / 2;
- $y = ($h - ($textbox[7] - $textbox[1])) / 2;
- imagefttext($img, $fsize, 0, $x, $y, $text_color, $font, $word);
- // generate noise
- for ($i=0; $i<$this->_dotNoiseLevel; $i++) {
- imagefilledellipse($img, mt_rand(0,$w), mt_rand(0,$h), 2, 2, $text_color);
- }
- for($i=0; $i<$this->_lineNoiseLevel; $i++) {
- imageline($img, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), mt_rand(0,$h), $text_color);
- }
- // transformed image
- $img2 = imagecreatetruecolor($w, $h);
- $bg_color = imagecolorallocate($img2, 255, 255, 255);
- imagefilledrectangle($img2, 0, 0, $w-1, $h-1, $bg_color);
- // apply wave transforms
- $freq1 = $this->_randomFreq();
- $freq2 = $this->_randomFreq();
- $freq3 = $this->_randomFreq();
- $freq4 = $this->_randomFreq();
- $ph1 = $this->_randomPhase();
- $ph2 = $this->_randomPhase();
- $ph3 = $this->_randomPhase();
- $ph4 = $this->_randomPhase();
- $szx = $this->_randomSize();
- $szy = $this->_randomSize();
- for ($x = 0; $x < $w; $x++) {
- for ($y = 0; $y < $h; $y++) {
- $sx = $x + (sin($x*$freq1 + $ph1) + sin($y*$freq3 + $ph3)) * $szx;
- $sy = $y + (sin($x*$freq2 + $ph2) + sin($y*$freq4 + $ph4)) * $szy;
- if ($sx < 0 || $sy < 0 || $sx >= $w - 1 || $sy >= $h - 1) {
- continue;
- } else {
- $color = (imagecolorat($img, $sx, $sy) >> 16) & 0xFF;
- $color_x = (imagecolorat($img, $sx + 1, $sy) >> 16) & 0xFF;
- $color_y = (imagecolorat($img, $sx, $sy + 1) >> 16) & 0xFF;
- $color_xy = (imagecolorat($img, $sx + 1, $sy + 1) >> 16) & 0xFF;
- }
- if ($color == 255 && $color_x == 255 && $color_y == 255 && $color_xy == 255) {
- // ignore background
- continue;
- } elseif ($color == 0 && $color_x == 0 && $color_y == 0 && $color_xy == 0) {
- // transfer inside of the image as-is
- $newcolor = 0;
- } else {
- // do antialiasing for border items
- $frac_x = $sx-floor($sx);
- $frac_y = $sy-floor($sy);
- $frac_x1 = 1-$frac_x;
- $frac_y1 = 1-$frac_y;
- $newcolor = $color * $frac_x1 * $frac_y1
- + $color_x * $frac_x * $frac_y1
- + $color_y * $frac_x1 * $frac_y
- + $color_xy * $frac_x * $frac_y;
- }
- imagesetpixel($img2, $x, $y, imagecolorallocate($img2, $newcolor, $newcolor, $newcolor));
- }
- }
- // generate noise
- for ($i=0; $i<$this->_dotNoiseLevel; $i++) {
- imagefilledellipse($img2, mt_rand(0,$w), mt_rand(0,$h), 2, 2, $text_color);
- }
- for ($i=0; $i<$this->_lineNoiseLevel; $i++) {
- imageline($img2, mt_rand(0,$w), mt_rand(0,$h), mt_rand(0,$w), mt_rand(0,$h), $text_color);
- }
- imagepng($img2, $img_file);
- imagedestroy($img);
- imagedestroy($img2);
- }
- /**
- * Remove old files from image directory
- *
- */
- protected function _gc()
- {
- $expire = time() - $this->getExpiration();
- $imgdir = $this->getImgDir();
- if(!$imgdir || strlen($imgdir) < 2) {
- // safety guard
- return;
- }
- foreach (new DirectoryIterator($imgdir) as $file) {
- if (!$file->isDot() && !$file->isDir()) {
- if ($file->getMTime() < $expire) {
- unlink($file->getPathname());
- }
- }
- }
- }
- /**
- * Display the captcha
- *
- * @param Zend_View_Interface $view
- * @param mixed $element
- * @return string
- */
- public function render(Zend_View_Interface $view = null, $element = null)
- {
- return '<img width="'.$this->getWidth().'" height="'.$this->getHeight().'" alt="'.$this->getImgAlt().'" src="' . $this->getImgUrl() . $this->getId() . $this->getSuffix() . '"/><br/>';
- }
- }