再談驗證碼——扭曲以及部分反色
經過上次的淺談驗證碼以及簡單驗證碼實現,我們簡單實現了驗證碼,照說最終實現的應該可以了,起碼應付一部分破解菜鳥應該可以了,但是,隨著破解技術的不斷提高,我們也必須提高破解難度,正所謂:魔高一尺,道高一丈!
另外,下面只有兩個函式的程式碼,具體實現的程式碼上篇文章有,下面的函式直接用在圖片輸出前的末尾即可,另外,換了下字型,上次的字型在這裡很難看清
好了,廢話不多說,現在先實現驗證碼圖片的扭曲,思路就是根據某個連續函式來錯開圖片的每一行,於是,sin函式就是個不錯的選擇:
function distort($img,$scale = 8) {//8即為最大錯開畫素個數 $w = imagesx($img); $h = imagesy($img); $new_w = $w + $scale * 2; $new_img = @imagecreatetruecolor($new_w, $h); $bg_color = imagecolorallocate($new_img, 255, 255, 255); @imagefilledrectangle($new_img, 0, 0, $new_w - 1, $h - 1, $bg_color);//新圖片背景填充為白色 $tmp = mt_rand(); $f = 6.28 / $h; for ($i = 0; $i < $h; $i++) { $detaX = $scale * (1 + sin($i * $f + $tmp));//計算每一行錯開的畫素 for ($j = 0; $j < $w; $j++) { $rgb = imagecolorat($img, $j, $i); imagesetpixel($new_img, $j + $detaX, $i, $rgb); } } imagedestroy($img); return $new_img; }
好了,來看看效果:
不錯吧,效果還是可以的
下面介紹部分反色,很簡單,為了圖方便,我直接用矩形區域反色:
function part_reverse($img,$rw = 40 ,$rh = 30,$border = 10){//rw:反色區域寬度,border:邊界距離
$w = imagesx($img) - $rw;
$h = imagesy($img) - $rh;
$x = mt_rand($border,$w - $border - 1);
$y = mt_rand($border,$h - $border - 1);
$tmp_img = @imagecreatetruecolor($rw, $rh);
imagecopy($tmp_img,$img,0,0,$x,$y,$rw,$rh);
imagefilter($tmp_img,IMG_FILTER_NEGATE);//這是個不錯的函式,詳見 http://cn2.php.net/manual/zh/function.imagefilter.php
imagecopy($img,$tmp_img,$x,$y,0,0,$rw,$rh);
imagedestroy($tmp_img);
return $img;
}
好了,就介紹這兩個,實際應用時,可以兩個一起使用(當然,要注意調整下引數,否則連人都看不清的),那樣效果更好,尤其是字元是漢字的時候。
在我的印象裡,有幾個公司的驗證碼是做的很不錯的,人人、豆瓣、Google,其它的印象不是很深刻,有空也會拿他們的來實現試試~
==================================================
然後,順便給上次的淺談驗證碼補充下,介紹下一些比較高階的驗證碼吧:
1.問題驗證碼,無非是將問題畫在圖形上讓使用者回答,只要準備足夠的問題就行,當然,也可以直接讓使用者算數學問題,加減法神馬的都行,限制你的只有想象力了~
2.實物圖片驗證碼,就是準備一大堆實物圖片,讓使用者說出名稱,但是答案不唯一,但是可以讓使用者做個選擇題,很顯然,缺點是實物有限,準備這個資料庫有點耗時間,而且得時常更新,因為如果就那幾個物體的話,很容易被破解
3.填空圖片驗證碼,比如 "He lo w rld",讓使用者填出缺少的字母,很容易,就是l 和 0 麼,而且來源廣泛,不用手工採集,隨便去網上扒一篇英文,調幾個簡單的句子,隨便抽幾個字元,讓使用者填空即可,當然,中文也可以,缺點是你得準備一個哪些句子是“簡單的”的資料庫。(這個方法是本人自己想的,實現起來不知道是否可行)