欢迎光临
我们一直在努力

中文版 Perl CGI 程式写作常问问题集(五)-CGI教程,CGI文档

建站超值云服务器,限时71元/月

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程式请在这里点一下</a>

———————————————————————-

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 在
先天上容易产生安全问题。 

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 中文版 Perl CGI 程式写作常问问题集(五)-CGI教程,CGI文档
分享到: 更多 (0)