雖然目前已經(jīng)有很多可以取代CGI且性能較CGI要高的技術(shù)(例如ASP、ISAPI、NSAPI等),但使用它們需要用到專(zhuān)門(mén)的知識(shí)和工具,并且利用這些技術(shù)所編制的程序也只適用于特定的Web服務(wù)器或系統(tǒng)平臺(tái)。考慮到CGI程序的易用易學(xué)性、跨服務(wù)器平臺(tái)特性等優(yōu)點(diǎn),CGI程序還將在WWW上占有一一席之地。本文將介紹如何用VB編寫(xiě)標(biāo)準(zhǔn)的CGI程序,最后本文還用VB實(shí)現(xiàn)了一個(gè)有關(guān)主頁(yè)客戶(hù)留言簿的CGI程序。
利用通用網(wǎng)關(guān)接口CGI,WEB服務(wù)器可以執(zhí)行一些外部程序,可以將這些外部程序所產(chǎn)生的輸出結(jié)果和WEB服務(wù)器所管理的靜態(tài)文本、圖象和聲音融合在一起傳給相應(yīng)的WEB瀏覽器。當(dāng)客戶(hù)方的瀏覽器向WEB服務(wù)器請(qǐng)求一個(gè)HTML文件時(shí),服務(wù)器在收到請(qǐng)求后就去尋找這個(gè)文件并將找到的文件傳送給客戶(hù)方。而當(dāng)客戶(hù)方的請(qǐng)求是一個(gè)CGI程序時(shí),WEB服務(wù)器將激活客戶(hù)方所請(qǐng)求的CGI程序并把程序的執(zhí)行結(jié)果傳給客戶(hù)方。
標(biāo)準(zhǔn)的CGI程序是通過(guò)環(huán)境變量和標(biāo)準(zhǔn)輸入輸出和WEB服務(wù)器交換信息的。任何一個(gè)被系統(tǒng)激活的進(jìn)程都擁有標(biāo)準(zhǔn)輸入和輸出這兩個(gè)文件句柄,CGI程序的進(jìn)程也不例外。不過(guò)當(dāng)CGI程序被WEB服務(wù)器激活以后,它的標(biāo)準(zhǔn)輸入STDIN被連接到WEB服務(wù)器的標(biāo)準(zhǔn)輸出STDOUT上,而CGI程序的標(biāo)準(zhǔn)輸出STDOUT則被連到服務(wù)器的標(biāo)準(zhǔn)輸入STDIN上。因此CGI程序從標(biāo)準(zhǔn)輸入讀取信息也就是從WEB服務(wù)器的標(biāo)準(zhǔn)輸出讀信息,而它向標(biāo)準(zhǔn)輸出寫(xiě)信息也就是向WEB服務(wù)器的標(biāo)準(zhǔn)輸入寫(xiě)信息。
WEB服務(wù)器一般將客戶(hù)方傳送來(lái)的信息放在它的標(biāo)準(zhǔn)輸出和相關(guān)環(huán)境變量中,而CGI程序則從環(huán)境變量和它的標(biāo)準(zhǔn)輸入(也就是WEB服務(wù)器的標(biāo)準(zhǔn)輸出)獲取所需的信息,程序的最終輸出結(jié)果則被寫(xiě)向它的標(biāo)準(zhǔn)輸出STDOUT(也就是WEB服務(wù)器的標(biāo)準(zhǔn)輸入)。WEB服務(wù)器將從它的標(biāo)準(zhǔn)輸入STDIN(也就是CGI程序的標(biāo)準(zhǔn)輸出)獲取CGI程序的輸出結(jié)果并將它傳送給客戶(hù)方??蛻?hù)方、WEB服務(wù)器和CGI程序之間的信息交流如圖1所示,顯然,WEB服務(wù)器就象是客戶(hù)方和CGI程序間的中介人。
WEB服務(wù)器、CGI程序間的這種標(biāo)準(zhǔn)框架在UNIX系統(tǒng)下和微軟視窗環(huán)境中的字符方式下可以工作得非常好,因?yàn)榇藭r(shí)系統(tǒng)所產(chǎn)生的所有進(jìn)程都可以存取標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出。但對(duì)于微軟視窗環(huán)境圖形方式下的程序就不行了,這是由于它們無(wú)法存取標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出。為了解決這一問(wèn)題,微軟在Win32系統(tǒng)中創(chuàng)建了另一類(lèi)型的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出,程序可以通過(guò)調(diào)用Win32 API函數(shù)存取標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出,不過(guò)這就意味著使用這類(lèi)標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出的CGI程序都必須是32位的。
微軟視窗環(huán)境下的其它一些WEB服務(wù)器(例如Website)則使用另外一種特殊的技術(shù)即利用INI文件來(lái)實(shí)現(xiàn)WEB服務(wù)器和CGI程序間的數(shù)據(jù)交流。采用這種被稱(chēng)為Win-CGI規(guī)范編寫(xiě)的CGI程序通常只能在部分WEB服務(wù)器上運(yùn)行。一般支持Win-CGI的WEB服務(wù)器將客戶(hù)端的輸入和有關(guān)的狀態(tài)信息寫(xiě)入一個(gè)INI文件中,而CGI程序則從該INI文件獲取相關(guān)信息,這類(lèi)程序的執(zhí)行效率將沒(méi)有標(biāo)準(zhǔn)CGI程序高。
在進(jìn)行CGI編程時(shí),您只要使CGI程序從標(biāo)準(zhǔn)輸入和環(huán)境變量中獲取客戶(hù)方提供的信息,把要傳送給客戶(hù)方的輸出結(jié)果寫(xiě)入標(biāo)準(zhǔn)輸出,剩下的信息傳遞工作WEB服務(wù)器將自動(dòng)完成。通用網(wǎng)關(guān)接口CGI只是規(guī)定了一個(gè)標(biāo)準(zhǔn)的接口規(guī)范,只要遵守這個(gè)標(biāo)準(zhǔn)規(guī)范,程序開(kāi)發(fā)人員可以利用各種編程工具例如Perl、C、Fortran、Visual Basic等進(jìn)行CGI編程??紤]到Visual Basic的強(qiáng)大的數(shù)據(jù)庫(kù)處理能力、客戶(hù)服務(wù)器模式的編程能力以及字符串處理能力,本文將介紹如何用VB編寫(xiě)標(biāo)準(zhǔn)的CGI程序。
一. 輸入輸出的處理
一個(gè)CGI程序被激活以后,它首先要做的事情就是確定系統(tǒng)平臺(tái)、WEB服務(wù)器和客戶(hù)端瀏覽器的狀態(tài)信息、客戶(hù)端用戶(hù)的輸入數(shù)據(jù),最后它還必須將相關(guān)信息能傳送給客戶(hù)端,否則它將一事無(wú)成。這些操作都是通過(guò)存取環(huán)境變量和標(biāo)準(zhǔn)輸入輸出完成的。用VB編寫(xiě)的CGI程序可以通過(guò)調(diào)用函數(shù)Environ( )來(lái)獲取相關(guān)環(huán)境變量的值。存取標(biāo)準(zhǔn)輸入輸出就要在程序中使用Win32API函數(shù)GetStdHandle( )、ReadFile( )和WriteFile( ),在使用這些函數(shù)時(shí)首先必須在程序中聲明它們。
以下的CGI程序說(shuō)明了在VB-CGI程序中如何處理環(huán)境變量和標(biāo)準(zhǔn)輸入輸出,該CGI程序非常簡(jiǎn)單,可以將標(biāo)準(zhǔn)輸入中的信息不經(jīng)任何處理就返回給客戶(hù)端,它可以被任何表單用POST方法激活:
Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, _
ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, _
lpOverlapped As Any) As Long
Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, ByVal lpBuffer As String, _
ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, _
lpOverlapped As Any) As Long
Public Const STD_INPUT_HANDLE = -10&
Public Const STD_OUTPUT_HANDLE = -11&
Public Const FILE_BEGIN = 0&
Public hStdIn As Long ’ 標(biāo)準(zhǔn)輸入文件句柄
Public hStdOut As Long ’ 標(biāo)準(zhǔn)輸出文件句柄
Sub Main()
Dim CGI_ContentLength As String,CGI_QueryString As String
Dim lContentLength As Long ’ 標(biāo)準(zhǔn)輸入中的字符串的長(zhǎng)度
Dim sBuff As String ’ 用于存儲(chǔ)標(biāo)準(zhǔn)輸入中的字符串
Dim lBytesRead As Long ’ 實(shí)際讀入的字符個(gè)數(shù)
Dim rc As Long
Dim sFormData As String
’調(diào)用系統(tǒng)函數(shù)生成標(biāo)準(zhǔn)輸入輸出文件句柄
hStdIn = GetStdHandle(STD_INPUT_HANDLE)
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
’獲取環(huán)境變量CONTENT_LENGTH的值,并將它轉(zhuǎn)換為整型
CGI_ContentLength = Environ("CONTENT_LENGTH")
lContentLength = Val(CGI_ContentLength)
sBuff = String(lContentLength, Chr$(0))
’從標(biāo)準(zhǔn)輸入中讀數(shù)據(jù)
rc = ReadFile(hStdIn, ByVal sBuff, lContentLength, lBytesRead, ByVal 0&)
sFormData = Left$(sBuff, lBytesRead)
OutPut "Content-type: text/html" & vbCrLf
OutPut "〈HTML〉〈HEAD〉"
OutPut "〈TITLE〉表單傳送數(shù)據(jù)的方法POST 〈/TITLE〉〈/HEAD〉"
OutPut "〈BODY〉〈H3〉表單傳送數(shù)據(jù)的方法POST〈/H3〉 "
OutPut "〈P〉本CGI 程序由Visual Basic編制! "
OutPut "〈P〉POST方法傳送的數(shù)據(jù): "
OutPut "〈P〉" & sBuff
OutPut "〈/BODY〉〈/HTML〉"
End Sub
Sub OutPut(s As String) ’ 定義一個(gè)向標(biāo)準(zhǔn)輸出寫(xiě)信息的函數(shù)
Dim lBytesWritten As Long
s = s & vbCrLf
WriteFile hStdOut, s, Len(s), lBytesWritten, ByVal 0&
End Sub
利用通用網(wǎng)關(guān)接口CGI,WEB服務(wù)器可以執(zhí)行一些外部程序,可以將這些外部程序所產(chǎn)生的輸出結(jié)果和WEB服務(wù)器所管理的靜態(tài)文本、圖象和聲音融合在一起傳給相應(yīng)的WEB瀏覽器。當(dāng)客戶(hù)方的瀏覽器向WEB服務(wù)器請(qǐng)求一個(gè)HTML文件時(shí),服務(wù)器在收到請(qǐng)求后就去尋找這個(gè)文件并將找到的文件傳送給客戶(hù)方。而當(dāng)客戶(hù)方的請(qǐng)求是一個(gè)CGI程序時(shí),WEB服務(wù)器將激活客戶(hù)方所請(qǐng)求的CGI程序并把程序的執(zhí)行結(jié)果傳給客戶(hù)方。
標(biāo)準(zhǔn)的CGI程序是通過(guò)環(huán)境變量和標(biāo)準(zhǔn)輸入輸出和WEB服務(wù)器交換信息的。任何一個(gè)被系統(tǒng)激活的進(jìn)程都擁有標(biāo)準(zhǔn)輸入和輸出這兩個(gè)文件句柄,CGI程序的進(jìn)程也不例外。不過(guò)當(dāng)CGI程序被WEB服務(wù)器激活以后,它的標(biāo)準(zhǔn)輸入STDIN被連接到WEB服務(wù)器的標(biāo)準(zhǔn)輸出STDOUT上,而CGI程序的標(biāo)準(zhǔn)輸出STDOUT則被連到服務(wù)器的標(biāo)準(zhǔn)輸入STDIN上。因此CGI程序從標(biāo)準(zhǔn)輸入讀取信息也就是從WEB服務(wù)器的標(biāo)準(zhǔn)輸出讀信息,而它向標(biāo)準(zhǔn)輸出寫(xiě)信息也就是向WEB服務(wù)器的標(biāo)準(zhǔn)輸入寫(xiě)信息。
WEB服務(wù)器一般將客戶(hù)方傳送來(lái)的信息放在它的標(biāo)準(zhǔn)輸出和相關(guān)環(huán)境變量中,而CGI程序則從環(huán)境變量和它的標(biāo)準(zhǔn)輸入(也就是WEB服務(wù)器的標(biāo)準(zhǔn)輸出)獲取所需的信息,程序的最終輸出結(jié)果則被寫(xiě)向它的標(biāo)準(zhǔn)輸出STDOUT(也就是WEB服務(wù)器的標(biāo)準(zhǔn)輸入)。WEB服務(wù)器將從它的標(biāo)準(zhǔn)輸入STDIN(也就是CGI程序的標(biāo)準(zhǔn)輸出)獲取CGI程序的輸出結(jié)果并將它傳送給客戶(hù)方??蛻?hù)方、WEB服務(wù)器和CGI程序之間的信息交流如圖1所示,顯然,WEB服務(wù)器就象是客戶(hù)方和CGI程序間的中介人。
WEB服務(wù)器、CGI程序間的這種標(biāo)準(zhǔn)框架在UNIX系統(tǒng)下和微軟視窗環(huán)境中的字符方式下可以工作得非常好,因?yàn)榇藭r(shí)系統(tǒng)所產(chǎn)生的所有進(jìn)程都可以存取標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出。但對(duì)于微軟視窗環(huán)境圖形方式下的程序就不行了,這是由于它們無(wú)法存取標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出。為了解決這一問(wèn)題,微軟在Win32系統(tǒng)中創(chuàng)建了另一類(lèi)型的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出,程序可以通過(guò)調(diào)用Win32 API函數(shù)存取標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出,不過(guò)這就意味著使用這類(lèi)標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出的CGI程序都必須是32位的。
微軟視窗環(huán)境下的其它一些WEB服務(wù)器(例如Website)則使用另外一種特殊的技術(shù)即利用INI文件來(lái)實(shí)現(xiàn)WEB服務(wù)器和CGI程序間的數(shù)據(jù)交流。采用這種被稱(chēng)為Win-CGI規(guī)范編寫(xiě)的CGI程序通常只能在部分WEB服務(wù)器上運(yùn)行。一般支持Win-CGI的WEB服務(wù)器將客戶(hù)端的輸入和有關(guān)的狀態(tài)信息寫(xiě)入一個(gè)INI文件中,而CGI程序則從該INI文件獲取相關(guān)信息,這類(lèi)程序的執(zhí)行效率將沒(méi)有標(biāo)準(zhǔn)CGI程序高。
在進(jìn)行CGI編程時(shí),您只要使CGI程序從標(biāo)準(zhǔn)輸入和環(huán)境變量中獲取客戶(hù)方提供的信息,把要傳送給客戶(hù)方的輸出結(jié)果寫(xiě)入標(biāo)準(zhǔn)輸出,剩下的信息傳遞工作WEB服務(wù)器將自動(dòng)完成。通用網(wǎng)關(guān)接口CGI只是規(guī)定了一個(gè)標(biāo)準(zhǔn)的接口規(guī)范,只要遵守這個(gè)標(biāo)準(zhǔn)規(guī)范,程序開(kāi)發(fā)人員可以利用各種編程工具例如Perl、C、Fortran、Visual Basic等進(jìn)行CGI編程??紤]到Visual Basic的強(qiáng)大的數(shù)據(jù)庫(kù)處理能力、客戶(hù)服務(wù)器模式的編程能力以及字符串處理能力,本文將介紹如何用VB編寫(xiě)標(biāo)準(zhǔn)的CGI程序。
一. 輸入輸出的處理
一個(gè)CGI程序被激活以后,它首先要做的事情就是確定系統(tǒng)平臺(tái)、WEB服務(wù)器和客戶(hù)端瀏覽器的狀態(tài)信息、客戶(hù)端用戶(hù)的輸入數(shù)據(jù),最后它還必須將相關(guān)信息能傳送給客戶(hù)端,否則它將一事無(wú)成。這些操作都是通過(guò)存取環(huán)境變量和標(biāo)準(zhǔn)輸入輸出完成的。用VB編寫(xiě)的CGI程序可以通過(guò)調(diào)用函數(shù)Environ( )來(lái)獲取相關(guān)環(huán)境變量的值。存取標(biāo)準(zhǔn)輸入輸出就要在程序中使用Win32API函數(shù)GetStdHandle( )、ReadFile( )和WriteFile( ),在使用這些函數(shù)時(shí)首先必須在程序中聲明它們。
以下的CGI程序說(shuō)明了在VB-CGI程序中如何處理環(huán)境變量和標(biāo)準(zhǔn)輸入輸出,該CGI程序非常簡(jiǎn)單,可以將標(biāo)準(zhǔn)輸入中的信息不經(jīng)任何處理就返回給客戶(hù)端,它可以被任何表單用POST方法激活:
Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, _
ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, _
lpOverlapped As Any) As Long
Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, ByVal lpBuffer As String, _
ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, _
lpOverlapped As Any) As Long
Public Const STD_INPUT_HANDLE = -10&
Public Const STD_OUTPUT_HANDLE = -11&
Public Const FILE_BEGIN = 0&
Public hStdIn As Long ’ 標(biāo)準(zhǔn)輸入文件句柄
Public hStdOut As Long ’ 標(biāo)準(zhǔn)輸出文件句柄
Sub Main()
Dim CGI_ContentLength As String,CGI_QueryString As String
Dim lContentLength As Long ’ 標(biāo)準(zhǔn)輸入中的字符串的長(zhǎng)度
Dim sBuff As String ’ 用于存儲(chǔ)標(biāo)準(zhǔn)輸入中的字符串
Dim lBytesRead As Long ’ 實(shí)際讀入的字符個(gè)數(shù)
Dim rc As Long
Dim sFormData As String
’調(diào)用系統(tǒng)函數(shù)生成標(biāo)準(zhǔn)輸入輸出文件句柄
hStdIn = GetStdHandle(STD_INPUT_HANDLE)
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
’獲取環(huán)境變量CONTENT_LENGTH的值,并將它轉(zhuǎn)換為整型
CGI_ContentLength = Environ("CONTENT_LENGTH")
lContentLength = Val(CGI_ContentLength)
sBuff = String(lContentLength, Chr$(0))
’從標(biāo)準(zhǔn)輸入中讀數(shù)據(jù)
rc = ReadFile(hStdIn, ByVal sBuff, lContentLength, lBytesRead, ByVal 0&)
sFormData = Left$(sBuff, lBytesRead)
OutPut "Content-type: text/html" & vbCrLf
OutPut "〈HTML〉〈HEAD〉"
OutPut "〈TITLE〉表單傳送數(shù)據(jù)的方法POST 〈/TITLE〉〈/HEAD〉"
OutPut "〈BODY〉〈H3〉表單傳送數(shù)據(jù)的方法POST〈/H3〉 "
OutPut "〈P〉本CGI 程序由Visual Basic編制! "
OutPut "〈P〉POST方法傳送的數(shù)據(jù): "
OutPut "〈P〉" & sBuff
OutPut "〈/BODY〉〈/HTML〉"
End Sub
Sub OutPut(s As String) ’ 定義一個(gè)向標(biāo)準(zhǔn)輸出寫(xiě)信息的函數(shù)
Dim lBytesWritten As Long
s = s & vbCrLf
WriteFile hStdOut, s, Len(s), lBytesWritten, ByVal 0&
End Sub