选择显示字体大小

perl cgi 程式写作常问问题集(五)


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 标签中的内容做进一步的处理或
利用,否则本例中最外围的一对括弧可去掉。

&#36;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=&quot;password&quot; 不是就是拿来做这个的吗?

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。以下为一例:

&#36;browser = &#36;env{'http_user_agent'};
if (&#36;browser =~ /mozilla/) {
#
#.netscape
#
} else {
#
# non.netscape
#
}

----------------------------------------------------------------------

q4.12: 为什麽我的 system() 所产生的资料输出顺序不对?

这是由於标准输出的产生方式通常是先累积相当的资料再输出(buffered)。要
让输出的资料以正确的顺序显示,您必须藉由 &#36; 这个变数的设定将
buffering
的特性关掉。

----------------------------------------------------------------------

q4.13: 我听说.netscape 会支援 java*。这是不是说我现在得弃
perl,改
java 了?是不是该这麽做?

【译者】原 faq 已有相当一段时间未更新。这句话现在应该改作
.netscape 和 ie 两大浏览器都已支援 java」。

不、不、不。javacgi 的概念完全不同。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 &quot;content-type: text/plain&quot;, &quot;\n\n&quot;;

foreach &#36;key (sort keys %env) {
print &#36;key, &quot; = &quot;, &#36;env{&#36;key}, &quot;\n&quot;;
}
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(&#36;string = <stdin>);
&#36;string =~ s/([^\w\s])/sprintf(&quot;&#%d;&quot;, ord(&#36;1))/ge;
print '跳脱过的字串是: ', &quot;&#36;string\n&quot;;
exit 0;

----------------------------------------------------------------------

q4.16: 为什麽我的perl cgi
程式可以由指令列,却无法从浏览器去执行?

最可能的原因是权限的问题。别忘了,您的 server 可能是以
``nobody''、

``www'',或其他权限很低的帐户身份来执行的。因此,除非它有足够的权限,
否则是无法执行您的 script 的。

----------------------------------------------------------------------

q4.17: 为什麽我的 perl cgi 程式能跑,但是不会把资料写到档案中?

这又是权限在作怪!server
除非有足够的权限否则是无法将资料写进某目录下
的某档案里去的。

您应该养成习惯检查 open 指令递回的错误状态 (error status):

print &quot;content-type: text/plain\n\n&quot;;
.
.
.
open(file, &quot;>/some/dir/some.file&quot;)
print '无法写进档案: ', &quot;&#36;!\n&quot;;
.
.
.

----------------------------------------------------------------------

q4.18: 要如何做一个会维系状态,或允许【同一使用者】多次连线的
form?

您可以用 cgi::minisvr 这个 module
来维持【记住】几次不同的连线之间的状
态资料。

或者,您可以制做一系列的动态文件,在彼此之间相互传递一个期间代码
(session id),此代码可以以询问
(query)、额外路径,或隐藏式栏位等形式存
在*。

【译者】cgi.pm 会替您把这部份(维持状态)做好 (用上述的原理
),故使用 cgi.pm 可自动享受这项功能,不需要自己去做。这又多
了一个该使用 cgi.pm 的理由。

----------------------------------------------------------------------

q4.19: 如果不从浏览器去执行我的 cgi 程式,要如何替它除错?

cgi 程式不容易除错。您可以藉著手动设定环境变数来模拟 server:

setenv http_user_agent &quot;mozilla/2.0b6&quot; (csh)

export http_user_agent = &quot;mozilla/2.0b6&quot; (ksh, bash)

要模拟 post 请求,您可以把资料先放进一个档案里,然後把它 pipe
到您的程
式去:

cat data.file some_program.pl

或者您可以用 cgi.pm 来帮您除错。假设您有一个像下面这样的
script,它会
把所有您传给它的索引/设定值对应资料 (key/value pairs)
都列印出来。

#!/usr/local/bin/perl -w
use cgi;
&#36;cgi = new cgi;
print &#36;cgi->header;
print &#36;cgi->start_html(&quot;simple cgi.pm program&quot;);
print &quot;<h1>simple cgi.pm program</h1>\n&quot;;
print &quot;<hr >&quot;;
print '以下所列的是您传送的设定值:';
print &#36;cgi->dump;
exit 0;

这个 script 不会在乎您是透过 get、post,或 isindex
请求,或者是由指令

列、标准输入,或文字档将资料传送给它。为了方便除错,我们就直接从指令
列传一些资料给它吧:

% simple.cgi first=shishir last=gundavaram document='cgi\
faq'

% simple.cgi &quot;first=shishir&last=gundavaram&document='cgi\
faq'&quot;

在第二个例子中,整个字串周围必须加引号(&quot;),否则 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=&quot;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'' 了。

&#36;error = 0;
foreach &#36;value (values %form) {
&#36;value =~ s/\s//g;
&#36;error = 1 unless &#36;value;
}
if (&#36;error) {
print &quot;content-type: text/plain\n&quot;;
print &quot;status: 204 no content\n\n&quot;;
print '除非您的浏览器不支援状态码 204
,否则您不该看到这部份',
&quot;\n&quot;;
} 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 &quot;location: http://host/page.html\n 不
work?又为
什麽它只 work 一次,但随後的转向就都弄错了呢?

cgi 程式只能送一个 location 标头。还有,如果您要 server
做转向的动作
您就不该送 mime 类别。譬如,以下的例子是错误的示范,尽管在有些
servers
上行的通:

#!/usr/local/bin/perl -w
.
.
.
print &quot;content-type: text/plain\n&quot;
print &quot;location: http://some.machine/some.doc\n\n&quot;;

----------------------------------------------------------------------

q4.24: 要如何让 server 在每个 html
网页的底部都自动加上一个:「最近更
新日期: ...」的告示?或者,是不是只有 ssi 的网页才能这麽做?cgi
程式
的日期要如何取得?

如果您是透过 cgi
以动态方式来产生您的文件,那麽要插入一个时间标记非常
简单。以下是一例(仅适用於 perl 5):

&#36;last_updated = localtime;
print '最近更新日期: ',&quot;&#36;last_updated\n&quot;;

或者是:

require &quot;ctime.pl&quot;;
&#36;last_updated = &ctime(time);
print '最近更新日期: ', &quot;&#36;last_updated\n&quot;;

甚至像这样:

chop(&#36;date = `/usr/local/bin/date`);
print '最近更新日期: ', &quot;&#36;last_updated\n&quot;;

您可以用 ssi 来达到这个效果,像这样:

<--#echo var=&quot;last_modified&quot;-->

----------------------------------------------------------------------

q4.25: 什麽样的场合下以 perlcgi 程式会显得太小题大作,因为用
shell
就可以做到?而什麽样的场合对 perl 来说又过於困难?用 c++
做这类的事不
是好得多吗?那用 c 呢?

每一个语言都有其长处和短处。相信这句话您听过很多次了。所以一切全看您要
做的是什麽而定。如果您预期正准备写的 cgi
程式每个钟头会有几千几万人次
连去使用,那麽您应该选用 c 或
c++来写。如果您求快的话(指发展所花费的
时间而言),那麽 perl 是正确的选择!

一般说来,您应避免用 shell 来做任何形式的 cgi 程式设计,因为
shell 在先天上容易产生安全问题。

  


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons