<?php namespace WebPlugin; use Hood\Session; class Captcha { private static $V = array( "a", "e", "i", "o", "u", "y" ); private static $VN = array( "a", "e", "i", "o", "u", "y", "2", "3", "4", "5", "6", "7", "8", "9" ); private static $C = array( "b", "c", "d", "f", "g", "h", "j", "k", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "z" ); private static $CN = array( "b", "c", "d", "f", "g", "h", "j", "k", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "z", "2", "3", "4", "5", "6", "7", "8", "9" ); private $_width = 160; private $_height = 60; private $_fs = 28; private $_dotNoiseLevel = 50; private $_lineNoiseLevel = 5; private $_wordLen = 6; private $_useNumbers = true; /** * Generate new random word * * @return string */ protected function _generateWord() { $word = ''; $wordLen = $this->getWordLen (); $vowels = $this->_useNumbers ? self::$VN : self::$V; $consonants = $this->_useNumbers ? self::$CN : self::$C; for($i = 0; $i < $wordLen; $i = $i + 2) { $consonant = $consonants [array_rand ( $consonants )]; $vowel = $vowels [array_rand ( $vowels )]; $word .= $consonant . $vowel; } if (strlen ( $word ) > $wordLen) { $word = substr ( $word, 0, $wordLen ); } return $word; } public function getWordLen() { return $this->_wordLen; } /** * 设置验证码长度 * * @param string $wordLen * @return \Plugin\Captcha */ public function setWordLen($wordLen) { $this->_wordLen = $wordLen; return $this; } /** * 获取图像宽度 * * @return int */ public function getWidth() { return $this->_width; } /** * 获取图像高度 * * @return int */ public function getHeight() { return $this->_height; } /** * 设置图像宽度 * * @param int $width * @return \Plugin\Captcha */ public function setWidth($width) { $this->_width = $width; return $this; } /** * 设置图像高度 * * @param int $height * @return \Plugin\Captcha */ public function setHeight($height) { $this->_height = $height; return $this; } /** * */ public function getFontSize() { return $this->_fs; } public function setFontSize($fs) { $this->_fs = $fs; return $this; } /** * 设置干扰点 * * @param string $noise * @return \Plugin\Captcha */ public function setDotNoiseLevel($noise = 100) { $this->_dotNoiseLevel = $noise; return $this; } /** * 设置干扰线 * * @param string $noise * @return \Plugin\Captcha */ public function setLineNoiseLevel($noise = 5) { $this->_lineNoiseLevel = $noise; return $this; } /** * 获取干扰点 * * @return string */ public function getDotNoiseLevel() { return $this->_dotNoiseLevel; } /** * 获取干扰线 * * @return string */ public function getLineNoiseLevel() { return $this->_lineNoiseLevel; } /** * 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 0; return mt_rand ( 300, 700 ) / 100; } public function getFont() { return dirname ( __FILE__ ) . '/ttf/2.ttf'; } /** * 将验证码存入Sessioin * * @param string $namespace * @param string $code * @return true */ public static function setToSession($namespace, $code) { self::getSessionObject($namespace)->captcha = $code; return true; } /** * 从session中取出已经生成的验证码 * * @param string $namespace * @return string|false */ public static function getFromSession($namespace) { $code = self::getSessionObject($namespace)->captcha; if (!empty( $code )) { return $code; } else { return false; } } /** * Constructor * * @param array $options * @return void */ public function __construct($options = null) { if (isset ( $options )) { foreach ( $options as $k => $v ) { call_user_func ( array ($this, 'set' . ucfirst ( $k ) ), $v ); } } } public function generate($namespace) { $word = $this->_generateWord (); self::setToSession ( $namespace, $word ); header ( "Content-type: image/png" ); $this->_generateImage ( $word ); return $word; } /** * 生成验证码 * * @param string $word */ protected function _generateImage($word) { if (! extension_loaded("gd")) { exit("Image CAPTCHA requires GD extension"); } if (! function_exists("imagepng")) { exit("Image CAPTCHA requires PNG support"); } if (! function_exists("imageftbbox")) { exit("Image CAPTCHA requires FT fonts support"); } $font = $this->getFont(); if (empty($font)) { exit("Image CAPTCHA requires font"); } $w = $this->getWidth (); $h = $this->getHeight (); $fsize = $this->getFontSize (); $img = imagecreatetruecolor ( $w, $h ); $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 ); imagedestroy ( $img ); imagedestroy ( $img2 ); } /** * 获取session对象 * * @param string $namespace * @return object */ public static function getSessionObject($namespace) { if(strtoupper(substr(PHP_OS,0,3)) === 'WIN') { return Session::fileStart($namespace); } else { return Session::start($namespace, null, 'yohobuy.com'); } } }