当进行 CGI 编程时您通常可以选择使用 CGI 模块或手工编写脚本。现在我们来看一看您使用 CGI 模块和它的源类能做些什么,如 CGI::Fast。虽然当一个 CGI 应用程序仅需使用少量的代码(例如当你分析
$ENV{QUERY_STRING} )或优先考虑运行速度时(例如你正在编译一个 200 KB 的模块),不使用预建立的模块而直接编写脚本会比较好。但通常来说,CGI 模块会更适用。
使用 CGI 模块的第一个优点是它不可替代的文件上传功能,这一点在不同的平台和浏览器中的体现稍有不同。CGI 模块提供了上传文件所需的所有工具,包括处理 HTTP 标题 和 cookies,从命令行运行脚本,以及支持 NPH 脚本和文件上传功能。此外,模块可以在面向对象的样式和面向函数的样式中方便的使用。
CGI 模块本身是一个复杂的甚至是极难懂的包含许多 Perl 语言特征的应用程序。所以不奇怪,某些专家认为如果您理解了 GGI.pm 模块,自然也就懂得了 Perl!由 Lincoln Stein 编写的 CGI.pm 是大多数通过 Perl 构建 Web 应用程序的开发人员所广泛使用的模块。您可通过 CPAN 获得该模块,请在 CGI.pm 页上参阅它的最新文档。
不幸的是,复杂的库通常包含精妙深奥之处从而增加了使用的难度。但另一方面,CGI
模块的复杂之处只在某种条件下才表现出来。例如,在 HTML
表单里执行文件上传功能,而 CGI 文档却未能告知所有功能。在下面的清单
1 里,用户把一个文件上传到 Web
服务器上。当处理表单时,脚本获得文件的内容并显示在浏览器中;它们被附在
<pre> 和
</pre>
标记之间。
清单 1. 文件上传代码样本
#!/usr/bin/perl -Tw
use CGI ':standard';
use strict;
my $out = start_multipart_form.filefield(-name => 'upload');
$out .= br.submit('submit','Send').end_form;
my$file = param('upload');
#the filename returned is also a file handle
if(request_method eq 'POST' &&
defined $file && ref $file && ref $file eq 'Fh')
{
local $/ = undef; #read the whole file
$out .= pre <$file>||'';
#takes care not to send uninitialized value
close $file if $CGI::OS ne 'UNIX';
#such as Win32 platforms
}
print header,start_html('Sample upload page'),$out,end_html;
|
在这里,
"$out .= pre <$file>||'';"
这一行是必需的。当用户发送一个空文件或键入无效的文件名时,菱形操作符返回未初始化定义的值,使
pre 函数无法正常运行。
此外,
$file
需要很多确认信息,因为当一个简单的表单使用
POST
方法时,
$file 不再是一个文件句柄。
某些操作系统需要显式地关闭临时文件。Win32 系统是这样的,但 UNIX 平台并不如此。
这些都是文档里没有指出的所有 CGI 模块的精妙之处,而就是这些精妙之处使得模块在这些情况下变得更为复杂。
调试代码时,在浏览器窗口显示语法和运行时错误会很有用。在我们看来,编写脚本的整个过程应包含编辑脚本文件,保存脚本及刷新浏览器窗口。让我们来看它是怎么工作的。
#!/usr/bin/perl -Tw
use strict; #restrict unsafe constructs
use CGI ':standard';
use CGI::Carp qw/carpout fatalsToBrowser set_message/;
use diagnostics -verbose;
#print warning diagnostics
BEGIN {
local *LOG;
my $size = -s "my.log" || 0;
open LOG, ">>my.log" or die "Can't open: $!";
carpout(\*LOG);
my $errors = 0;
sub handle_errors
#will be called with the text of the error
{
$errors = defined $_[0] && $_[0] || $errors, $size
}
set_message(\&handle_errors);
}
END {
my($errors, $size) = handle_errors;
if($errors)
{
local *LOG;
local $/ = undef;
open LOG, "my.log" or die "Can't open: $!";
seek LOG,$size,0;
#skip previous error log
local $_ = <LOG>;
close LOG;
s/&/&/g;
#replace special characters
s/"/"/g;
s/>/>/g;
s/</</g;
print "<table><tr><td bgcolor=linen><pre style='color:black'>";
print "<b>$errors</b>\n$_</pre></td></tr></table>";
}
}
print header,start_html('Test page'),'test',end_html;
|
现在看到的是一个关于代码调试的最完整和常见的示例(根据使用的模块)。虽然在正常情况下几乎不可能同时使用所有的技术,但是每一种都值得深入研究。
虽然
-w 标记和
"use strict;"
在这里很重要,但
-T
标记更是必不可少的,因为它会高亮显示脚本中的安全漏洞。
当诊断模块和 CGI::Carp
模块一起使用时,您会得到一些有趣的结果。CGI::Carp 把
$::SIG{__WARN__} 和
$::SIG{__DIE__}
的信号处理器设置成几乎相同的形式,
而诊断模块则扩展已安装的信号处理器。这就是在
use
语句中所包含模块的次序是非常重要的原因。此外,模块不允许把整个
STDERR
显示在浏览器窗口,结果,仅有一小部分模块的代码被使用了。
因为重复(而且烦人)的错误信息的存在,诊断模块所显示的附加错误数据不是每次都容易读的。这一点对
-verbose 标记尤为明显,该标记只有在第一次运行时才被使用。
该例中的另一个不理想之处是它相对长的编译时间,可通过将代码碎片复制到其它模块来避免。最好使用绑定的文件句柄把
STDERR
直接写到一个标量值里,接着在浏览器中显示错误信息,这样比把
STDERR 写到文件里要好。不幸的是,由于 Perl
的错误目前还不可能做到这一步。
Tie::STDERR 模块的设计者 Jan Pazdziora 承认“Tie::STDERR 能捕获编译时的错误,但只知道错误的存在,而无法知道原因。我也不知道如何修正。”所以目前唯一的解决办法是将
STDERR 重定向到文件中。
在完成脚本的设计和测试阶段后,也许跳过调试阶段而先把一小部分代码上传到服务器上会更好。Perl Diver(一个简单的 Perl 脚本)可以用来判定某些服务器特征(已安装模块、发送邮件的位置和环境变量等等)。您也可以看一下 脚本详细描述。
作为主要功能的补充,CGI 模块还有一些附加函数,其中包括一条 HTML 编写函数,据模块的设计者所说,“为了 CGI::* 模块,应该放弃使用该函数。”(HTTP::* 和 HTML::* 也应该补充在此处)。很多模块的函数并不总是方便使用的,这就是为什么经常使用 CGI.pm 来代替而放弃使用 HTML 编写函数的原因。CGI::Minimal 和 CGI_Lite 模块可以更好地完成该功能。
复杂的 CGI 脚本编写有时需要 Web 相关模块。它们的执行通常依赖特定的任务或通用 HTML 编写技术。有关这一点的模块清单可以从 CPAN (请参阅 参考资料)上获得,那里不仅有关于 Perl 的编程档案,还是编程理念的中心。我强烈建议您在编写复杂的脚本之前先访问 CPAN,这是非常值得的。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 请参阅
CGI
模块的最新版本和完整文档。
- 本文所有的源代码示例可以参阅
Official
Guide to Programming with CGI.pm (John Wiley & Sons,
1998)。
- 请参阅
comprehensive
Web server report(一个 Perl 脚本)。
- 请参阅该发行版中按模块名字母顺序排列的
CPAN
模块。
- 请查阅
O'Reilly Open
Books Project中的相关参考资料。
- 请阅读
Debugging CGI Scripts 上的文章,选自
Perl/PHP
Newsletter。
- 在
developerWorks 中,请阅读:
- Zope for the Perl/CGI programmer
- Server-side scripting languages
- Cultured Perl: One-liners 101
- Repurposing CGI applications with SOAP
-
Make
your software behave: CGI programming made secure
- 从
developerWorks上下载您的
IBM
Linux 开发工具包!
Eugene Logvinov 是 softPilot.2000 工程 (CONSUL Bureau, Sevastopol, Ukraine) 的网站开发人员。他是乌克兰 Kharkov 国立大学的三年级本科生,致力于 Web 开发和技术文献的新思想。可通过 rezonal@univer.kharkov.ua 和他联系。