1. 程式人生 > >再談驗證碼——扭曲以及部分反色

再談驗證碼——扭曲以及部分反色

經過上次的淺談驗證碼以及簡單驗證碼實現,我們簡單實現了驗證碼,照說最終實現的應該可以了,起碼應付一部分破解菜鳥應該可以了,但是,隨著破解技術的不斷提高,我們也必須提高破解難度,正所謂:魔高一尺,道高一丈!

另外,下面只有兩個函式的程式碼,具體實現的程式碼上篇文章有,下面的函式直接用在圖片輸出前的末尾即可,另外,換了下字型,上次的字型在這裡很難看清

好了,廢話不多說,現在先實現驗證碼圖片的扭曲,思路就是根據某個連續函式來錯開圖片的每一行,於是,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 麼,而且來源廣泛,不用手工採集,隨便去網上扒一篇英文,調幾個簡單的句子,隨便抽幾個字元,讓使用者填空即可,當然,中文也可以,缺點是你得準備一個哪些句子是“簡單的”的資料庫。(這個方法是本人自己想的,實現起來不知道是否可行)