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