📄 204.htm
字号:
<p>用VB编写标准CGI程序(下)</p>
<p></p>
<p> </p>
<p>三、CGI编程实例 </p>
<p></p>
<p> 本节将用VB编写一个处理主页客户留言簿的CGI程序。除了要调用本文前面所介绍的Win32API函数外,程序中还调用了Win32API函数GetTempFileName()来获得一个唯一的临时文件名。程序中的函数UrlDecode()用来对客户端的输入进行URL译码。函数GetCgiValue()则用来分解字符串,根据表单元素的NAME属性获取其VALUE值,并调用UrlDecode()函数对其进行URL译码。 </p>
<p></p>
<p> 本程序要求在留言簿文件guests.html中使用一个定位串“<! ENDHEAD >”,将文件的开始部分和具体的客户留言部分分开。CGI程序将在“<! ENDHEAD >”所在的位置插入客户新的留言。guests.html应具有如下所示的样式: </p>
<p></p>
<p> <html> </p>
<p></p>
<p> <head><title>DHTML Zone </title></head> </p>
<p></p>
<p> <body bgcolor="#FFFFFF" text="#00000" vlink="#990000" link="#333399"> </p>
<p></p>
<p> <! ENDHEAD > </p>
<p></p>
<p> <!---客户的留言部分从这开始--> </p>
<p></p>
<p> <P>………………………. </p>
<p></p>
<p> <!---客户的留言部分结束于此--> </p>
<p></p>
<p> </body></html> </p>
<p></p>
<p> 这种样式将保证最后的留言出现在留言簿的最前面。如果要想使最后的留言出现在留言簿的最后面,则只需将留言簿文件中的定位字符串“<! ENDHEAD >”移到留言簿文件中客户留言部分和HTML文件结尾部分之间的位置就行了。整个程序的完整代码如下所示: </p>
<p></p>
<p> 注释:guestbook.bas </p>
<p></p>
<p> Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long </p>
<p></p>
<p> Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any,ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long </p>
<p></p>
<p> 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 </p>
<p></p>
<p> Declare Function GetTempFileName Lib "kernel32" Alias "GetTempFileNameA"(ByVal lpszPath As String, ByVal lpPrefixString As String, ByVal wUnique As Long, ByVal lpTempFileName As String) As Long </p>
<p></p>
<p> Public Const STD_INPUT_HANDLE = -10& </p>
<p></p>
<p> Public Const STD_OUTPUT_HANDLE = -11& </p>
<p></p>
<p> Public Const FILE_BEGIN = 0& </p>
<p></p>
<p> Public hStdIn As Long 注释: 标准输入文件句柄 </p>
<p></p>
<p> Public hStdOut As Long 注释: 标准输出文件句柄 </p>
<p></p>
<p> Public sFormData As String 注释: 用于存储没有经过URL译码的用户输入数据 </p>
<p></p>
<p> Public lContentLength As Long </p>
<p></p>
<p> Public CGI_RequestMethod As String </p>
<p></p>
<p> </p>
<p></p>
<p> Sub Main() </p>
<p></p>
<p> Dim CGI_ContentLength As String, CGI_QueryString As String, sBuff As String, chinesetail As String </p>
<p></p>
<p> Dim lBytesRead As Long, rc As Long,I As Long </p>
<p></p>
<p> Dim sEmail As String, sName As String, sURL As String, sfrom As String, tempstring As String </p>
<p></p>
<p> Dim sComment As String, tempFileName As String, guestbook As String </p>
<p></p>
<p> 注释:CGI程序的初始化工作 </p>
<p></p>
<p> hStdIn = GetStdHandle(STD_INPUT_HANDLE) </p>
<p></p>
<p> hStdOut = GetStdHandle(STD_OUTPUT_HANDLE) </p>
<p></p>
<p> CGI_RequestMethod = Environ("REQUEST_METHOD") </p>
<p></p>
<p> CGI_QueryString = Environ("QUERY_STRING") </p>
<p></p>
<p> CGI_ContentLength = Environ("CONTENT_LENGTH") </p>
<p></p>
<p> lContentLength = Val(CGI_ContentLength) </p>
<p></p>
<p> sBuff = String(lContentLength, Chr$(0)) </p>
<p></p>
<p> OutPut "Content-type: text/html" & vbCrLf 注释: 输出MIME类型 </p>
<p></p>
<p> OutPut "<FONT SIZE=""+2"">" </p>
<p></p>
<p> If CGI_RequestMethod = "POST" Then </p>
<p></p>
<p> sBuff = String(lContentLength, Chr$(0)) </p>
<p></p>
<p> rc = ReadFile(hStdIn, ByVal sBuff, lContentLength, lBytesRead, ByVal 0&) </p>
<p></p>
<p> sFormData = Left$(sBuff, lBytesRead) </p>
<p></p>
<p> ElseIf CGI_RequestMethod = "GET" Then </p>
<p></p>
<p> sFormData = CGI_QueryString </p>
<p></p>
<p> Else </p>
<p></p>
<p> OutPut "Unknow Form Method !" </p>
<p></p>
<p> End If </p>
<p></p>
<p> chinesetail = String(400, " ") </p>
<p></p>
<p> 注释:为了在页面上正确显示中文,生成一个空格串以获取客户端用户的输入 </p>
<p></p>
<p> sName = GetCgiValue("name") </p>
<p></p>
<p> sEmail = GetCgiValue("email") </p>
<p></p>
<p> sURL = GetCgiValue("URL") </p>
<p></p>
<p> sfrom = GetCgiValue("from") </p>
<p></p>
<p> sComment = GetCgiValue("URL_Comment") </p>
<p></p>
<p> 注释:对客户端用户的输入进行检查 </p>
<p></p>
<p> If Len(sName) = 0 Then </p>
<p></p>
<p> OutPut "<P>非常抱歉!您还没有填写姓名!" & chinesetail </p>
<p></p>
<p> Exit Sub </p>
<p></p>
<p> End If </p>
<p></p>
<p> If Len(sComment) = 0 Then </p>
<p></p>
<p> OutPut "<P>非常抱歉!您还没有提出建议!" & chinesetail </p>
<p></p>
<p> Exit Sub </p>
<p></p>
<p> End If </p>
<p></p>
<p> 注释:获取唯一的临时文件名和留言簿文件并打开它们 </p>
<p></p>
<p> tempFileName = TempFile("c:\windows\temp", "gbk") </p>
<p></p>
<p> guestbook = "e:\netscape\server\docs\guests.html" </p>
<p></p>
<p> Open tempFileName For Output As #1 </p>
<p></p>
<p> Open guestbook For Input As #2 </p>
<p></p>
<p> Do 注释:本循环体用于将留言簿中字符串"<! ENDHEAD >"前面的内容写入临时文件 </p>
<p></p>
<p> Line Input #2, tempstring </p>
<p></p>
<p> Print #1, tempstring </p>
<p></p>
<p> Loop While tempstring <> "<! ENDHEAD >" And Not EOF(2) </p>
<p></p>
<p> 注释:向临时文件中插入客户端用户的留言 </p>
<p></p>
<p> Print #1, "<hr>" & vbCrLf </p>
<p></p>
<p> Print #1, "<ul>" & vbCrLf </p>
<p></p>
<p> Print #1, "<li><b>留言时间</b>:" & Date$ & " " & Time$ & vbCrLf </p>
<p></p>
<p> Print #1, "<li><b>姓名: </b>" & sName & vbCrLf </p>
<p></p>
<p> If Len(sEmail) <> 0 Then </p>
<p></p>
<p> Print #1, "<li><b>E-mail: </b><a href=""mailto:" & sEmail & """ >" & sEmail & "</a>" & vbCrLf </p>
<p></p>
<p> End If </p>
<p></p>
<p> If Len(sURL) <> 0 Then </p>
<p></p>
<p> Print #1, "<li><b>我的主页: </b> <a href=""" & sURL & """ >" & sURL & "</a>" & vbCrLf </p>
<p></p>
<p> End If </p>
<p></p>
<p> If Len(sfrom) <> 0 Then </p>
<p></p>
<p> Print #1, "<li><b>我来自: </b>" & sfrom & vbCrLf </p>
<p></p>
<p> End If </p>
<p></p>
<p> Print #1, "<li><b>我的建议: </b>" & vbCrLf </p>
<p></p>
<p> Print #1, sComment & vbCrLf </p>
<p></p>
<p> Print #1, "</ul>" & vbCrLf </p>
<p></p>
<p> Do 注释:本循环体用于将留言簿剩余的东西写入留言簿 </p>
<p></p>
<p> Line Input #2, tempstring </p>
<p></p>
<p> Print #1, tempstring </p>
<p></p>
<p> Loop While Not EOF(2) </p>
<p></p>
<p> Close #1 </p>
<p></p>
<p> Close #2 </p>
<p></p>
<p> Kill guestbook 注释:删除旧的留言簿 </p>
<p></p>
<p> Name tempFileName As guestbook 注释:将临时文件改成新的留言簿 </p>
<p></p>
<p> OutPut "<P>非常感谢您的留言!" & chinesetail </p>
<p></p>
<p> OutPut "<P>欢迎您经常光顾本主页!" & chinesetail </p>
<p></p>
<p> OutPut "</FONT>" </p>
<p></p>
<p> End Sub </p>
<p></p>
<p> </p>
<p></p>
<p> Sub OutPut(s As String) 注释: 本子程序用于向标准输出写信息 </p>
<p></p>
<p> Dim lBytesWritten As Long </p>
<p></p>
<p> s = s & vbCrLf </p>
<p></p>
<p> WriteFile hStdOut, s, Len(s), lBytesWritten, ByVal 0& </p>
<p></p>
<p> End Sub </p>
<p></p>
<p> </p>
<p></p>
<p> Public Function GetCgiValue(cgiName As String) As String </p>
<p></p>
<p> 注释: 本子程序可以获取表单上某一元素的数据 </p>
<p></p>
<p> Dim delim2 As Long 注释: position of "=" </p>
<p></p>
<p> Dim delim1 As Long 注释: position of "&" </p>
<p></p>
<p> Dim n As Integer </p>
<p></p>
<p> Dim pointer1 As Long,pointer2 As Long,length As Long,length1 As Long </p>
<p></p>
<p> Dim tmpstring1 As String,tmpstring2 As String </p>
<p></p>
<p> pointer1 = 1 </p>
<p></p>
<p> pointer2 = 1 </p>
<p></p>
<p> delim2 = InStr(pointer2, sFormData, "=") </p>
<p></p>
<p> pointer2 = delim2 + 1 </p>
<p></p>
<p> Do </p>
<p></p>
<p> length = delim2 - pointer1 </p>
<p></p>
<p> tmpstring1 = Mid(sFormData, pointer1, length) </p>
<p></p>
<p> delim1 = InStr(pointer1, sFormData, "&") </p>
<p></p>
<p> pointer1 = delim1 + 1 </p>
<p></p>
<p> length1 = delim1 - pointer2 </p>
<p></p>
<p> If delim1 = 0 Then length1 = lContentLength + 1 - pointer2 </p>
<p></p>
<p> If tmpstring1 = cgiName Then </p>
<p></p>
<p> tmpstring2 = Mid$(sFormData, pointer2, length1) </p>
<p></p>
<p> GetCgiValue = UrlDecode(tmpstring2) </p>
<p></p>
<p> Exit Do </p>
<p></p>
<p> End If </p>
<p></p>
<p> If delim1 = 0 Then </p>
<p></p>
<p> Exit Do </p>
<p></p>
<p> End If </p>
<p></p>
<p> delim2 = InStr(pointer2, sFormData, "=") </p>
<p></p>
<p> pointer2 = delim2 + 1 </p>
<p></p>
<p> Loop </p>
<p></p>
<p> End Function </p>
<p></p>
<p> </p>
<p></p>
<p> Public Function UrlDecode(ByVal sEncoded As String) As String </p>
<p></p>
<p> 注释: 本函数可以对用户输入的数据进行URL解码 </p>
<p></p>
<p> Dim pointer As Long 注释: sEncoded position pointer </p>
<p></p>
<p> Dim pos As Long 注释: position of InStr target </p>
<p></p>
<p> Dim temp As String </p>
<p></p>
<p> If sEncoded = "" Then Exit Function </p>
<p></p>
<p> pointer = 1 </p>
<p></p>
<p> Do 注释:本循环体用于将"+"转换成空格 </p>
<p></p>
<p> pos = InStr(pointer, sEncoded, "+") </p>
<p></p>
<p> If pos = 0 Then Exit Do </p>
<p></p>
<p> Mid$(sEncoded, pos, 1) = " " </p>
<p></p>
<p> pointer = pos + 1 </p>
<p></p>
<p> Loop </p>
<p></p>
<p> pointer = 1 </p>
<p></p>
<p> Do </p>
<p></p>
<p> 注释:本循环体用于将%XX转换成字符。对于两个连续的%XX,如果第一个%XX不是某些特指的Web系统保留字符,将把它们转换成汉字 </p>
<p></p>
<p> pos = InStr(pointer, sEncoded, "%") </p>
<p></p>
<p> If pos = 0 Then Exit Do </p>
<p></p>
<p> temp = Chr$("&H" & (Mid$(sEncoded, pos + 1, 2))) </p>
<p></p>
<p> If Mid(sEncoded, pos + 3, 1) = "%" And (temp <> ":") And (temp <> "/") _ </p>
<p></p>
<p> And (temp <> "(") And (temp <> ")") And (temp <> ".") And (temp <> ",") _ </p>
<p></p>
<p> And (temp <> ";") And (temp <> "%") Then </p>
<p></p>
<p> Mid$(sEncoded, pos, 2) = Chr$("&H" & (Mid$(sEncoded, pos + 1, 2)) _ </p>
<p></p>
<p> & (Mid$(sEncoded, pos + 4, 2))) </p>
<p></p>
<p> sEncoded = Left$(sEncoded, pos) & Mid$(sEncoded, pos + 6) </p>
<p></p>
<p> pointer = pos + 1 </p>
<p></p>
<p> Else </p>
<p></p>
<p> Mid$(sEncoded, pos, 1) = temp </p>
<p></p>
<p> sEncoded = Left$(sEncoded, pos) & Mid$(sEncoded, pos + 3) </p>
<p></p>
<p> pointer = pos + 1 </p>
<p></p>
<p> End If </p>
<p></p>
<p> Loop </p>
<p></p>
<p> UrlDecode = sEncoded </p>
<p></p>
<p> Exit Function </p>
<p></p>
<p> End Function </p>
<p></p>
<p> </p>
<p></p>
<p> Public Function TempFile(sPath As String, sPrefix As String) As String </p>
<p></p>
<p> 注释:本函数可以获得一个唯一的临时文件名 </p>
<p></p>
<p> Dim x As Long,rc As Long </p>
<p></p>
<p> TempFile = String(127, Chr$(0)) </p>
<p></p>
<p> rc = GetTempFileName(sPath, sPrefix, ByVal 0&, TempFile) </p>
<p></p>
<p> x = InStr(TempFile, Chr$(0)) </p>
<p></p>
<p> If x > 0 Then TempFile = Left$(TempFile, x - 1) </p>
<p></p>
<p> End Function </p>
<p></p>
<p> </p>
<p></p>
<p> CGI程序guestbook.bas所要处理的表单如下所示: </p>
<p></p>
<p> <html><head><title>贵宾留言簿</title></head> </p>
<p></p>
<p> <body> </p>
<p></p>
<p> <h3>贵宾留言簿测试</h3> </p>
<p></p>
<p> <form action="/cgi-bin/guest.exe" method="post"> </p>
<p></p>
<p> 您的姓名: <input type="text" name="name"><br> </p>
<p></p>
<p> 您的Email信箱: <input type="text" name="email"><br> </p>
<p></p>
<p> 您的主页的URL: <input type="text" name="URL"><br> </p>
<p></p>
<p> 您的建议:<br> <textarea name="URL_Comment" rows=4 cols=30></textarea><br> </p>
<p></p>
<p> 您来自: <input type="text" name="from"><br> </p>
<p></p>
<p> <input type="submit" value=" 留言 "> </p>
<p></p>
<p> </form> </p>
<p></p>
<p> </body></html> </p>
<p></p>
<p> 虽然目前已经有很多可以取代CGI且其性能较CGI要高的技术(例如ASP、ISAPI、NSAPI等),但使用它们时需要用到专门的知识和工具,并且利用这些技术所编制的程序只适用于特定的Web服务器或系统平台。考虑到CGI编程具有易用易学性、跨服务器平台特性等优点,因此,CGI程序还将在WWW上占有一席之地。</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -