为什么要用 Perl 来写 CGI
为什么要用Perl来写CGI 应用程序呢?
因为 Perl 有很强的字符串处理能力,尤其是利用关联性数组来作 CGI 应用程序剖析输入数据串,可以说是一个功能强大的语言。由于 Internet 上有大量的字符数据需要处理,因而在国外很多处理数据库的软件可以用 Perl 来沟通。现在 Perl 5.0 版本中增加了如下特色:
面向对象的用法、
增加对字符串的处理能力、
可以把整个文件当成一个字符串来处理、
不受任何数据的大小限制而只受存储器的大小限制、
能够处理 DBM 数据库格式的数据,也能够处理二进制的数据 等等,
更重要的是 Perl 还可以在 UNIX、WindowsNT、Windows95、Dos、Linux、FreeBSD、OS2、Macitosh 等众多操作系统中使用。
另外 Perl 很容易学习和入门,虽然要精通需要一定的时间。它的语法和 C 语言很接近,对于原本熟悉 C 语言的人来说,Perl 是很容易上手的。只要几个小时的学习就可以很轻易地用 Perl 语言写一个简单的 CGI 应用程序;至于那些没有 C 语言基础的人,也只要多花一点时间来熟悉,也是可以很快地掌握 Perl 语言。
Perl 作为编写 CGI 的语言虽然很好,但是对于复杂的网络应用就不是很有效了,这主要来源于 Apache 与 Perl 的配合。每一个 Perl 的 CGI 程序在被 Apache 调用执行的时候都必须开一个单独的进程来完成。而 Linux/UNIX 操作系统下,进程是一个非常消耗系统资源的实体,作为访问量巨大的网络服务器,如果只用 Perl 来完成 CGI 所需的功能将会使服务器不堪重负。所幸的是现在有一个 Apache 的专用模块,Emb-Perl,其语法与 Perl 几乎相同,但是他由于采用少量后台进程来循环供 Apache 使用,因此大大提高了运行效率。关于 Emb-Perl方面的知识在我们本次系列讲座的应用部分有专门的介绍,这里就不多谈了。
虽然 Perl 不是专门用来编写 CGI 的,而且 Perl 的功能远远超过编写 CGI 程序,但是 Perl 依然不失为一个优秀的 CGI 程序语言。而且许多人一开始接触 Perl 也是从 CGI 开始的,下面我们就来举几个小例子,来快速了解和体会 Perl 的 CGI 程序。
6.2 几个简单的 Perl CGI 程序
由于我们还没有讲解详细的 Perl 语法,所以下面讲解的例子可能会有一些不太明白的地方,不过没有关系,我们快速看几个 Perl 写的 CGI 程序的例子,获得一定的感性认识,等到这一讲结束后,相信同学们就可以弄清楚这些程序的含义了,而且也可以自己试着写几个 CGI 程序了。
用 Perl 来写 CGI,要求服务器必须已经配置好 Apache 和 Perl,关于这些服务器配置方面的问题同学们可以去听我们系列讲座应用部分的一些相关讲座,这里我们假定服务器已经配置妥当。
第一个例子是大家最常看到的计数器。我们用 vi 编辑如下这个程序(和 BASH 一样,除了 #! 所在的第一行以外,所有以 # 开始到行尾的部分都是注释):
#!/usr/bin/perl
# 输出 HTML 说明信息,让浏览器知道这是一个 HTML 格式的文档。
print "Content-type: text/html\n\n";
# 打开文件 count.txt 供读取,count.txt 文件中存储了一个整数。
open(CNT,"count.txt");
# 读取 count.txt 文件中的整数,存放到变量 $count 中。CNT 相当于 C 语言中的文件句柄。
$count=<CNT>;
# 如果该程序被执行,说明调用该程序的页面又被访问了一次,变量 $count 加 1。
$count ++;
# 把加 1 后的结果,和访问者的 IP 地址输出给浏览器。
print "你是第 $count 位访问者,来自 $ENV{'REMOTE_ADDR'} <br>";
# 关闭 count.txt 文件
close(CNT);
# 再打开另一个文件 count.old 用于永久保存加 1 后的计数值。(因为 $count 在程序执行结束后就没有了)
open(OLD ,">count.old");
# 将变量 $count,即加 1 后的结果写回 count.old 文件中。
print OLD $count;
# 关闭 count.old 文件
close(OLD);
# 执行 Shell 命令,将 count.old 文件复制成 count.txt 文件,此时这两个文件中都包含了最新的计数值。
`cp count.old count.txt`;
# 退出该程序
exit;
在需要计数的页面中插入下面这行:
<!--#exec cgi="/cgi-bin/counter.pl"-->
并将页面的文件名从 xxx.html 改为 xxx.shtml。这样下次再访问这个页面的时候,就可以在相应位置看到有个整数每访问一次就会自动加一。
下面再来看一个稍微复杂一点的例子。
#!/bin/usr/perl
# 输出 HTML 语句头
print "Content-type: text/html\n\n";
print "<TITLE> Quiz </TITLE>";
print "<H1> 在线测验 </H1>";
# 调用 parse 函数
&parse;
# %ANSWER 是一个关联阵列 (以本表单为例 , 第一题答案是 A , 第二题答案是 C)一共有五题。
%ANSWER=("1","A","2","C","3","C","4","C","5","B");
# 为 正确题数/错误题数 均赋初值为零。
$right=0;
$wrong=0;
# 用 keys 这个函数将 FORM 的每个 KEY 取出存成一个阵列,再用 sort 这个函数来排序 (由小排到大) 。
foreach $Num (sort keys %FORM) {
# $FORM{$Num}所存放的是表单里 value 的值
print "第 $Num 题你所答的答案是:$FORM{$Num} ";
# $ANSWER{$Num}所存放的是%ANSWER这个关联阵列由 $Num 所对应出来 A,C,C,C,B
print "标准答案:$ANSWER{$Num} <br>";
# 计算答对和答错的题数。
if ($FORM{$Num} eq $ANSWER{$Num}) {
$right++;
} else {
$wrong++;
}
}
print "<p>您总共答对:$right 题;答错:$wrong 题</p>";
sub parse{
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs){
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;
}
}
这个例子在浏览器中的显示和执行结果是这样的。