|
|
<?php
|
|
|
namespace Plugin;
|
|
|
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');
|
|
|
}
|
|
|
}
|
|
|
} |
|
|
\ No newline at end of file |
...
|
...
|
|