文档库 最新最全的文档下载
当前位置:文档库 › CGI教程

CGI教程

CGI教程
CGI教程

CGI教程(1)

CGI是一个连接外部应用程序到信息服务器(比如HTTP或者网络服务器)的标准。一个简单的HTML文档是无交互后台程序,它是静态的,也就是说它处于一个不可变的状态,即文本文件不可以变化。相反地,CGI程序是可以实时执行地,它可以输出动态的信息。

举个例子吧,如果你想把Unix数据库”挂到”万维网上,并允许世界各地的人可以访问它。基本上,就就需要创建一个CGI程序,它的执行将传递信息给数据库引擎,并且把解雇返回给用户显示出来。这是一个网关的例子。

数据库例子是一个简单的思想,在实际应用过程中更为复杂。实际上没有什么不能挂到网络上面的。但是只有一件事情你必须记住:不管你的CGI程序是怎样,一定不能花太多的时间来处理。否则,用户就做在奔腾机前面静静地等着浏览器的显示结果,这势必伤透了”奔腾的心”。

下面讲讲CGI的特殊要求:

既然CGI程序是可执行的,那基本上就等价于世界任何地方的人可以在你的系统中运行CGI程序,所以这是一种不安全的事情。因此在使用CGI程序的时候,需要一些安全的预防措施。可能,一种有效的方法是将CGI程序放置在一个特殊的目录中,这样网络服务器件只是执行CGI程序而不是将它显示到浏览器中。这个特殊的目录通常处在网络管理员直接控制的目录,这样就可以阻止普通用户创建CGI程序。仍然有其它几种方法可以允许用户访问CGI脚本,但是这需要网络管理员为他进行一些设置。在这一点上,你可能有与网络管理员联系以获得访问CGI权限的冲动。

如果你有一个NCSA HTTPd服务器分布的版本,你将看到一个目录/cgi-bin。这个目录就是上面所提的特殊目录,它就是放置CGI程序的地方。CGI程序可以用任何的语言来编写,并且可以在以下的系统中执行:

C/C++

Fortran

PERL

TCL

任何的Unix shell

Visual Basic

AppleScript

采取什么的语言依靠你的系统支持什么语言而定的。如果你使用过一个编程语言如C或者Fortran,你就会知道在运行程序之前必须对程序进行编译。如果你进入这个目录,你就会发现一些CGI程序的源代码。但是如果你使用其中一种脚本语言,比如PERL、TCL或者Unix shell,脚本就只需要放置在/cgi-bin目录中,因为没有相关的源代码。许多设计人员喜欢使用CGI脚本而不使用编程语言,因为脚本比需要编译的程序语言更容易调试、修改和维护。

CGI教程(2)

怎样从服务器获得信息

每次客户端需要URL来对应CGI程序,服务器将实时执行它。程序将直接输出到客户端。关于CGI的公用的误解是你可以发送命令行选项和参数给你的程序,比如:

command% myprog -qa blorf

CGI为其它目的使用命令行,这样是不可能。相反,CGI使用环境变量来发送给程序它的参数。两个重要的环境参数是:QUERY_STRING和PATH_INFO。

QUERY_STRING被定义为在URL中跟在第一个?后面的内容。这个信息可以由ISINDEX文档或者通过HTML表单(利用GET action)来增加。它同样可以手动嵌入HTML 锚,这个HTML锚可以引用你的网关。这个字符串就是一个信息查询,比如用户想搜索archie数据库或者是你的反馈GET表单的编码结果。

这个字符串被在标准的URL编码,其格式将空格转换为+,并将特殊的字符利用%xx 十六进制编码。你为了使用它必须对它进行编码。

如果你的网关不是从表单来的编码结果,你同样可以利用命令行得到查询字符串。这就意味着查询字符串的每一个单词将在ARGV的不同部分。比如,查询字符串"forms rule"将以argv[1]="forms" 和argv[2]="rule"传递给程序。如果你选择这个,你在使用它之前不必做任何的处理。

下面讲讲PATH_INFO 。CGI允许为你的网关在URL中嵌入额外的信息,这个网关可以用于传递额外的信息给脚本。这个信息通常是处在URL的网关路径之后的额外信息。这个信息不能在服务器中以任何的方法来编码。

最亦用的PATH_INFO例子是传递文件位置给CGI程序。为了阐述这个,假设我们有一个CGI程序在服务器中,名为/cgi-bin/foobar,它可以处理在服务器的DocumentRoot 中的文件。这时我需要通知foobar哪个文件要被处理。通过包括额外的路径信息到URL 的末尾,foobar通过PATH_INFO环境变量就知道了文档位置相关的DocumentRoot,或者通过PATH TRANSLATED环境变量(服务器为你产生的)来知道文档的真实路径。

CGI教程(3)

怎样发回文档给客户端

对于CGI的初学者,一个公共的错误是没有正确格式化输出,这样服务器不能解释它。

CGI程序可以返回各种文件类型。它们可以返回给客户端一张图片、HTML文档、明文文档或者可能是一个音频夹。它们同样可能返回其它文档给引用。客户端必须知道哪种类型的文档你要发送,这样它就可以相应地将它显示出来。为了让客户端知道这个,CGI程序必须通知服务器哪种类型的文档将被返回。

为了通知服务器哪种类型的文档你想送回,而不管这个文档是一个完整的文档或者一个引用,CGI要求你放置一个短的数据头到输出中。这个数据头是一个ASCII文本,它包含了被linefeeds 或者carriage返回的行,其后还跟着一个空白行。

在本例子中,你必须通过一个MIME类型通知服务器什么类型的文档你要输出。公共的MIME类型是一些比如html/text以及ASCII文本。

比如,为了返回HTML给客户端,你的输出代码为:

Content-type: text/html

output of HTML from CGI script

Sample output

What do you think of this?

如果不输出文档,你可以只通知浏览器哪儿可以得到这个新文档或者让服务器自动为你输出新的文档。

比如,假如你想从Gopher服务器中引用一个文件。折中情况,你应该知道你想引用和输出的完整的URL,代码如下:

Content-type: text/html

Location: gopher://https://www.wendangku.net/doc/9d1064587.html,/0

Sorry...it moved

Go to gopher instead

Now available at

a new location

on our gopher server.

但是,现在的浏览器很是聪明,它会自动将新文档显示给你而不会看到上面的内容。如果不想输出上面的HTML,NCSA HTTPd会为你输出一个缺省的文档来支持旧的浏览器。

如果你想引用你自己服务器上另外文件(没有受到返回验证的保护),你不必做太多的工作,而只需要输出一个不完全的URL,代码如下:

Location: /dir1/dir2/myfile.html

这时服务器就会认为客户端没有请求你的脚本,而是请求

http://yourserver/dir1/dir2/myfile.html。你要注意文件类型以及数据头对不对。

如果你想引用一个受到访问验证保护的文档,你就不得不键如完整的URL,因为客户端和服务器需要重新处理来建立你访问引用文档的连接。

HTML 表单

FORM(表单)标签

表单的标签在HTML文档中指定了一个表单。在一个文档中可以有多个表单,但是一点必

须注意表单不能嵌套。

...

具体属性如下:

ACTION是将要提交的表单中查询服务器的URL,如果这个属性是空的,那么当前的文

档URL将被使用。

METHOD是HTTP/1.0方法,它使用与提交表单给查询数据库。你使用哪个方法取决于你特定的服务器是怎么工作的。这里强烈推荐使用POST。当然你也可以使用GET。

POST和GET具体描述如下:

GET—这是一个缺省的方法,它将表单内容附加给URL,就好象它们是普通查询。POST --–这个方法是将表单内容作为一个数据体而不是URL的一部分传送给服务器的。

ENCTYPE 为表单内容指定编码。这个属性只有在METHOD被设置为POST的时候才应用,并且只有一种可能数值(缺省值为application/x-www-form-urlencoded)。

在表单中,你除了不能表单外,你可以使用INPUT(输入)、SELECT(选择框)以及

TEXTAREA(文本域)。

因为表单不会自动从文档的其余部分中区分开来。我们推荐在一个表单之前使用HR

(horizontal rule,水平线)标签来区分。

CGI教程(5)

INPUT(输入)标签

输入标签用于在表单中指定一个简单的输入元素。它是一个独立的标签,它旁边没有其它内容并且没有终止标签,它跟IMG的用法是一样的。

输入标签具体的属性为:

TYPE(类型)必须为以下的一种:

"text"(文本),这个是缺省的。

"password"(密码),看不到键入的字符,只有星号。

"checkbox" (复选框),是一个单一的切换按钮,有开和关两种状态。

"radio" (无线电按钮),单一的切换按钮,有开和关两种状态,可以组成一个组,用于多选一的操作。

"submit" (提交),它是一个按钮,将当前的表单包装到查询URL中并且将它发送到远程的服务器中。

"reset" (复位),也是一个按钮,它可以使表单中的各种输入复位到它的缺省数值。

NAME 是为输入区域的一个符号名字(不是显示的名字---表单中HTML通常使用的)。

VALUE是文本或者密码区域,它可以用于指定缺省区域内容。对于一个复选框或者一个无线电按钮,VALUE指定当它被选择的时候按钮的值。复选框或者无线电按钮的缺省值为”on”。对于"submit" (提交)and "reset"(重置),VALUE可以为按钮用于指定标志。

CHECKED (不需要数值)指定复选框或者无线电按钮被选中。它只适用于复选框或者无线电按钮。

SIZE 使指定输入区域字符串的大小,它只对文本区域和密码输入区域有效。如果这个没给出,缺省的设置为20。多行的文本输入区域可以指定为SIZE=width,height; 比如SIZE=60,12。这里注意:SIZE属性不应该要来指定多行文本输入区域因为TEXTAREA 标签是有效的。

MAXLENGTH 是可以接受的字符串的最大数目,它只适用于文本区域和密码区域。如果它没有设置则缺省的值是无穷大。如果MAXLENGTH大于SIZE则文本区域就可以滚动。

CGI教程(6)

SELECT(选择框)标签

...
里面有多少个SELECT标签都是允许的,它可以混合其它HTML元素(包括INPUT和TEXTAREA元素)和文本,但是不能包括FORMS。

. 不象INPUT,SELECT有和关闭标签。在SELECT里面,只有一系列的OPTION标签,每一个OPTION标签之后跟着一些文本,比如:

SELECT的属性有:

NAME是为这个SELECT元素起的名字。它不能为空,必须给出具体值。

SIZE:如果SIZE是1或者如果SIZE的属性没有,SELECT缺省为一个Motif option 菜单。如果SIZE为2或者更大,SELECT将作为一个Motif出现滚动的列表。这个SIZE 的数值决定了列表中有几项。

MULTIPLE:如果出现(它没有数值),它指定选择框可以进行多行选择。

OPTION的属性如下:

SELECTED 指定缺省状态这个OPTION被选择。如果SELECT允许多行选择,多个OPTION可以指定为SELECTED。

CGI教程(7)

TEXTAREA(文本域)标签

TEXTAREA标签被用来放置一个多行的文本输入区域。它有以下的属性:

NAME是文本域的名字。

ROWS 是文本域的行数。

COLS 是文本域的列数(即字符的水平宽度)。

TEXTAREA 域自动有滚动条。不论多少的文本都可以件入到里面。

TEXTAREA元素需要一个打开和关闭的标签即 。没有缺省内容的TEXTREA如下所示:

缺省内容必须是ASCII文本。

CGI教程(8)

表单的提交

下面先讲讲Method = GET:

当提交按钮被按下,表单的内容将被汇编到查询URL中,如下所示:

action?name=value&name=value&name=value

"action"由FORM标签设置的ACTION指定的URL,或者如果没有ACTION属性没有被指定的时候,是当前的文档URL。

在"name" 或者"value"任何实例中奇怪的字符都将被视为正常的字符,当然包括"=" 和"&"等等。这里注意,"="是分离名字和数值,而"&"示分离名字/数值对的。

对于文本和密码域,不管用户键入什么都将视为数值。如果用户没有键入任何的内容,这个数值将是空,但是"name="还是会出现。对于复选框和无线电按钮,VALUE属性指定了复选框或者无线电按钮被选中的时候的值。一个未选中的复选框会在汇编查询字符串的时候被忽视。多个复选框可以有相同的名字(和不同的数值)。多个无线电按钮是用于多选一的情况,它可以有相同的名字但是不同的数值。

再来谈谈Method = POST吧:

表单的内容跟上面讲述的GET方法的编码是一样的,但是不是将它们附加到URL由于表单ACTION属性指定为查询,而是这些内容将作为POST操作的一部分以数据块发送的。这个ACTION属性是数据块要POST的URL。

测试服务器

如果你想编写原型的表单并对它在查询服务器上进行测试,你可以编写如下代码:

对于METHOD="POST", 使用ACTION="https://www.wendangku.net/doc/9d1064587.html,/cgi-bin/post-query"

对于METHOD="GET", 使用ACTION="https://www.wendangku.net/doc/9d1064587.html,/cgi-bin/query"

CGI教学:第一章cgilib例

一个简单的读取并处理表格请求数据的cgilib.pl例子:

#!/usr/bin/perl

sub readGetData{

# 指定局部变量queryString用以保存和传递函数的参数

local(*queryString) = @_ if @_;

# 读取环境变量QUERY_STRING的值赋给变量$queryString

$queryString = $ENV{"QUERY_STRING"};

return 1;

}

sub readPostData{

local(*queryString)=@_ if @_;

local($contentLength);

# 读取环境变量CONTENT_LENGTH的值

$contentLength = $ENV{"CONTENT_LENGTH"};

# 检查是否有数据

if($contentLength){

# 从设备STDIN读取contentLength长度的字符赋给$queryString read(STDIN,$queryString,$contentLength);

}

return 1;

}

sub readData{

local(*queryString) = @_ if @_;

# 读取环境变量REQUEST_METHOD

$requestType=$ENV{"REQUEST_METHOD"};

# 如果请求方式为GET则使用函数readGetData # 否则如果请求方式为POST则使用函数readPostData

if($requestType eq "GET"){

&readGetData(*queryString);

}

elsif($requestType eq "POST"){

&readPostData(*queryString);

}

return 1;

}

sub DecodeData{

local(*queryString)= @_;

# 把加号转换成空格

$queryString=~s/\+/ /g;

# 转换十六进制字符

$queryString=~s/%(..)/pack("c",hex($1))/ge;

return 1;

}

sub parseData{

local(*queryString,*formData) = @_ if @_;

local($key,$value,$curString,@tmpArray);

# 以&为分隔符把字符串转换成键-值对

@tmpArray = split(/&/,$queryString);

# 在数组@tmpArray内循环

foreach $curString(@tmpArray){

# 以=为分隔符分开键-值对

($key,$value) = split(/=/,$curString);

# 解码

&DecodeData(*key);

&DecodeData(*value);

# 把键和值加到字典中

$formData{$key}=$value;

}

return 1;

}

1;

#end of file cgilib.pl

使用方法:

要使用此库需含下列语句:

#require "cgilib.pl";

表格数据处理:

%dataDict=();

&readData(*data);

&parseData(*data,dataDict);

字典数据处理:

while(($key,$value)=each(%dataDict)){

print $key,"=",$value,"\n\n";

}

CGI教学:第二章动态创建图像

―动态文档‖不仅指文本,CGI程序可以创建图象、声音等各种媒体。你只须输出相应的

MIME头、一行空行及原始数据即可。

下例的image.cgi将装载一个GIF图像文件并送到浏览器显示:

#!/usr/bin/perl

$file = '/usr/local/etc/httpd/htdocs/images/picture.gif';

print "Content-Type: image/gif\n\n";

open(GIF,"<$file") || die "Can't open GIF\n";

while (read(GIF,$buffer,16384)) {

print $buffer;

}

image.cgi首先发送MIME头说明(Content-Type),然后读取文件内容并输出。这

段程序对$file变量和Content-Type类型略加修改就可以发送声音或影像文件。

那么怎样把CGI程序创建的图像嵌到页面中呢?SSI是不行的,方法是用标签,

语法如:

仅就显示picture.gif这幅图像而言,用上述的image.cgi是没有什么意义的,更恰当

的方式是这样使用:

但是,image.cgi可以扩展功能来做更多的事。例如它可以从多个图像文件中随即地选择一个来显示,那么,每一次访问该页面时都会出现不同的图像。

计数器程序通常利用标签的这一特性,尤其是那些不允许解析HTML和SSI的服务器特别实用。服务器端不解析HTML文件可以降低服务器的负载。

此外,除了简单的装载并显示已有的图像文件外,可以真正的动态生成所需的图像。你可以设计一个CGI程序根据不同的参数及用户定义的一些细节来实时创建相应的图像(如图表)并显示。这种程序的复杂性在于图像的生成而不在于将图像输出给浏览器。幸运的是,有一些库提供了这样的接口,如Thomas boutell的gd图像库,这是生成GIF图像的一个出色工具,可以从https://www.wendangku.net/doc/9d1064587.html,/tppmsgs/msgs0.htm#29来下载。它是用C语言写的,但是有Perl接口库gd.pm,还有基于gd支持多种语言的接

口库tgd和fly。详细情况见上述gd主页。

下面是一个简单的用位图动态生成图像的计数器程序,对理解上述描述应该会有所帮助。

(源代码下载)

您是第位访问本网页的人。

附:GIF的说明

现在流行着一种趋势,即远离GIF格式而采用Portable Network Graphic格式(PNG),这种变化出于技术和法律两个方面的考虑。1995年1月1日,Unisys声称他们有权要求使用LZW压缩算法的软件公司要经过他们的许可或付给他们报酬,因为他们拥有专利使用权。而GIF格式正是使用这种算法。所以,你所编写的任何用于商业应用程序中的GIF图像(包括以CGI/WWW为基础的那些文件),都必须购买许可证或支付费用。许多软件包不再压缩GIF文件(这样会使图像变得很大),或者把GIF文件及其支持软件全部去掉。PNG使用非专利的压缩算法,从而避免了这些麻烦。在技术方面,PNG提供了较好的压缩算法(无损失,像GIF一样,但不像JPEG。JPEG在压缩时会丢失数据)、二维交互以及24位和48位真彩支持。现在,很少有浏览器支持内插的PNG 图像,但不久的将来,这种情况很可能会改变。GD图形库文件说明了PNG支持即将来临。

CGI教学:第三章计数器的编写方法

一、记录(log)文件

1、grep

2、page-stats

3、wusage

二、创建自己的计数器

1、使用DBM文件

2、文本文件

3、文件锁定

4、输出计数结果

5、www Homepage Access Counter

6、使用GD图形库

计数器(Access Counter)可以记录网页被访问的次数,在万维网上的使用十分普遍,其编写方法很多,从简单的SSI命令到用CGI程序生成内嵌图像等。计数器除了记录点击次数外,还可以记录访问者的IP、OS、浏览器类型等内容,使你对自己网站的访问情况有个全面的了解,本章主要介绍点击次数的统计和显示方法。

一、记录(log)文件

1、grep

对于Web服务器而言,都有记录文件记录着详细的访问信息,其名称通常为

access_log,下面是一个例子:

01: https://www.wendangku.net/doc/9d1064587.html, - - [02/Oct/1995:20:18:05 -0500] "GET

/phoenix/ HTTP/1.0" 200 2330

02: https://www.wendangku.net/doc/9d1064587.html, - - [08/Oct/1995:19:56:45 -0500] "HEAD /

HTTP/1.0" 200 0

03: https://www.wendangku.net/doc/9d1064587.html, - - [09/Oct/1995:07:54:56 -0500] "GET /leading-rein/orders HTTP/1.0" 401 -

04: https://www.wendangku.net/doc/9d1064587.html, - - [10/Oct/1995:11:11:40 -0500] "GET /

HTTP/1.0" 200 1529

05: https://www.wendangku.net/doc/9d1064587.html, - - [10/Oct/1995:11:11:43 -0500] "GET

/accn.jpg HTTP/1.0" 200 20342

06: https://www.wendangku.net/doc/9d1064587.html, - - [10/Oct/1995:11:11:46 -0500] "GET

/home.gif HTTP/1.0" 200 1331

07: https://www.wendangku.net/doc/9d1064587.html, - - [12/Oct/1995:08:04:27 -0500] "GET

/cgi-bin/env.cgi?

08:

SavedName=+&First+Name=Eric&Last+Name=Herrmann&Street=&C

ity=&State=&

09:

zip=&Phone+Number=%28999%29+999-9999+&Email+Address=& 10: simple=+Submit+Registration+ HTTP/1.0" 200 1261

11: https://www.wendangku.net/doc/9d1064587.html, - - [14/Oct/1995:16:40:04 -0500] "GET /leading-rein/index.cgi?unique_id=9658-199.170.89.58-813706781

HTTP/1.0" 200 1109

注;当主页在srm.conf中被命名为welcome.html、index.cgi、index.shtml等时,对其的访问记录,可能只含有目录名而不包含该文件名。

我们可以用UNIX命令grep来统计主页被访问的次数,grep命令通常输出每一行匹配结果,但可以加上参数-c以输出匹配行的数目,grep详见UNIX帮助。下面是一个简单

的例子grep.cgi:

1: #!/usr/local/bin/perl

2: print "content-type: text/html\n\n";

3: $num = `grep -c 'GET / HTTP' /your-server-root/logs/access_log` ;

4: $num += `grep -c 'GET /index.shtml'

/your-server-root/logs/access_log` ;

5: $num += `grep -c 'GET /index.html' /your-server-root

/logs/access_log` ;

6: print "$num\n";

现在就可以在主页中加上SSI指令来显示计数了,例如:

01:

02: grep test

03:

04:


05: This page has been accessed

06: times.

07:


08:

09:

别忘了把此文件扩展名改为.shtml。在grep.cgi中,grep命令中包围模式的单引号告诉UNIX shell不改变该串的内容以精确匹配。

这种方法有许多缺陷,首先是效率低,用grep来匹配花时间较长,可能要几秒钟的时间,这对一个简单的文本计数器而言太长了。其次,对每一个需要计数器的页面CGI文件均不相同。最后一个对某些人来说不算是个问题,就是要把Web服务器设置成允许SSI执行,

即将其目录映射略加修改。

2、page-stats

有一个叫page-stats的程序较好地解决了grep的问题。它查看HTTP daemon的access_log并寻找在标识文件中指定网页的访问,然后计算其数目并生成一个HTML 形式的统计页面。这样,你既得到了页面的详细统计信息,同时又得到了可显示的结果页面,这样的例子可在https://www.wendangku.net/doc/9d1064587.html,/tppmsgs/msgs0.htm#35找到。还可以用grep命令在统计页面中查找所需信息并生成自己的显示形式,这样速度就快多

了。

注意不应在建立自己的统计时运行该程序,否则会导致冲突。应该把它放到任务列表中用UNIX命令cron定时执行,每天、每小时甚至每几分钟运行一次。cron详见UNIX帮

助。

3、wusage

另外一个广为应用的服务器统计程序是由Thomas Boutell(boutell@https://www.wendangku.net/doc/9d1064587.html,)编写的应用于整个服务器的wusage,它生成很详细的信息,包括服务器怎样、何时及从何处被访问等等。它每周运行一次,可以生成漂亮的图表结果,十分直观。

使用wrsage要求使用ncSA或CERN的Web Server或任何有标准记录文件格式的

服务器,还需要有C编译器,wusage可在

https://www.wendangku.net/doc/9d1064587.html,/tppmsgs/msgs0.htm#36得到。

随着时间推移,access_file会越来越庞大,必须定期截留,这时先查看最近一周wusage 是否已生成了完整的报表,确定统计结束时间,然后把access_log中该时间前的访问记录删掉,并把wusage生成的结果保存在一个目录中,以便wusage可以生成过去访问

情况的图表。

二、创建自己的计数器

除了使用access_log记录文件外,我们可以创建自己的计数器。这时首先必须决定用何种形式存贮计数结果,是用文本文件还是用DBM文件,然后要决定是否进行文件同步访问的保护,这是用文件锁定来实现的,最后就是确定数据的存贮格式了。

1、使用DBM文件

对DBM文件而言,常用的函数有dbmopen()、dbmclose()、reset()、each()、values()和keys(),用于计数器时,主要使用前两个函数。dbmopen()函数把DBM

文件与关联数组绑定,调用语法为:

dbmopen (%array_name, DB_filename, Read_write_mode);

如果这时指定的数据库文件不存在,则自动创建两个名为DB_filename.dir和DB_filename.pag的文件,除非把读写模式设为undef值。

缺省的,只有64个记录被读进内存,可以通过给%array_name分配大小来改变此缺省值。如果你只是给自己的网页做计数,缺省值已经足够了,但如果是给整个服务器建立

计数器,一般需要更大的值。

现在看看这三个参数。当调用dbmopen时,%array_name原有的值都被清除(如果有的话),用DBM文件中的值替换掉,给之赋予新值很简单:

$array_name{'new_key'} = value; 当调用dbmclose (%array_name);语句时绑定被解除,关联数组中的内容被写如DBM文件,也可以不关闭文件而将内容写入,方法是调用reset (%array_name);语句,注意此语句并不是重置DBM文件,而是将内存中的数据写入文件。第二个参数DB_filename是不包含扩展名的,至于读写

模式详见本教程的语言部分。

下面是个使用DBM文件的计数器的简单例子:

1: dbmopen(%COUNTERS,

$DOCUMENT_ROOT/DBM_FILES/counters,0666);

2: if(!(defined($counters{'my_counter'})){

3: $counters{'my_counter'}=0;}

4: $counters{'my_counter'})++;

5: $count=$counters{'my_counter'};

6: dbmclose (counters);

2、文本文件

如果不用DBM文件而用文本文件,除了打开、关闭文件外,还要涉及到数据的读写问题,必须确定合适的数据格式,基本步骤如下:1)打开文件

2)读取计数

3)自增

4)写入新值

5)关闭文件

3、文件锁定

当更新文件内容时,该文件可能同时被另一个进程修改。对计数器程序而言,如果两个或多个人同时访问页面调用了计数器程序,就会出现多个进程同时修改同一文件的情况,这样有的进程的修改就会失效。当然这并不是太大的问题,只是失去一些计数而已,不过计数器就不准确了,访问的人越多,这个问题就越大。解决办法就是修改时通知其它试图打

开该文件的进程等待,或叫文件锁定,修改完再释放,允许其它进程打开文件并修改。有两种方法,一是创建自己的锁定机制,一种是使用系统函数flock()。

1)创建自己的文件锁

这种方法具体实现是创建和删除一个特定名称的文件,这在资源共享机制中通常称作

semaphore。下面是个例子:

01: While(-f counter.lock){

02: select(undef,undef,undef,0.1);}

03: open(LOCKFILE,">counter.lock);

04: dbmopen(%COUNTERS,

$DOCUMENT_ROOT/DBM_FILES/counters,0666);

05: if(!(defined($counters{'my_counter'})){

06: $counters{'my_counter'}=0;}

07: $counters{'my_counter'})++;

08: $count=$counters{'my_counter'};

09: dbmclose (counters);

10: close(LOCKFILE);

11: unlink(counter.lock);

首先检查锁定标志文件是否存在,如果存在,就说明另一个进程正在使用该文件,于是等待直到该文件(此处命名为counter.lock)不存在为止。此处用select()的特殊形式循环等待,此语句使程序进入休眠状态一段时间,该时间段由最后一个参数定义。之所以不用sleep()函数是因为其基本单位为秒,对这种文件锁定而言太长了,几个微秒就足够了。当锁定标志文件不再存在,就创建自己的锁定标志文件并开始修改计数,完成后关闭该文件并用unlink函数将之删除,这样其它的进程又被允许修改计数。锁定标志文件并不是特殊的文件,其文件名也可以由你自己随意选择。

2)使用flock()

其实锁定文件是很普通的编程步骤,系统函数flock()提供了这一功能,如果在你的系统上不提供的话,可以使用前面介绍的方法自己实现。

flock()的语法为:

flock (filehandle, lock_type);

参数filehandle为用open()函数打开的文件句柄,lock_type可以为下面四个值之一:

1:定义共享锁。对计数器而言不适用。

2:定义排他锁。

3:定义非阻止锁。此处亦不用。

4:解除锁定。

使用flock()实现的文件锁定例子如下:

1a: dbmopen(%counters,"filename", 0666);

or

1b: OPEN(counters,"

2: flock(counters,2);

3: if(!(defined($counters{'my_counter'})){

4: $counters{'my_counter'}=0;}

5: $counters{'my_counter'})++;

6: $count=$counters{'my_counter'};

7: dbmclose (counters);

8: flock(counters,8);

4、输出计数结果

现在一切就绪,只剩下输出我们的计数结果了,有三种输出方法:

1)用上面谈到的SSI方法输出。

2)创建各种文本格式输出。

3)生成各种漂亮的图形结果输出,本教程的《动态创建图像》一章讲述了基本原理并提供了一个x-bitmap格式的小例子,下面介绍两个更完善和漂亮的程序/库,这两个例子均

需要C编译器。

5、www Homepage Access Counter

这是一个广为应用的网页计数程序,利用已有的GIF图象连接起来生成一个GIF图象,此程序是用C语言写的,有适用于各种操作系统的版本,可以在

https://www.wendangku.net/doc/9d1064587.html,/tppmsgs/msgs0.htm#37下载。它提供了很多参数,功能比较齐全,生成的图象结果也很漂亮,可以选择图像格式,其自带了一些数字样式,但你可以增加自己的数字图像生成各种想要的图像,

https://www.wendangku.net/doc/9d1064587.html,/digits/digits.htm提供了很多GIF数字图象。其参数通过QUERY_STRING传递,且必须是小写字母,下面是个较复杂的调用例子:

src="/cgi-bin/Count.cgi?ft=9|frgb=69;139;50|tr=0|trgb=0;0;0|wxh =15;20|md=6|dd=A|st=5|sh=1|df=count.dat" align=absmiddle>; 其参数详细说明和使用方法详见上述下载网址。如果有必要的话,研究并修改一下其源程

序可以使你生成更适合于自己需要的图象。

6、使用GD图形库

www Homepage Access Counter利用现有的数字图象简化了一部分的工作,其目的就是用于图形计数器。GD图形库的功能更加强大,不仅可以用于创建图形计数器,还可以生成各种统计图表,还提供了Perl接口库。GD及其衍生的程序详见本教程《动态创建

图像》一章。

在下载的程序中有一个名为gddemo.c的程序演示了其使用方法,在https://www.wendangku.net/doc/9d1064587.html,:8086/cgi.htm有其用于计数器的例子。下面是一个通过

GD.pm调用GD图形库生成图像的Perl程序例:

#!/usr/bin/perl

use GD;

# create a new image

$im = new GD:Image(100,100);

# allocate some colors

$white = $im->colorAllocate(255,255,255);

$black = $im->colorAllocate(0,0,0);

$red = $im->colorAllocate(255,0,0);

$blue = $im->colorAllocate(0,0,255);

# make the background transparent and interlaced

$im->transparent($white);

$im->interlaced('true');

# Put a black frame around the picture

$im->rectangle(0,0,99,99,$black);

# Draw a blue oval

$im->arc(50,50,95,75,0,360,$blue);

# And fill it with red

$im->fill(50,50,$red);

# Convert the image to GIF and print it on standard output

print $im->gif;

CGI教学:第四章设置Web Server以运行CGI

一、NCSA Server

二、CERN httpd

三、Netscape Server

四、IIS

一、设置NCSA Server或Apache Server以使用CGI

NCSA Server的CGI1.1只允许用下列两种方式激活用户服务器上的脚本:ScriptAlias 指令和AddType指令。这两条指令都放在srm.conf文件中,该文件一般在用户的服务器根目录的conf目录中。

ScriptAlias指令告诉服务器该目录中的所有文件都是脚本或者是服务器作为CGI文件执行的程序。该方法能保证用户的CGI程序在特定位置。AddType指令允许用户告诉服务器任何具有指定前缀的文件都是可执行文件。如果希望将CGI程序放在服务器中任何地方的话该指令即很有用。

1、ScriptAlias指令

ScriptAlias指令位于Server Resource Map文件(srm.conf)中,程序内容例如下:

DocumentRoot /usr/local/etc/httpd/htdocs

UserDir public_html

REdirect /HTTPD/ https://www.wendangku.net/doc/9d1064587.html,/

Alias /icons/ /usr/local/etc/httpd/icons/

ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/

DirectoryIndex index.html index.shtml index.cgi

IndexOptions FancyIndexing

AddIcon /icons/movie.gif .mpg .qt

AddIcon /icons/menu.gif

AddIcon /icons/blank.xbm

DefaultIcon /icons/unknown.xbm

IndexIgnore */.??* *~ *# */HEADER* */README*

DefaultType text/plain

AccessFileName .htaccess

srm.conf文件允许用户根据自己系统需要设置HTTP Server。它允许用户告诉服务器用户的主页在什么地方,目录中的哪个文档是索引文档,如果不存在索引文件的话将装载什么图片文件以显示文件的类型,等等。srm.conf及其他配置文件的说明可查阅https://www.wendangku.net/doc/9d1064587.html,/tppmsgs/msgs0.htm#34。

2、AddType指令

AddType指令是执行CGI程序的另一种方式,它是在srm.conf文件中加入下列行:AddType application/x-httpd-cgi.cgi

在自己的系统中设置了该指令后,任何在服务器控制范围内的扩展名为.cgi的文件都会被作为CGI程序执行而不是作为文本文件阅读。这意味着用户可以在他的个人目录中创建脚本并能执行它。但是如果脚本写得不正确,就可能导致对文件系统、口令文件等的不同类型伤害。

AddType指令可以扩展为允许扩展名不是.cgi的程序同样被执行。大家经常会看见以.pl (Perl脚本的常见扩展名)或.sh(Bourne Shell脚本的常见扩展名)结尾的脚本。如果想支持其他扩展名的程序,只需简单地将它们加入AddType指令中,如下所示:

AddType application/x-httpd-cgi .cgi .pl .sh

3、访问配置文件

为了支持CGI程序的执行必须多加入一条指令。在Server Root/conf目录中是一个名为access.conf的配置文件。该文件允许用户设置ServerRoot下的哪个目录能够访问的全局限制,甚至允许用户控制哪些站点可以访问这些目录。下面是access.conf文件的一个例子:

Options INdexes Exec CGI

Options Indexes FollowSymLinks

AllowOverride All

order allow,deny

allow from all

Exec CGI表示允许执行该目录中的CGI脚本。Options Indexes FollowSymLinks表示

允许索引(显示某文件夹中的内容)并能够遵循符号链(这就意味着在ServerRoot之外的文件也能被访问)。AllowOverride指令允许用户决定哪个指令可以被目录的.htaccess 文件覆盖。中设置了对该目录中允许使用GET方式的限制。在HTTPD中,部分指令的选项是GET、POST和PUT(目前PUT尚未实现)。order allow,deny一行告诉服务器先找allow行再找deny行。下一行则是告诉服务器允许所有站点访问该目录中的页面。

二、设置CERN HTTP服务器以使用CGI

CERN HTTP服务器(也称为W3C HTTP服务器)仅需要编辑/etc/httpd.conf文件即可支持在服务器内使用CGI程序。这个指令类似于NCSA Server使用的指令:

Exec /url-prefix/* /physical-path/*

其中/url-prefix/定义了客户能看见的路径,而/physical-path/则是包含脚本的目录的实际路径。

三、设置Netscape以使用CGI

首先要启动管理服务器。以root身份登录,并运行/ServerRoot/admserv/start-admin,缺省端口为81。然后启动浏览器连接。在Netscape Admin页面中,单击Select URL Mapping,从弹出窗口中选择Map a URL to a Local Directory。然后单击Select CGI and Server Parsed HTML,从弹出窗口中选择Activate CGI as a File Type。现在即可单击Browse Files并选择欲激活的目录。选择完目录后,单击I'd Like to Activate CGI as a File Type。在ServerRoot中即会看到Conf目录中的obj.conf配置文件中已加入了下列行:

NameTrans form="/cgi-bin" fn="pfx2dir" dir="/usr/local/web/cgi-bin" name="cgi"

name=cgi调用了下列行:

ObjectType fn="force-type" type="magnus-internal/cgi"

Service fn="send-cgi"

它告诉服务器此为一个CGI目录,其中的所有文件都将用Netscape内部提供的CGI执行。

四、设置IIS以使用CGI

在IIS上运行CGI有十个简单的步骤:

1)安装Internet Service Manager。

2)从列表中选择WWW Servive。

3)选择Properties/Service Properties命令。

4)单击Directories标签。

5)单击Add按钮。

6)指定自己的cgi-bin目录的完整路径(例如,c:\webfiles\scripts)。

相关文档