不少網站為了防止用戶利用機器人自動注冊、登錄、灌水,都采用了驗證碼技術。所謂驗證碼,就是將一串隨機產生的數字或符號,生成一幅圖片,圖片裡加上一些干擾象素(防止OCR),由用戶肉眼識別其中的驗證碼信息,輸入表單提交網站驗證,驗證成功後才能使用某項功能。
PHP實現:
我們這裡展示了如何編寫PHP程序實現驗證碼功能:
代碼一:
<?php
/*
* Filename: authpage.php
* Author: hutuworm
* Date: 2003-04-28
* @Copyleft hutuworm.org
*/
srand((double)microtime()*1000000);
//驗證用戶輸入是否和驗證碼一致
if(isset($HTTP_POST_VARS['authinput']))
{
if(strcmp($HTTP_POST_VARS['authnum'],$HTTP_POST_VARS['authinput'])==0)
echo "驗證成功!";
else
echo "驗證失敗!";
}
//生成新的四位整數驗證碼
while(($authnum=rand()%10000)<1000);
?>
<form action=authpage.php method=post>
<table>
請輸入驗證碼:<input type=text name=authinput style="width:
80px"><br>
<input type=submit name="驗證" value="提交驗證碼">
<input type=hidden name=authnum value=<? echo $authnum; ?>>
<img src=authimg.php?authnum=<? echo $authnum; ?>>
</table>
</form>
代碼二:
<?php
/*
* Filename: authimg.php
* Author: hutuworm
* Date: 2003-04-28
* @Copyleft hutuworm.org
*/
//生成驗證碼圖片
Header("Content-type: image/PNG");
srand((double)microtime()*1000000);
$im = imagecreate(58,28);
$black = ImageColorAllocate($im, 0,0,0);
$white = ImageColorAllocate($im, 255,255,255);
$gray = ImageColorAllocate($im, 200,200,200);
imagefill($im,68,30,$gray);
//將四位整數驗證碼繪入圖片
imagestring($im, 5, 10, 8, $HTTP_GET_VARS['authnum'], $black);
for($i=0;$i<50;$i++) //加入干擾象素
{
imagesetpixel($im, rand()%70 , rand()%30 , $black);
}
ImagePNG($im);
ImageDestroy($im);
?>
本文程序在Apache 2.0.45 + PHP 4.3.1環境下運行通過。
上文只是對驗證碼功能的一個簡單實現,並沒有考慮商用安全性問題。如果要增強安全性,將此功能投入商業應用,則可以通過以下幾個步驟實現:
1. 啟用Session。
2. authnum在authimg.php中生成,並計算md5sum,存入session。
3.
authpage.php將authinput計算md5sum後,與session中的authnum(md5sum)對比得出驗證結果。
本站注:作者使用了簡單的代碼實現了很酷的功能。不過在添加干擾像素時的效果不是太好,大家可以看一下雨聲論壇登錄時的效驗碼(http://ror.cn/perl/ut/user_login.cgi),偶把第二段代碼稍改了一下,生成了與其類似的效果。
修改後的代碼如下:
<?php
/*
* Filename: authimg.php
* Author: hutuworm
* Date: 2003-04-28
* @Copyleft hutuworm.org
*/
//生成驗證碼圖片
Header("Content-type: image/PNG");
srand((double)microtime()*1000000);
$im = imagecreate(62,20);
$black = ImageColorAllocate($im, 0,0,0);
$white = ImageColorAllocate($im, 255,255,255);
$gray = ImageColorAllocate($im, 200,200,200);
imagefill($im,68,30,$gray);
while(($authnum=rand()%100000)<10000);
//將四位整數驗證碼繪入圖片
imagestring($im, 5, 10, 3, $authnum, $black);
for($i=0;$i<200;$i++) //加入干擾象素
{
$randcolor =
ImageColorallocate($im,rand(0,255),rand(0,255),rand(0,255));
imagesetpixel($im, rand()%70 , rand()%30 , $randcolor);
}
ImagePNG($im);
ImageDestroy($im);
?>
顯示結果如下圖:
[在新窗口中浏覽該圖片]
有興趣的朋友可以自己試一下。
看一下上面這段代碼:
第一次看PHP代碼,呵呵。奇怪的學習經歷。
代碼一:
<?php
/*
* Filename: authpage.php
* Author: hutuworm
* Date: 2003-04-28
* @Copyleft hutuworm.org
*/
//以系統時間為種子得到隨機數
//srand -- 播下隨機數發生器種子
//microtime -- 返回當前 UNIX 時間戳和微秒數
srand((double)microtime()*1000000);
//驗證用戶輸入是否和驗證碼一致
if(isset($HTTP_POST_VARS['authinput']))
{
//authnum的值是不應該發送到客戶端的,這裡應該是為了構建一個簡單的例子先吧
//authnum 保存在 session 裡應該是個可行的辦法
if(strcmp($HTTP_POST_VARS['authnum'],$HTTP_POST_VARS['authinput'])==0)
echo "驗證成功!";
else
echo "驗證失敗!";
}
//生成新的四位整數驗證碼
while(($authnum=rand()%10000)<1000);
?>
<form action=authpage.php method=post>
<table>
請輸入驗證碼:<input type=text name=authinput style="width:
80px"><br>
<input type=submit name="驗證" value="提交驗證碼">
<input type=hidden name=authnum value=<? echo $authnum; ?>>
<img src=authimg.php?authnum=<? echo $authnum; ?>>
</table>
</form>
代碼二:
<?php
/*
* Filename: authimg.php
* Author: hutuworm
* Date: 2003-04-28
* @Copyleft hutuworm.org
*/
//下面幾行代碼肯定會讓寫ASP的GGDD們羨慕不已。
//生成驗證碼圖片
//指定頭信息
Header("Content-type: image/PNG");
srand((double)microtime()*1000000);
//返回一個圖像標識符,代表了一幅大小為58 X 28的空白圖像。
$im = imagecreate(58,28);
$black = ImageColorAllocate($im, 0,0,0);
$white = ImageColorAllocate($im, 255,255,255);
$gray = ImageColorAllocate($im, 200,200,200);
imagefill($im,68,30,$gray);
//強悍!!
//將四位整數驗證碼繪入圖片
//方便起見,使可以通過authimg.php?authnum=XXXX的方式得到圖片。實際應用中這種做法肯定是不足取的。
imagestring($im, 5, 10, 8, $HTTP_GET_VARS['authnum'], $black);
for($i=0;$i<50;$i++) //加入干擾象素
{
imagesetpixel($im, rand()%70 , rand()%30 , $black);
}
ImagePNG($im);
//imagepng -- 以 PNG 格式將圖像輸出到浏覽器或文件
ImageDestroy($im);
?>
本文程序在Apache 2.0.45 + PHP 4.3.1環境下運行通過。
上文只是對驗證碼功能的一個簡單實現,並沒有考慮商用安全性問題。如果要增強安全性,將此功能投入商業應用,則可以通過以下幾個步驟實現:
1. 啟用Session。
2. authnum在authimg.php中生成,並計算md5sum,存入session。
3. authpage.php將authinput計算md5sum後,與session中的authnum(md5sum)對比得出驗證結果。
本站注:作者使用了簡單的代碼實現了很酷的功能。不過在添加干擾像素時的效果不是太好,大家可以看一下雨聲論壇登錄時的效驗碼(http://ror.cn/perl/ut/user_login.cgi),偶把第二段代碼稍改了一下,生成了與其類似的效果。
修改後的代碼如下:
<?php
/*
* Filename: authimg.php
* Author: hutuworm
* Date: 2003-04-28
* @Copyleft hutuworm.org
*/
//生成驗證碼圖片
Header("Content-type: image/PNG");
srand((double)microtime()*1000000);
$im = imagecreate(62,20);
$black = ImageColorAllocate($im, 0,0,0);
$white = ImageColorAllocate($im, 255,255,255);
$gray = ImageColorAllocate($im, 200,200,200);
imagefill($im,68,30,$gray);
while(($authnum=rand()%100000)<10000);
//將四位整數驗證碼繪入圖片
imagestring($im, 5, 10, 3, $authnum, $black);
for($i=0;$i<200;$i++) //加入干擾象素
{
$randcolor =
ImageColorallocate($im,rand(0,255),rand(0,255),rand(0,255));
imagesetpixel($im, rand()%70 , rand()%30 , $randcolor);
}
ImagePNG($im);
ImageDestroy($im);
?>
驗證碼技術核心內容是動態生成圖片。ASP做到這一點,最簡單也是最普遍的就是用到XBM。我們先了解一下XBM的相關知識。
[轉]用XBM創建動態客戶端圖像
作者: BUILDER.COM
Wednesday, April 9 2003 11:23 AM
X-Bitmap(XBM)是一種古老但通用的圖像文件格式,它與現在的許多Web浏覽器都兼容。X-Windows圖形界面(UNIX和Linux常用的GUI)的C代碼庫xlib中有一個組件專門描述了它的規范。我將解釋XBM格式的工作原理,然後向你展示一種更有趣的使用它的方法:在客戶端創建動態圖像。文章中的代碼可以在此下載。
XBM基礎
XBM格式本來是為存儲單色的系統位圖而設計的,比如圖標和鼠標指針。XBM圖形的實質上是使用16進制數組來表示二進制圖像的C源代碼文件。(16進制數組表示的二進制圖像)
這裡你也許會問:這種文件格式與Web浏覽器有什麼關系?在上世紀九十年代早期,美國超級計算應用中心(NCSA)在伊利諾斯大學開發第一個被廣泛使用的Web浏覽器,名為Mosaic。這個浏覽器的圖形支持來自很多開放源碼代碼庫,其中就包括xlib。因此,導致今天的許多浏覽器能夠處理XBM圖形。
Mosaic項目後來成為了Netscape浏覽器的開發基礎。微軟也借用了一部分Mosaic代碼來創建Internet Explorer。微軟繼而在網絡信息服務器(IIS)中將XBM作為一個MIME類型注冊而提供本地支持,並且在現有所有版本的Internet Explorer中將其作為一種可支持的圖像。(浏覽器的廣泛支持)
從一個程序員的角度來看,JPEG或GIF與XBM有著極大的不同。這兩種文件格式都在位級別上操作並使用了壓縮算法。它們可以支持很大的顏色深度范圍。創建這些動態Web圖形的唯一方法是使用服務器端的腳本,比如<a href=http://stein.cshl.org/WWW/software/GD/GD.pm和CGI/Perl腳本的結合,或者通過System.Drawing名字空間訪問ASP.NET中的圖形設計接口類庫(GDI+)。(升級到ASP.NET有很多個理由。)
XBM創建起來很有程序性。每個位都被一一指定,而結果圖形被限制為兩色(黑色和白色)。(局限性之一:讓人不爽)X-Bitmap並不是必須服務器端腳本,可以在客戶端用JavaScript實時創建它們。(增加了不少靈活性)
X-Bitmap的實用程序包括動態生成的圖、頁面計數器、老式圖形圖標、以及統計圖表。(就是通過位控制太麻煩了,有良好的包裝就好了。另外:生成圖片的大小,算法的強度,是否都達到了可用的要求?)給我印象最深的XMB應用是一個叫Wolfenstein 5k的游戲,它是一個紋理映射的第一視角射擊游戲,用JavaScript編寫,只有5KB大小。(不錯啊,稍後爽一下)
通過使用IMG標識可以很容易地將XBM文件嵌入到一個Web頁面中。其語法如下:
<img src=”xbmsmill.xbm”>
----------------------------------------------------------------------
注意
這種格式不對Mac或相應的浏覽器有效,比如Mozilla的早期版本。
----------------------------------------------------------------------
典型的XBM源代碼與列表A中顯示的比較相像。
#define語句以像素點為單位設置了圖像的寬度和高度。你也可以使用x_hot和y_hot命令來定義圖像中的一個熱點。我已經創建了一個X-Bitmap來描繪這個過程。為了設計它,我先將圖像映射為二進制值,如果你仔細的看,在這裡你會看到一張笑臉。
我所創建的二進制圖像寬16個數字高7個數字,在我們的源代碼的XBM頭中定義了相同大小的寬/高像素值。圖像本身被存儲在一個靜態數組中,它包含一列二進制編碼的十六進制(BCH)值——換句話說,每四位分成一組。
計算出笑臉的十六進制值得最簡單的方法是一次檢驗圖像的一行,將二進制值分成四位一組的分段,將每個分段映射成二進制/十六進制表中對應的十六進制數。下面是第一行:
0001100001100000
下面兩行分別表示四位的分段和其在表A中對應的十六進制數
二進制: 0001 1000 0110 0000
十六進制: 8 1 6 0
表A
XBM二/十六進制轉換表
二進制 十六進制
0000 0
1000 1
0100 2
1100 3
0010 4
1010 5
0110 6
1110 7
0001 8
1001 9
0101 A
1101 B
0011 C
1011 D
0111 E
1111 F
請注意這些並不是標准的二/十六進制轉換。它們是反向計算的(從左到右)而不是從右到左。把它顛倒是因為浏覽器會從左到右來讀圖形,我們的代碼必須與其一致。
最後要把這些十六進制值轉換成XBM的右格式。必須在每個十六進制值前加“0x”。這是標准C++表示十六進制的方法。然後將這些值從右到左輸出(每個十六進制對表示八位二進制位)。請看列表B中的例子。
因此,我們可以說:
0001100001100000=0x18,0x06
這些符合XBM的值可以很容易地插入到圖像數組中:
static unsigned char xbmsmile_bits[]=
現在我們來看看格式本身,現在是時候來學習在客戶端浏覽器中動態創建X-Bitmap了。
圖片用點陣的形式表示,比如2:
00111100 0011為3 1100為C 即0x3c
01100110 0110為6 0110為6 0x66
01100000 ....... 0x表示十六進制數。
01100000 依此類推
00110000 這是用二進制數得到的點陣,其中的1為顯示一黑點,0不顯示
00011000 是一個反著看的2
00001100 其余數字可自已排列點陣再二進制化為十六進制數
00000110 缺點是只有黑白兩種顏色
00000110 顯示出來是白底黑字,要顯示黑底白字的話,對其取反就行了
01111110
下面是我"畫"的0-9的數字
num.asp
<%
Dim a(10,10)
a(0,1) = "0x3c" '數字0
a(0,2) = "0x66"
a(0,3) = "0xc3"
a(0,4) = "0xc3"
a(0,5) = "0xc3"
a(0,6) = "0xc3"
a(0,7) = "0xc3"
a(0,8) = "0xc3"
a(0,9) = "0x66"
a(0,10)= "0x3c"
a(1,1) = "0x18" '數字1
a(1,2) = "0x1c"
a(1,3) = "0x18"
a(1,4) = "0x18"
a(1,5) = "0x18"
a(1,6) = "0x18"
a(1,7) = "0x18"
a(1,8) = "0x18"
a(1,9) = "0x18"
a(0,10)= "0x7e"
a(2,1) = "0x3c" '數字2
a(2,2) = "0x66"
a(2,3) = "0x60"
a(2,4) = "0x60"
a(2,5) = "0x30"
a(2,6) = "0x18"
a(2,7) = "0x0c"
a(2,8) = "0x06"
a(2,9) = "0x06"
a(2,10)= "0x7e"
a(3,1) = "0x3c" '數字3
a(3,2) = "0x66"
a(3,3) = "0xc0"
a(3,4) = "0x60"
a(3,5) = "0x1c"
a(3,6) = "0x60"
a(3,7) = "0xc0"
a(3,8) = "0xc0"
a(3,9) = "0x66"
a(3,10)= "0x38"
a(4,1) = "0x38" '數字4
a(4,2) = "0x3c"
a(4,3) = "0x36"
a(4,4) = "0x33"
a(4,5) = "0x33"
a(4,6) = "0x33"
a(4,7) = "0xff"
a(4,8) = "0x30"
a(4,9) = "0x30"
a(4,10)= "0xfe"
a(5,1) = "0xfe" '數字5
a(5,2) = "0xfe"
a(5,3) = "0x06"
a(5,4) = "0x06"
a(5,5) = "0x3e"
a(5,6) = "0x60"
a(5,7) = "0xc0"
a(5,8) = "0xc3"
a(5,9) = "0x66"
a(5,10)= "0x3c"
a(6,1) = "0x60" '數字6
a(6,2) = "0x30"
a(6,3) = "0x18"
a(6,4) = "0x0c"
a(6,5) = "0x3e"
a(6,6) = "0x63"
a(6,7) = "0xc3"
a(6,8) = "0xc3"
a(6,9) = "0x66"
a(6,10) ="0x3c"
a(7,1) = "0xff" '數字7
a(7,2) = "0xc0"
a(7,3) = "0x60"
a(7,4) = "0x30"
a(7,5) = "0x18"
a(7,6) = "0x18"
a(7,7) = "0x18"
a(7,8) = "0x18"
a(7,9) = "0x18"
a(7,10)= "0x18"
a(8,1) = "0x3c" '數字8
a(8,2) = "0x66"
a(8,3) = "0xc3"
a(8,4) = "0x66"
a(8,5) = "0x3c"
a(8,6) = "0x66"
a(8,7) = "0xc3"
a(8,8) = "0xc3"
a(8,9) = "0x66"
a(8,10)= "0x3c"
a(9,1) = "0x3c" '數字9
a(9,2) = "0x66"
a(9,3) = "0xc3"
a(9,4) = "0xc3"
a(9,5) = "0x66"
a(9,6) = "0x3c"
a(9,7) = "0x18"
a(9,8) = "0x0c"
a(9,9) = "0x06"
a(9,10)= "0x03"
%>
顯示的方法是:
1.先傳出一個MIME:
Response.ContentType = "image/x-xbitmap"
2.再傳出一個c++的源程序,如顯示2:
#define counter_width 8
#define counter_height 10
static unsigned char counter_bits[] = {
0x3c,0x66,0x60,0x60,0x30,0x18,0x0c,0x06,0x06,0x7e
};
這樣在浏覽器上就顯示出來一個8*10像素的2了
要顯示兩個或以上的數字的時候,須改動寬度的值(必須是圖像點陣寬度的整數倍),在count_bits[]數組的值排序如下:
比如顯示 12
a(1,1), a(2,1), a(1,2), a(2,2)... a(1,10), a(2,10)
下面是具體計數器的例子:
count.asp
<!--#include file="num.asp"-->
<%
Dim Image
Dim Width, Height
Dim num
Dim digtal
Dim Length
Dim sort
Length = 10 '自定計數器長度
Redim sort( Length )
num = 62275 '計數器的值
digital = ""
For I = 1 To Length -Len( num ) '補0
digital = digital & "0"
Next
For I = 1 To Len( num )
digital = digital & Mid( num, I, 1 )
Next
For I = 1 To Len( digital )
sort(I) = Mid( digital, I, 1 )
Next
Width = 8 * Len( digital ) '圖像的寬度
Height = 10 '圖像的高度,在本例中為固定值
Response.ContentType="image/x-xbitmap"
hc=chr(13) & chr(10)
Image = "#define counter_width " & Width & hc
Image = Image & "#define counter_height " & Height & hc
Image = Image & "static unsigned char counter_bits[]={" & hc
For I = 1 To Height
For J = 1 To Length
Image = Image & a(sort(J),I) & ","
Next
Next
Image = Left( Image, Len( Image ) - 1 ) '去掉最後一個逗號
Image = Image & "};" & hc
Response.Write Image
%>
把
#define counter_width 8
#define counter_height 10
static unsigned char counter_bits[] = {
0x3c,0x66,0x60,0x60,0x30,0x18,0x0c,0x06,0x06,0x7e
};
保存為 xbm 文件就可以得到一張顯示為 2 的圖片
#define counter_width 80
#define counter_height 10
static unsigned char counter_bits[]={
0x3c,0x3c,0x3c,0x3c,0x3c,0x60,0x3c,0x3c,0xff,0xfe,0x66,0x66,0x66,0x66,0x66,0x30,0x66,0x66,0xc0,0xfe,0xc3,0xc3,0xc3,0xc3,0xc3,0x18,0x60,0x60,0x60,0x06,0xc3,0xc3,0xc3,0xc3,0xc3,0x0c,0x60,0x60,0x30,0x06,0xc3,0xc3,0xc3,0xc3,0xc3,0x3e,0x30,0x30,0x18,0x3e,0xc3,0xc3,0xc3,0xc3,0xc3,0x63,0x18,0x18,0x18,0x60,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x0c,0x0c,0x18,0xc0,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x06,0x06,0x18,0xc3,0x66,0x66,0x66,0x66,0x66,0x66,0x06,0x06,0x18,0x66,0x7e,0x7e,0x7e,0x7e,0x7e,0x3c,0x7e,0x7e,0x18,0x3c};
保存為 xbm文件則顯示為 0000062275 。