学院首页>网络编程>CGI>用VB编写标准CGI程序

用VB编写标准CGI程序

作者: 来源: 添加时间:2006-5-21 20:58:20
 一般地,用VB编译生成的CGI程序不能正确处理中文信息。这主要表现在CGI程序向STDOUT输出的中文在Web页面上无法正确显示,可通过在该中文字符串后跟着输出一些空格来解决这个问题。当使用HTML标识符、对Web页面进行排版时,浏览器在显示该Web页面时会吃掉多余的空格而只保留一个。在这种情况下,这些空格对Web页面的外观基本上没有什么影响。如果使用HTML标识符、对Web页面进行排版,则由于空格不能被浏览器吃掉,所以Web页面的外观将会受到较大的影响。不过,这时可用HTML的表格、来代替对Web页面进行排版。 
  注意:整个CGI程序的主体必须放在MAIN()函数中。 
  二、URL译码与解码 
  由于Web服务器和浏览器不能正确处理一些特殊的字符,Web服务器和浏览器之间可能会因此而产生某种程度的误会,所以在数据被传送之前,浏览器都要对表单内客户输入的数据中的特殊字符进行URL译码。 
  例如,Web系统用“=”分解表单各元素的NAME和VALUE属性,用“&”分解不同表单元素的输入数据。如果在表单的输入数据中包含这些特殊的字符,并且表单的数据在传送给Web服务器前不作任何处理,则Web服务器将无法知道哪一个“=”、“&”是用户输入的,哪一个是浏览器加上的。在由表单属性ACTION定义的URL中,也可能会出现一些特殊的字符,当在CGI程序的名称和路径信息(Path Information)中出现“=”、“&”和“?”时,都会影响数据的正确传送。 
  URL译码(URL Encoding)就是将Web服务器所不能正确处理的特殊字符转换成它的十六进制数的形式,比如将“%”转换成“%25”、“=”转换成“%3D”等等。这些特殊的字符通常被称作Web系统的保留字符。在Web系统上无论是用GET方法还是用POST方法传送的数据都要进行URL译码。CGI程序要想处理表单传送来的数据,还必须对浏览器URL译码过的数据进行解码。 
因此,理解URL译码对于我们进行CGI编程是非常重要的。URL译码一般包括以下步骤: 
  1、浏览器将所传送的数据根据表单所包含的元素分解成“NAME=VALUE”形式,NAME和VALUE分别是表单元素的属性。其中,VALUE属性中存储客户机在表单中输入的数据:如果客户机没有输入数据,则VALUE存储的是表单定义的缺省值;如果缺省值也没有定义,则VALUE值为空。 
  2、代表表单中各元素的各个“NAME=VALUE”对被浏览器用“&”连接起来。 
  3、VALUE属性中存放的数据若含有空格,则被转换成“+”。 
  4、URL和输入数据中所包含的Web系统的保留字符必须被译码成其十六进制数形式。 
  5、被译码后的字符被表示成一个“%”和它们的十六进制数形式(即%HH)。 
  CGI程序从环境变量“QUERY_STRING”或标准输入中读入的数据是经过浏览器URL译码过的,故在使用这些数据以前还必须对它们进行URL解码。解码的目的是将数据还原成客户端用户在Web页面上输入时的形式。本文已经介绍了URL译码过程,URL解码过程与它正好相反,它一般包括以下步骤: 
  1、从浏览器用GET或POST方法所传送来的数据中找出代表各个表单元素所储存数据的“NAME=VALUE”对。 
  2、VALUE属性中所存放的数据若含有“+”,则被转换成空格。 
  3、将VALUE属性中所存放的数据的十六进制数“%HH”转换成相应的字符。 
  Web系统将汉字当成特殊的字符,对它也要进行URL译码。对于一个特殊的单字节字符(比如“/”),浏览器通常将它译码成十六进制数的形式(比如%2F), “%”表示它后面跟的是两位十六进制数。当VB程序对其进行处理时调用Chr$函数就可以将其恢复为原貌。而一个汉字则被浏览器译码成四位十六进制数(比如%D5%C5)。如果CGI程序还像以前那样分别调用Chr(D5)和Chr(C5),则由于D5、C5都不是正常的单字节十六进制数码,故Chr函数返回空,汉字将无法正确还原。正确的做法应该是将有关汉字的四位十六进制数一起传给函数Chr(如Chr(D5C5)),此时汉字才能被正确还原。 
  因此,可以让CGI程序对四位连续的十六进制数一起进行译码,以便使汉字能够被正确还原。但在这种情况下,当客户端用户输入了两个连续的Web系统保留字符时,CGI程序又可能把它们当成汉字来处理。这时可以让CGI程序在需要对四位连续的十六进制数进行译码时首先检查前面两位是否为Web系统的保留字符,如果是则仍然按照单字节的字符处理。不过如果客户端用户在表单内填写了很多汉字,则CGI程序的负担将会大大加重。事实上,在大多数情况下,客户端用户很少会使用两个连续的Web系统的保留字符,所以可以只让CGI程序对最容易出现的情形如“://”(当客户端用户在表单中输入某一URL时会出现这种情况)进行检查,本文下节提供的函数UrlDecode( )可以实现对汉字和Web系统保留字符的URL解码。 
  三、CGI编程实例 
  本节将用VB编写一个处理主页客户留言簿的CGI程序。除了要调用本文前面所介绍的Win32API函数外,程序中还调用了Win32API函数GetTempFileName() 来获得一个唯一的临时文件名。程序中的函数UrlDecode()用来对客户端的输入进行URL译码。函数GetCgiValue()则用来分解字符串,根据表单元素的NAME属性获取其VALUE值,并调用UrlDecode()函数对其进行URL译码。 
  本程序要求在留言簿文件guests.html中使用一个定位串“”,将文件的开始部分和具体的客户留言部分分开。CGI程序将在“”所在的位置插入客户新的留言。guests.html应具有如下所示的样式: 

  ………………………. 
   
  这种样式将保证最后的留言出现在留言簿的最前面。如果要想使最后的留言出现在留言簿的最后面,则只需将留言簿文件中的定位字符串“>”移到留言簿文件中客户留言部分和HTML文件结尾部分之间的位置就行了。 
整个程序的完整代码如下所示: 
  ’guestbook.bas 
  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 
  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 
  Public Const STD_INPUT_HANDLE = -10& 
  Public Const STD_OUTPUT_HANDLE = -11& 
  Public Const FILE_BEGIN = 0& 
  Public hStdIn As Long ’ 标准输入文件句柄 
  Public hStdOut As Long ’ 标准输出文件句柄 
  Public sFormData As String ’ 用于存储没有经过URL译码的用户输入数据 
  Public lContentLength As Long 
  Public CGI_RequestMethod As String 
   
  Sub Main() 
  Dim CGI_ContentLength As String, CGI_QueryString As String, sBuff As String, chinesetail As String 
  Dim lBytesRead As Long, rc As Long,I As Long 
  Dim sEmail As String, sName As String, sURL As String, sfrom As String, tempstring As String 
  Dim sComment As String, tempFileName As String, guestbook As String 
  ’CGI程序的初始化工作 
  hStdIn = GetStdHandle(STD_INPUT_HANDLE) 
  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE) 
  CGI_RequestMethod = Environ("REQUEST_METHOD") 
  CGI_QueryString = Environ("QUERY_STRING") 
  CGI_ContentLength = Environ("CONTENT_LENGTH") 
  lContentLength = Val(CGI_ContentLength) 
  sBuff = String(lContentLength, Chr$(0)) 
  OutPut "Content-type: text/html" & vbCrLf ’ 输出MIME类型 
  OutPut "" 
  If CGI_RequestMethod = "POST" Then 
   sBuff = String(lContentLength, Chr$(0)) 
   rc = ReadFile(hStdIn, ByVal sBuff, lContentLength, lBytesRead, ByVal 0&) 
   sFormData = Left$(sBuff, lBytesRead) 
  ElseIf CGI_RequestMethod = "GET" Then 
   sFormData = CGI_QueryString 
  Else 
   OutPut "Unknow Form Method !" 
  End If 
  chinesetail = String(400, " ") 
   ’为了在页面上正确显示中文,生成一个空格串以获取客户端用户的输入 
  sName = GetCgiValue("name") 
  sEmail = GetCgiValue("email") 
  sURL = GetCgiValue("URL") 
  sfrom = GetCgiValue("from") 
  sComment = GetCgiValue("URL_Comment") 
  ’对客户端用户的输入进行检查 
  If Len(sName) = 0 Then 
   OutPut "非常抱歉!您还没有填写姓名!" & chinesetail 
   Exit Sub 
  End If 
  If Len(sComment) = 0 Then 
   OutPut "非常抱歉!您还没有提出建议!" & chinesetail 
   Exit Sub 
  End If 
  ’获取唯一的临时文件名和留言簿文件并打开它们 
  tempFileName = TempFile("c:windowstemp", "gbk") 
  guestbook = "e:netscapeserverdocsguests.html" 
  Open tempFileName For Output As #1 
  Open guestbook For Input As #2 
  Do ’本循环体用于将留言簿中字符串""前面的内容写入临时文件 
  Line Input #2, tempstring 
  Print #1, tempstring 
  Loop While tempstring <> "" And Not EOF(2) 
  ’向临时文件中插入客户端用户的留言 
第 2 页,共 3 页 [1] [2] [3]
站内搜索