1、字體變型 (一般通過算法,進行扭曲,比較有代表性就是:http://code.google.com/p/cool-php-captcha/
2、字體黏貼 (這裡面以qq驗證碼為代表了,目前網上還是很難找到,破解qq驗證碼的)
3、干擾線,噪點 (這種識別起來相當容易,很容易被程序自動化識別)
對於上面提到,第1,2 二種方法,在識別時候,是比較困難的。個人比較喜歡第二種方法,感覺看起來不是很費力。而扭曲的文字,總覺得怪怪的。 哈哈,純粹個人喜好了。
實現代碼:
<?php /** *帶文字旋轉,傾斜,黏貼,加正弦干擾線驗證碼* *@version 0.1 *@author http://www.cnblogs.com/chengmo *@copyright 程默 QQ:8292669 */ class Utils_Caption { var $Width = 60; //圖片寬 var $Height = 30; //圖片高 var $Length = 4; //驗證碼位數 var $BgColor = "#FFFFFF"; //背景色 var $TFonts = array("font.ttf"); var $TFontSize=array(17,20); //字體大小范圍 var $TFontAngle=array(-20,20); //旋轉角度 var $Chars = "0123456789"; //驗證碼范圍(字母數字) var $Code = array(); //驗證碼 var $Image = ""; //圖形對象 var $FontColors=array('#f36161','#6bc146','#5368bd'); //字體顏色,紅綠藍 var $TPadden = 0.75;///字符間距,多少個字符 var $Txbase = 5;///x軸兩邊距離 var $Tybase =5 ;///y軸兩邊距離 var $TLine =true; ///畫干擾線 public function RandRSI() ///生成驗證碼 { $this->TFontAngle=range($this->TFontAngle[0],$this->TFontAngle[1]); $this->TFontSize=range($this->TFontSize[0],$this->TFontSize[1]); $arr=array(); $Chars=$this->Chars; $TFontAngle=$this->TFontAngle; $TFontSize=$this->TFontSize; $FontColors=$this->FontColors; $code=""; $font=dirname(__FILE__)."/font/".$this->TFonts[0]; $charlen=strlen($Chars)-1; $anglelen=count($TFontAngle)-1; // 角度范圍 $fontsizelen=count($TFontSize)-1; // 角度范圍 $fontcolorlen=count($FontColors)-1; // 角度范圍 for($i=0;$i<$this->Length;$i++) ///得到字符與顏色 { $char=$Chars[rand(0,$charlen)]; ///得到字符 $angle=$TFontAngle[rand(0,$anglelen)]; ///旋轉角度 $fontsize=$TFontSize[rand(0,$fontsizelen)]; ///字體大小 $fontcolor=$FontColors[rand(0,$fontcolorlen)]; ///字體大小 $bound=$this->_calculateTextBox($fontsize,$angle,$font,$char); ///得到范圍 $arr[]=array($fontsize,$angle,$fontcolor,$char,$font,$bound); ///得到矩形框 $code.=$char; } $this->Code=$arr; //驗證碼 return $code; } public function Draw() ///畫圖 { if(empty($this->Code)) $this->RandRSI(); $codes=$this->Code; ///用戶驗證碼 $wh=$this->_getImageWH($codes); $width=$wh[0]; $height=$wh[1]; ///高度 $this->Width=$width; $this->Height=$height; $this->Image = imageCreate( $width, $height ); $image=$this->Image; $back = $this->_getColor2($this->_getColor( $this->BgColor)); ///背景顏色 imageFilledRectangle($image, 0, 0, $width, $height, $back); ///填充背景 $TPadden=$this->TPadden; $basex=$this->Txbase; $color=null; foreach ($codes as $v) ///逐個畫字符 { $bound=$v[5]; $color=$this->_getColor2($this->_getColor($v[2])); imagettftext($image, $v[0], $v[1], $basex, $bound['height'],$color , $v[4], $v[3]); $basex=$basex+$bound['width']*$TPadden-$bound['left'];///計算下一個左邊距 } $this->TLine?$this->_wirteSinLine($color,$basex):null; ///畫干擾線 header("Content-type: image/png"); imagepng( $image); imagedestroy($image); } /** *通過字體角度得到字體矩形寬度* * * @param int $font_size 字體尺寸 * @param float $font_angle 旋轉角度 * @param string $font_file 字體文件路徑 * @param string $text 寫入字符 * @return array 返回長寬高 */ private function _calculateTextBox($font_size, $font_angle, $font_file, $text) { $box = imagettfbbox($font_size, $font_angle, $font_file, $text); $min_x = min(array($box[0], $box[2], $box[4], $box[6])); $max_x = max(array($box[0], $box[2], $box[4], $box[6])); $min_y = min(array($box[1], $box[3], $box[5], $box[7])); $max_y = max(array($box[1], $box[3], $box[5], $box[7])); return array( 'left' => ($min_x >= -1) ? -abs($min_x + 1) : abs($min_x + 2), 'top' => abs($min_y), 'width' => $max_x - $min_x, 'height' => $max_y - $min_y, 'box' => $box ); } private function _getColor( $color ) //#ffffff { return array(hexdec($color[1].$color[2]),hexdec($color[3].$color[4]),hexdec($color[5].$color[6])); } private function _getColor2( $color ) //#ffffff { return imagecolorallocate ($this->Image, $color[0], $color[1], $color[2]); } private function _getImageWH($data) { $TPadden=$this->TPadden; $w=$this->Txbase; $h=0; foreach ($data as $v) { $w=$w+$v[5]['width']*$TPadden-$v[5]['left']; $h=$h>$v[5]['height']?$h:$v[5]['height']; } return array(max($w,$this->Width),max($h,$this->Height)); } //畫正弦干擾線 private function _wirteSinLine($color,$w) { $img=$this->Image; $h=$this->Height; $h1=rand(-5,5); $h2=rand(-1,1); $w2=rand(10,15); $h3=rand(4,6); for($i=-$w/2;$i<$w/2;$i=$i+0.1) { $y=$h/$h3*sin($i/$w2)+$h/2+$h1; imagesetpixel($img,$i+$w/2,$y,$color); $h2!=0?imagesetpixel($img,$i+$w/2,$y+$h2,$color):null; } } }
外帶字體:
font.ttf ,一個簡單粗體文件。
說明:
先看下運行效果吧,大家也不要忙著復制運行了。
……
主要特點是:旋轉,然後黏貼,干擾線是線粗細可以變,然後正弦波形可以變化。
比較復雜是:calculateTextBox 這個函數,這個是得到字符旋轉後的寬度高度。
demo:
$rsi = new Utils_Caption(); $rsi->TFontSize=array(15,17); $rsi->Width=50; $rsi->Height=25; $code = $rsi->RandRSI(); session_start(); $_SESSION["CHECKCODE"] = $code; $rsi->Draw();
好了,就寫這麼些了,代碼還有很多不足之處。歡迎朋友提出好的建議。