全部博文(54)
分类:
2006-05-24 23:53:10
第一章:基础的基础
1.1 为什么使用CGI?
我没有把什么是CGI放在基础篇的第一段,是因为实在很难说明白到底什么是CGI.
而如果你先知道CGI有什么作用,将会很好的理解CGI是什么这个概念。 CGI可以为我们
提供许多HTML无法做到的功能。比如a.一个记数器; b.顾客信息表格的提交以及统计;
c.搜索程序;d.WEB数据库等等。
用Html是没有办法记住客户的任何信息的,就算用户愿意让你知道。用Html也是无法
把信息记录到某一个特定文件里的。要把客户段的信息记录在服务器的硬盘上,就要用到
CGI. 这是CGI最重要的作用,它补充了Html的不足。是的,仅仅是补充,不是替代。
1.2 CGI是什么?
好了,现在我们来说到底什么是CGI.Common Gate Intergace听起来让人有些专业,
我们就管它叫CGI好了。在物理上,CGI是一段程序,它运行在Server上,提供同客户段
Html页面的接口。这样说大概还不好理解。那么我们看一个实际例子: 现在的个人主页
上大部分都有一个留言本。留言本的工作是这样的:先由用户在客户段输入一些信息,
如名字之类的东西。接着用户按一下“留言”(到目前为止工作都在客户端),浏览器把
这些信息传送到服务器的cgi目录下特定的cgi程序中,于是cgi程序在服务器上按照预定
的方法进行处理。在本例中就是把用户提交的信息存入指定的文件中。然后cgi程序给客
户端发送一个信息,表示请求的任务已经结束。此时用户在浏览器里将看到“留言结束”
的字样。整个过程结束。
1.3 选择你熟悉的编程语言
既然CGI是一种程序,自然需要用编程语言来写。你可以用任何一种你熟悉的高级语言,
C,C++,C shell和VB.值得特别指出的,有一种叫Perl的语言。其前身是属于Unix专用的
高级语言,其具有强大的字符串处理能力而成为现在写CGI,特别是表单类程序的首选。最
近它已经有了Window95,和winnt版本。你可以在搜索程序里找到在那里下载它。 VB是Ms
的杀手锏,从目前的情况看,微软公司正试图使VB无所不能。自然也包括在Internet 请各
位注意,VB开发的程序只能在windows平台上被执行,所以它有一定局限。 C Shell,经典
的语言。可惜能做的事情不多,而且必须在Unix平台下。 C,C++,正真的无所不能。可是
在写CGI的时候显得非常难以掌握。特别是缺乏可以灵活使用的字符串处理函数。对程序员
的要求也比较高,维护复杂。 最后要提醒各位,因为CGI是Server和Clinet的接口,所以
对于不同的Server,CGI程序的移值是一个很复杂的问题。一般对于不同的Server,决没有
两个可以互相通用的CGI.实际上 这就是CGI程序最复杂的地方。
1.4 安全
我想各位敏感的朋友又要问我关于安全性能的问题了。实际上CGI是比较安全的,至少
比那些没有数字签名的ActiveX控件要安全的多。除非你有意在程序里加入了破坏Server的
命令, 否则一般不会有什么严重的后果。而个人网站不向大众开放CGI目录,则因为怕各位
学习不精,无端增加服务器的负担,所以一般不提供。
小结:本章讲述了CGI基本概念,也说明了各种编程语言的优缺点,同时解释了为什么个人
网站不提供CGI的原因。接下来我们开始正式学习。
第二章 Html的表单基础知识
组成Cgi程序的是两部分,一部分是html页面,就是用户看到的东西。另一部分则是运
行在服务器上的程序。一般来说,我们先写html页面,再写程序。所以我们的学习页是这样,
先看看表单的写法,再去学习CGI程序。
对于html的表单,有比较复杂和详细的规定。但由于它们是属于html标准里的东西,所
以我不打算详细讲解。最好是你自己找本书看看。
Html表单
标记把输入域组合起来,并且说明了表单提交的方式和地点。Form标签有许
多属性,比如NAME等等。具体的属性,将在使用的时候说明。
在FORM里还有许多不同的标签,正是它们组成了表单的各种成分。
[VALUE='DEFAULT TEXT']>
该语句在HTML里产生一个文本标签,[]里表示该属性是可选的。
该语句产生一个提交按键,用于表单的提交。它提供一个发送表单的按纽,信息发向
2.Perl文件:请使用任意一个文本编辑器,输入后以env.pl保存到c:websitecgi-shl下。
#! perl
print"Content-type:text/htmlnn";print"
在完成上面的工作后,请打开浏览器,输入.当然如果你的
机器是以tcp/ip方式 连在局域网上,请把127.0.0.1改成你的ip地址(还有test.htm里的。)
然后按下那个键,当你的浏览器去向另一个 页面的时候,今天的任务就算是完成了。
第五章:第一个程序--环境变量
服务器与CGI程序交换信息的协作方式是通过环境变量实现的。无论什么请求,CGI程序总能在特定位置找到某些信息。无论环境变量怎样定义,总有一些变量有着特定含义。环境变量是一个保存用户信息的内存区。例如,所有的机器都有一个PATH环境变量,当在当前目录找布道文件时就要查找PATH变量。当服务器收到一个请求后,它首先要收集它能得到的所有相关信息,并把它放入内存。那么,服务器要收集什么信息呢?
关于服务器自身的详细信息
关于用户的信息信息
关于用户请求的信息
服务器不知道CGI程序到底需要那些信息,所以它把这些信息一起收集,那么如果有什么重要的东西就不会遗漏了。为了向你展示服务器收集那些环境变量,在上一期的教程里我已经为各位写了一个程序,该程序将几乎所有的信息都反映在了浏览器里。所以在进一步学习变量的时候,请首先把程序调试好。
环境变量
1.与服务器相关的环境变量
GATEWAY_INTERFACE | 服务器遵守的CGI版本 |
SERVER_NAME | 服务器的IP或名字 |
SERVER_PORT | 主机的端口号 |
SERVER_SOFTWARE | 服务器软件的名字 |
2.与客户机相关的环境变量
服务器了解你的CGI程序,但它一定不知道你的客户机环境。正因为如此,同客户机有
关的变量才是最重要的。因为它涉及到你的浏览器等等。
ACCEPT | 例出能被次请求接受的应答方式 |
ACCEPT_ENCODING | 列出客户机支持的编码方式 |
ACCEPT_LANGUAGE | 表明客户机可接受语言的ISO代码 |
AUTORIZATION | 表明被证实了的用户 |
FORM | 列出客户机的EMAIL地址 |
IF_MODIFIED_SINGCE | 当用get方式请求并且只有当文档比指定日期更早时才返回数据 |
PRAGMA | 设定将来要用到的服务器代理 |
REFFERER | 指出连接到当前文档的文档的URL |
USER_AGENT | 标明客户使用的软件 |
3.与请求相关的环境变量
每次服务器受到的请求都不可能是一样的。这意味着有许多CGI程序必须注意的信息。这些与请求相关的信息包含有用户调用的信息,用户如何发送请求,以及作为请求的一部分传送了多少(什么)信息。这些对你的程序来说是非常重要的,因此我们将化些时间详细地讨论一下其中的一些变量。特别是下面写出的三个变量。这三个变量相当重要。
REQUEST_METHOD
QUERY_STRING
CONTENT_LENGTH
你必须熟悉这三个变量,因为它们用来表示数据是如何送到CGI程序的;然后你所要要做的事情就是在这三个变量里取出数据,进行下一步的编程。其他的一些变量的用处很多,
你可以了解你的竞争对手正在调用你的程序,你可以辨别用户是否注册,或者你可以设置连接到你的CGI程序以便要求附加路径信息包含在请求之中——因此你不必猜测你的用户正在你的服务器的哪个页面上。
AUTH_TYPE | 服务器用的确认模式 |
CONTENT_FILE | 含有CGI程序的数据文件 |
CONTENT_LENGTH | POST请求中向标准输入(STDIN)发送的字节数 |
CONTENT_TYPE | 被发送数据的类型 |
PATH_INFO | CGI程序的附加路径 |
PATH_TRANSLATED | PATH_INFO对应的绝对路径 |
QUERY_STRING | 传送给CGI程序的URL的问号(?)之后的那一部分 |
REMOTE_ADDR | 最终用户的IP或主机名 |
REMOTE_USER | 如果用户合法,则是用户的组名 |
REQUEST_LINE | 发送给服务器的完整URL请求 |
REQUEST_METHOD | 作为HTTP的一部分请求而传送数据的方法,比如get。 |
SCRPT_NAME | 运行的脚本名字 |
第六章: 调查表
对于本章的程序——选票程序,我不想多说什么。我只是想在本程序内教给大家如何
使用perl语言或C语言如何处理字符串的实例。让我们先看看代码:
页面文件——pote.html
查询选举投票结果
CGI程序:——vote.pl
#!perl
print"Content-type:text/htmlnn";
print"
if($ENV{'REQUEST_METHOD'}eq"POST"){
read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'});
}elsif($ENV{'REQUEST_METHOD'}eq"GET"){
$buffer=$ENV{'QUERY_STIRNG'};
}
@pairs=split(/&/,$buffer);
foreach $pair(@pairs){
($name,$value)=split(/=/,$pair);
$value=~tr/+//;
$value=~s/%([a-f A-F 0-9][a-f A-f 0-9])/pack("C",hex($1))/eg;
$FORM{$name}=$value;}
$filename="/vote.dat";
%NAME=("A","张德陪","B","阿加西","C","桑普拉斯","D","贝克","E","顾懿");
if($ENV{'REQUEST_METHOD'}eq"POST"){
print"Content-type:text/htmlnn";
print"
print"
open(FILE,"<$filename")||die"不能打开文件,请和管理员联系n";
for($i=0;$i<2;$i++){
$file[$i]=
$file[$i]=~s/n$//;
}
close(FILE);
@item=split(/:/,$file[0]);
@vote=split(/:/,$file[1]);
for($i=0;$i<@item;$i++){
if($FORM{'idol'}eq$item[$i]){
$vote[$i]++;
last;
}
}
open(FILE,">filename")||die"Can't Open the file";
$item=join(":",@item);
$vote=join(":",@vote);
pirnt FILE "$itemn";
print FILE "$voten";
close (FILE);
print"
print"查询投票结果系统";
}
if($FORM{'command'}eq"view"){
print "HTTP/1.0 200n";
print "Content-type:text/htmlnn";
print"
print"
open (FILE,"$filename")||die"文件打开错误";
for($i=0;$i<2;$i++){
$file[$i]=
$file[$i]=~s/n$//;
}
close(FILE);
@item=split(/:/,$file[0]);
@vote=split(/:/,$file[1]);
print"
姓名 | $NAME{$item[$i]} | 票数 | ,td>$vote[$i]
}
这个程序是要各位学习Perl的分解字符串的功能。在Perl中,字符串操作
是非常简单的。
我对几句重要语句做一个分析:
if($ENV{'REQUEST_METHOD'}eq"POST"){
read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'});
}elsif($ENV{'REQUEST_METHOD'}eq"GET"){
$buffer=$ENV{'QUERY_STIRNG'};
}
这是一个非常常见的功能块,几乎所有的CGI程序都会用到它。它判断
页面使用何种方式提交变量。如果是post,就从STDIN里把变量读出,存到
变量buffer里。注意在perl里,变量是用$开头的。而$ENV{'CONTENT_LENGTH'}
则是读出该变量的长度,请注意CONTENT_LENGTH是一个环境变量。第二个if则
处理get情况,在get情况下,页面提交的信息是存放在环境变量QUERY_STIRNG中
的。所以$buffer也就是页面提交的信息。环境变量REQUEST_METHOD表示方式,
它的值是一个字符串,前面加上$ENV则表示读出该变量的值。
@pairs=split(/&/,$buffer);
foreach $pair(@pairs){
($name,$value)=split(/=/,$pair);
$value=~tr/+//;
$value=~s/%([a-f A-F 0-9][a-f A-f 0-9])/pack("C",hex($1))/eg;
$FORM{$name}=$value;}
以上功能块是一个分解过程。页面信息的提交往往是以“名称=值”的形式,
比如本例子中就是以“idol=顾懿”这样的形式提交的,所以我们要去掉字符串中
的"="等等信息,但同时要保留“idol”和"顾懿"之间的对应关系。$FORM{$name}
=$value做到这一点,这是一个关联数组。具体其中的语法,请各位自行查书。接
下来的就是文件的操作,但那已经不是本课的重点。所以就不多说了。
第七章:上传文件
上传文件是建立交互式网站的一个重要手段。一般来说,考虑到CGI程序的安全和一些敏感问题,服务器是不会轻易开放文件上传权利的。
今天的程序是由WEBSITE1.1附带的一个upload.exe程序,由VB编写而成。所以我要讲的也就是VB写WIN-CGI时候的一些问题。
VB写Win-CGI:
在Windows环境下,WEB服务器和一个Windows CGI之间是通过临时文件来传送数据的。这个
过程如下:
1.Web服务器接受一个客户机对Windows CGI程序的请求,这个请求也称为Windows CGI请求。
2.Web服务器把要传送给Windows CGI程序的数据放在一个叫CGI profile的主输入文件。在某些情况下,还会增加一个文件。
3.Web服务器执行CGI程序,把CGI profile作为它的第一个参数。
4.Windows CGI开始执行,服务器等待Windows CGI进程结束。在等待过程中,服务器还可以处理其他请求,比如另一个新的CGI进程或HTTP请求。
5.Windows CGI程序读取作为命令行参数的profile文件并完成必要的处理,CGI程序也许要使用porfile文件中的数据和其他相关的辅助文件中的数据。
6.在Windows CGI程序结束前,把它的应答写在profile文件指定的输出文件中。
7.得到CGI程序处理结果后,WEB服务器读取输出文件,看看输出数据是否要打包,并把最后数据发给客户机。
8.WEB服务器随后就删除处理这个请求时产生的临时文件。如果在服务器管理器注册时,不删除临时文件,则保留这些临时文件。总的说,基于文件的传输过程是比较古老的。但它是最常用的通讯方式。
CGI32.BAS
CGI32.BAS是给windows系列的使用者在VB4.0或更高的环境下开发Windows-cgi而写的一
个程序接口。本文假设你已经对VB编程非常熟悉,所以对于使用VB的过程我就省略不说了。
在写Win-CGI程序的时候,请将VB环境中的有效对象全部关掉(Custom controls),并将
CGI32.bas加入project中。随后创建一个子程序
CGI_Main()
Sub CGI-Main()
'Win-CGI程序内容end sub
对于CGI32.bas,如果你还没有,请在这里下载。
Sub Main()
On Error GoTo ErrorHandler
If Trim$(Command$) = "" Then ' Interactive start Inter_Main ' Call interactive main Exit Sub ' Exit the program End If
InitializeCGI ' Create the CGI environment
'=========== CGI_Main ' Execute the actual "script" '===========
Cleanup:Close #CGI_OutputFN Exit Sub ' End the program '——ErrorHandler:Select Case Err ' Decode our "user defined" errors Case ERR_NO_FIELD:ErrorString = "Unknown form field" Case Else:ErrorString = Error$ ' Must be VB error End Select
ErrorString = ErrorString & " (error #" & Err & ")" On Error GoTo 0 ' Prevent recursion ErrorHandler (Err) ' Generate HTTP error result Resume Cleanup '——End Sub
上面是一个Win-cgi的例子。
第八章:Form to Mail
Form to Mail
所谓Form to Mail的功能,就是在页面上建立一个表单(form),该表单内记录着用户的信息,当用户提交了此表单,程序自动将表单内容发送的管理员所设定的信箱里。听起来这非常简单,根本用CGI就可以写这样的功能。其实当然没有这么简单,实际上许多公司网页还要求此表单在提交时存如另一个数据库,这样就需要写CGI程序了。
为了便于解说form to mail的功能,我们这里不考虑复杂情况,只考虑最简单的情况。就是唯一的form to mail功能,其他的功能只要在程序内加入相应的程序块就可以了。
在Unix中,我们最多使用的就是Email网关,因为是CGI开发环境中少数几个标准unix工具之一。在CGI程序中发送e-mail的命令是mail和Sendmail.我比较喜欢sendmail,因为它功能更强,Sendmail从STDIN接受数据,遇到Eof或只包含。的一行信息就将信息发送出去。
Perl中使用Sendmail的一个方式是将mail内容写入一个临时文件,然后使用Cat,同时把输出管道与Sendmail命令相联系起来。
如:
open(EMAIL,“>tempfile $ $,txt”);
print(EMAIL,“stuff to be emailed …… la la la ……n”);
close(EMAIL);
system(“cat tempfile $ $,txt | /usr/sbin/sendmail $tokens(‘email’)”);
system(“rm tempfile $ $,txt”);
名字tempfile $$,txt中的$ $是Perl中的一个特殊变量,即进程号(PID)。之所以使用是为了避免两个用户同时启动这个程序会覆盖tempfile文件,使用这种方法每个tempfile都是唯一的。(由pid表示)。这种好的思想可以用在许多程序中。
Sendmail命令从关联数组元素$token(‘email’)中找到e-mail目标地址,你可以假设这个变量的值在用户提交的表单由用户输入。如果没有安全措施,这样做是很危险的,设想有恶意的用户在Web表单中给你如下地址: ;cd/;rm-R *分号是表示unix命令结束的符号并将命令提交unix命令解释器。精通web的人谁也不会在根目录运行httpd,这个例子将删除整个文件系统。所以在设计整个系统的时候,必须考虑到这种用户直接到达Shell的情况。
Windows 下的Form to Mail
很不幸,Windows没有类似于Unix的mail网关,不管是WinNt和Windows都无法做到类似的功能。当然也有些非常热心的程序员写过Dos接口的mail程序,但是相当不幸,此类程序直到现在也没有很成功的例子。它们的问题是过于占用系统资源,并非常容易被黑客攻击。所以这里我就不提供程序了。
第九章:Guest book
Guest-book在网页设计中占有相当重要的地位,以至于可以和记数器相提并论。留言本可以用许多编程语言来设计,当然使用最多的还是perl和vb两种。本次cgi教程我们将谈谈在编写Guest-book中最应该注意的问题,并将给出一个不算很完整的程序代码。同时提供一个C语言的win-cgi程序供大家下载。
就现在的情况来看,一个标准的guest-book程序一般包括三个文件。提交表单文件(form.html)、cgi处理文件(guest-book.cgi)和最后的输出文件(book.html)。有些vb程序以access数据库为后台存储格式,以方便用户查找留言。下图给出了guest-book的工作流程。
form.html首先我们来看看form.html的文件内容: