現在的驗證碼真是越來越高階了,12306 的找圖驗證碼,極驗的拖動式驗證碼,還有國外的一些黑科技,能智慧型判斷你是不是機械人的驗證碼。
驗證碼的更新迭代讓我突然對傳統驗證碼一下子不滿足了,出於挑戰自我和對自己技能的修煉,我用了一周的時間寫了乙個簡單的 demo ,然後又花了一周時間將其優化成外掛程式的形式,於是 clicaptcha 就誕生了。
簡單介紹下 clicaptcha ,它是由 click 和 captcha 這兩個單子合併而成,顧名思義,這是乙個點選驗證碼,那怎麼個點選驗證呢?整個操作流程只需根據提示文字資訊,點選圖中文字所在位置,即可完成驗證,效果圖下圖:
具體的功能實現這裡就不一步步給大家回顧了,感興趣的可以直接上 oschina 或者 github ,搜尋 clicaptcha 就可以看到這個專案。
首先我們要做一些準備工作:
背景中文字型
隨機文字
字型所佔範圍(因為是 php 生成,所以借助 gd 庫里的 imagettfbbox 方法)
準備好這些後,就可以開始考慮我們的隨機布局演算法了,其實並不複雜,如果有看過我之前寫的《絕對定位的層判斷是否有相互覆蓋的解決演算法》,其實思路是差不多的。
可以看下上面這張圖,假設中間帶背景色的區域是已經固定的乙個區域,當第2個區域要進行隨機生成的時候,大概會有4種情況,也就是圖中的這4種,我們只需依次判斷以下4種條件,只要有一項符合,則這個隨機生成的x,y座標就可以使用。
x2 + w2 < x1其實這倒不算個難點,就是個小細節。x1 + w1 < x2
y2 + h2 < y1
y1 + h1 < y2
gd 庫里的 imagefttext 方法中,設定字型大小並不是以畫素(px)為單位的,而是以磅(point)為單位。所以在具體使用的時候,需要進行轉換,也就是乘以 0.75 ,比如你需要在上展示 50px 大小的字型,則需要 50px * 0.75 = 37.5point 。至於為什麼是乘以 0.75 ,可以見下表:
八號 = 5磅(7px) = (5/72)*96 = 6.67 = 6px我們都知道,在 php 中,通過設定 header 的引數,可以輸出各種檔案型別,但一次只能輸出一種資料格式到客戶端。七号 = 5.5磅 = (5.5/72)*96 = 7.3 = 7px
小六 = 6.5磅 = (6.5/72)*96 = 8.67 = 8px
六號 = 7.5磅 = (7.5/72)*96 = 10px
小五 = 9磅 = (9/72)*96 = 12px
五號 = 10.5磅 = (10.5/72)*96 = 14px
小四 = 12磅 = (12/72)*96 = 16px
四號 = 14磅 = (14/72)*96 = 18.67 = 18px
小三 = 15磅 = (15/72)*96 = 20px
三號 = 16磅 = (16/72)*96 = 21.3 = 21px
小二 = 18磅 = (18/72)*96 = 24px
二號 = 22磅 = (22/72)*96 = 29.3 = 29px
小一 = 24磅 = (24/72)*96 = 32px
一號 = 26磅 = (26/72)*96 = 34.67 = 34px
小初 = 36磅 = (36/72)*96 = 48px
初號 = 42磅 = (42/72)*96 = 56px
在我這個專案中,除了需要輸出,同時還需要將提示文字也輸出,不然使用者就不知道依次點哪些文字進行驗證了。
解決這個問題我想到有兩種解決方案:
只輸出到前端,同時將提示檔案放入 cookie 中,前端調取 cookie 顯示提示文字
最終我是選擇了第二套方案,因為這是個驗證碼外掛程式,如果每次生成的驗證都儲存下來,對伺服器硬碟資源占用將是個大問題。
在我將後端**全部開發完成,前端也封裝好了乙個 jquery 外掛程式後,發現了乙個大問題,就是如果使用者通過特殊手段跳過驗證碼驗證,直接提交表單或者相關業務操作怎麼辦?
因為驗證碼是以外掛程式的形式存在,所以在呼叫的引數裡有乙個 callback 引數,用於驗證成功後執行**本身業務邏輯的**。這樣就可能會有個問題,我用 chrome 按 f12 開啟開發者工具,直接在任務台裡輸入了提交表單的**並回車執行,然後表單順利提交了,完完全全跳過了驗證。
解決這個問題也不複雜,我思考了傳統驗證碼的驗證流程,核心一點就是它是隨表單一起提交並做驗證的,但由於我這個驗證碼的特殊性,所以只能增加乙個後端二次驗證,也就是前端初步驗證後,將驗證資訊隨表單提交到後端進行二次驗證即可,同時,後端的二次驗證成功後,將 session 清除,避免重複重新整理提交表單造成能跳過二次驗證的問題。
以下是針對前兩個難點寫的乙個小demo,如果對完整的原始碼一時半會難理解的話,可以 copy 以下**到本地,替換下字型和,然後執行一下看看效果。
//為什麼要乘0.75?因為 imagefttext 方法裡的 size 引數使用磅(point)做為單位的,所以需要進行轉換,轉換為畫素
$fontsize = 50 * 0.75;
//以「」三個字舉例,將文字、尺寸等資訊存入陣列
foreach(array('博', '客', '園') as $v)
//獲取背景底圖寬高和型別資訊
list($imagewidth, $imageheight, $imagetype) = getimagesize($imagepath);
//隨機生成漢字位置,並附加存入陣列
foreach($textarr as &$v)
unset($v);
//建立的例項
$image = imagecreatefromstring(file_get_contents($imagepath));
//字型顏色
$color = imagecolorallocate($image, 0, 0, 0);
//繪畫文字
foreach($textarr as $v)
//生成
switch($imagetype)
imagedestroy($image);
//隨機生成位置布局
function randposition($textarr, $imgw, $imgh, $fontw, $fonth)else
return $return;
}function checkposition($textarr, $x, $y, $w, $h)
}else if($x > $v['x'])
}else
$flagy = true;
if($v['y'] > $y)
}else if($y > $v['y'])
}else
if(!$flagx && !$flagy)
} }return $flag;
}
驗證碼顯示中文
現在qq上申請免費號碼的驗證碼是中文的,其實這個也不難,就是隨機生成乙個16進製制的陣列,然後根據編碼查詢漢字,程式如下,此為控制台程式。1using system 2using system.text 34 namespace5 14 17此函式在漢字編碼範圍內隨機建立含兩個元素的十六進製制位元組...
做中文驗證碼
知識點 imagettftext 用 truetype 字型向影象寫入文字 具體引數看手冊 如何產生隨機的中文字串 中文安其uniccode編碼 是有規律的 位於 0x4e00 0x9fa0 但是請注意 對於客戶來說 能否認識 所以在實際專案中 只是抽取幾百或上千的常用漢字 放陣列裡 隨機選取 選常...
discuz增加中文驗證碼
方法 1.從windows 系統下獲得字型檔案 c盤下的windows fonts目錄 如 simhei.ttf simsun.ttc 2.linux centos6.5 usr share fonts 下 mkdir chinese 目錄 3.賦予操作許可權 chmod r 755 usr sha...