clicaptcha中文點選驗證碼開發經驗總結

2022-02-09 08:09:12 字數 3749 閱讀 4683

現在的驗證碼真是越來越高階了,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

七号 = 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

我們都知道,在 php 中,通過設定 header 的引數,可以輸出各種檔案型別,但一次只能輸出一種資料格式到客戶端。

在我這個專案中,除了需要輸出,同時還需要將提示文字也輸出,不然使用者就不知道依次點哪些文字進行驗證了。

解決這個問題我想到有兩種解決方案:

只輸出到前端,同時將提示檔案放入 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...