科技讯息网 – 程序员的那点事!

首页 > 编程资料 > Perl语言 > 正文

perl常问问题集--第七篇

浏览次数:次 2004年12月28日 作者:keigopan 字号:

我的?CGI?script可在指令列下执行但无法从浏览器执行。您能不能帮我修修看??
当然,但您恐怕付不起雇我们的签约金?:-)?

说真的,如果您能够先证明您已读过下列这几个?FAQs?,但遇到的问题并不单纯、非叁言两语即可回答的话,那麽您?post到?comp.infosystems.www.authoring.cgi上(如果是有关?HTTP?、?HTML?,或?CGI通信协定)的问题可能也会得到口气和缓而有用的答覆。表面上看似?Perl,但骨子里是?CGI之类的问题,如果?post到?comp.lang.perl.misc人家可能就不会这麽乐意地接受了。?

几个实用的?FAQs?分别是:?

http://www.perl.com/perl/faq/idiots-guide.html?
http://www3.pair.com/webthing/docs/cgi/faqs/cgifaq.shtml?
http://www.perl.com/perl/faq/perl-cgi-faq.html?
http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html?
http://www.boutell.com/faq/?

【译者】上面第叁份文件,Perl-CGI-FAQ的中译版可在?http://2Ti.com/cgi-bin/2T/perl/perl-cgi-faq-chi/?处取得。最後一份(WWW?FAQ)的中译版可自?http://www.acer.net/document/cwwwfaq/?取得。?


--------------------------------------------------------------------------------?

如何去除文章中的?HTML标签??
最正确(尽管不是最快)的方法是使用?HTML::Parse模组(可由?CPAN取得,是所有写?Web程式者必备的?libwww-perl?套件的一部分)。?

许多人尝试用简陋的正规表示式来解决这个问题,譬如说像?s///g,但这个式子在很多情况下会失败,因为要处理的字串可能会跨越断行字元,也可能含有被?quote【跳脱】的箭头号,或有?HTML?comment出现;再加上一些疏忽,譬如,人们常忘了转换如?'"]*|(['"]).*?\1)*>;//gs?

如果您想要更完整的解法,请看叁部曲的?striphtml?程式,?http://www.perl.com/CPAN/authors/Tom_Christiansen/scripts/striphtml.gz?。?


--------------------------------------------------------------------------------?

如何萃取?URLs??
一个快速但不完美的做法是?

#!/usr/bin/perl?-n00?
#?qxurl?-?tchrist@perl.com?
print?"$2\n"?while?m{?

}gsix;?

这个版本并不替相对式写法的?URLs?作调整,也不懂代换?bases【】,或如何处理?HTML?comments、同时处理同一个标签里的?HREF和?NAME?属性,或接受?URL形式的参数。同时,它要比一个较「完整」、利用?LWP?[libwww-perl]模组套件的解法,例如?http://www.perl.com/CPAN/authors/Tom_Christiansen/scripts/xurl.gz这个程?式,快上一百倍。?


--------------------------------------------------------------------------------?

如何从?user端上传资料?如何在另一台机器上开一个档案??
如果是?HTML表格的话,您可以使用?multipart/form-data的编码格式。?CGI.pm(可自?CPAN取得)中的?start_multipart_form()这个?method?就是为此设计的,它和?startform()这个?method?是两回事。?


--------------------------------------------------------------------------------?

如何在?HTML中做?pop-up?menu(跳出式选单)??
用?和?这两个标签。?CGI.pm模组(可由?CPAN取得)对这个?widget【此指跳出式选单这个介面成分】还有许多其他的介面成分都有支援【即有制作动态标签的函式】,其中有些是以巧妙模拟的方?式达成。?


--------------------------------------------------------------------------------?

如何抓?HTML档案??
有一个方法是,如果您的系统上装有?lynx一类的文字模式的?HTML浏览器的话,那麽可以这麽做:?

$html_code?=?`lynx?-source?$url`;?
$text_data?=?`lynx?-dump?$url`;?

收录在?CPAN里的?libwww-perl?(LWP)模组则提供了更强的方法来做这件事。它不但可钻过?proxies,而且也不需要?lynx:?

#?print?HTML?from?a?URL?
use?LWP::Simple;?
getprint?"http://www.sn.no/libwww-perl/";;?

#?print?ASCII?from?HTML?from?a?URL?
use?LWP::Simple;?
use?HTML::Parse;?
use?HTML::FormatText;?
my?($html,?$ascii);?
$html?=?get("http://www.perl.com/";);?
defined?$html?
or?die?"Can't?fetch?HTML?from?http://www.perl.com/";;?
$ascii?=?HTML::FormatText->;new->;format(parse_html($html));?
print?$ascii;?


--------------------------------------------------------------------------------?

如何解开或产生?Web上那些冠?%的码??
以下是一个解码的实例:?

$string?=?"http://altavista.digital.com/cgi-bin/query?pg=q&;what=news&fmt=.&q=%2Bcgi-bin+%2Bperl.exe";?
$string?=~?s/%([a-fA-F0-9]{2})/chr(hex($1))/ge;?

编码比较困难一点,因为您不能盲目地把所有非字母数字的字元?(\W)都一律转换成十六进位的跳脱码。很重要的是有特殊意义的字元,如?/?和???便不可以?转换。要做得正确,最简单的方法大概是使用现成的?URI::Escape模组,而不要重新发明轮子。这个模组是?libwww-perl?套件?(LWP)的一部分,可自?CPAN取得。?


--------------------------------------------------------------------------------?

如何【将?requests】转向到另一页去??
在您的回应中不要使用?Content-Type这个标头,相反地,用?Location:?这个标头。按正式规定,应当?URL:?才是正确的标头。因此?CGI.pm模组(可?由CPAN取得)两个标头都送:?

Location:?http://www.domain.com/newpage?
URI:?http://www.domain.com/newpage?

要注意的是,由於?servers采用「最高效率化」的运作方式,故在这些标头中如?果使用相对式的?URLs可能会产生奇怪的後果。?


--------------------------------------------------------------------------------?

如何替网页加上密码??
不一定,要看情况。您需要读您?server的使用手册,或者查查看上头所列的几个?FAQs。?


--------------------------------------------------------------------------------?

要怎麽用?Perl来编辑?.htpasswd和?.htgroup这两个档案??
HTTPD::UserAdmin?和?HTTPD::GroupAdmin等模组为这些档案提供了统一的物件导向介面,尽管这些档案可能以各种不同的格式储存。这些资料库可能是纯文字格式、?dbm、Berkeley?DB或任何?DBI相容的资料库驱动程式?(drivers)。?HTTPD::UserAdmin支援`Basic'?和?`Digest'这两个认证模式所用的档案。以下是?一例:?

use?HTTPD::UserAdmin?();?
HTTPD::UserAdmin?
->;new(DB?=>;?"/foo/.htpasswd")?
->;add($username?=>;?$password);?


--------------------------------------------------------------------------------?

如何防范使用者藉由填我的?CGI表格来做坏事??
阅读?CGI?security?FAQ,(可在?http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html取得),还有?Perl?CGI?FAQ,在?http://www.perl.com/CPAN/doc/FAQs/cgi/perl-cgi-faq.html?。?

简单一句话:使用?tainting(沾腥?)这项功能(详见?perlsec?)。它会让所有不在您的?script中、来路不明的资料(譬如,?CGI参数)无法放到?eval?或?system等呼叫中使用。除了使用?tainting之外,绝对不要使用单一参数?的方式下参数给?system()或?exec(),而应将欲执行的指令及其参数放在一个序?列或阵列里面,再传给?system()或?exec(),这样便可避免?globbing【即被?shell先做解译】。?


--------------------------------------------------------------------------------?

如何解读、萃取?email标头资料??
如果您只需要一个「快而脏」的解法的话,您可以试试这个从再版的?``Programming?Perl''第?222页中拿出来的例子:?

$/?=?'';?
$header?=?;?
$header?=~?s/\n\s+/?/g;?#将延续行合并成单行?
%head?=?(?UNIX_FROM_LINE,?split?/^([-\w]+):\s*/m,?$header?);?

譬如说,您若想保留所有?Received栏位资料的话【因?Received栏位通常不止一个】,这个解法便不太行了。一个完整的解法是使用收录在?CPAN的?Mail::Header模组(?MailTools?套件的一部分)。?


--------------------------------------------------------------------------------?

如何解译?CGI表格??
很多人忍不住要自己写程式来处理这部分的工作,所以您们大概都看过一大堆其中有?$ENV{CONTENT_LENGTH}?和?$ENV{QUERY_STRING}的程式码。没错,这麽?写是可以行得通,但事实上也有很多在网路上出没的这类程式根本不能用!?

请不要忍不住去重新发明轮子【译者:这是英文的说法?(reinventing?the?wheels),也就是浪费时间做人家做过的事的意思】。请改用?CGI.pm或?CGI_Lite.pm(可自?CPAN取得)。如果您被困在无模组的?perl1?..?perl4的土地上,您可以试看看?cgi-lib.pl(可至?http://www.bio.cam.ac.uk/web/form.html取得)。?


--------------------------------------------------------------------------------?

如何验证?email位址??
无法度。?

如果没有寄封信到一个位址去试试看它会不会弹回来(即使是这麽做您还得面对停顿的问题),您是无法确定一个位址是否真的存在的。即使您套用?email?标头的标准规格来做检查的依据,您还是有可能会遇到问题,因为有些送得到的位址并不?符合?RFC-822(电子邮件标头的标准)的规定,但有些符合标准的位址却无法投?递。?

许多人试图用一个简单的正规表示式,例如?/^[\w.-]+\@([\w.-]\.)+\w+$/来消除一些通常是无效的?email位址。不过,这样做也把很多合格的位址给一起滤掉了,而且对测试一个位址有没有希望投递成功完全没有帮助,所以在此建议大家不要这麽做;不过您可以看看:?http://www.perl.com/CPAN/authors/Tom_Christiansen/scripts/ckaddr.gz。这个?script真的彻底地依据所有的?RFC规定来做检验(除了内嵌式?comments外),同时会排除一些您可能不会想送信去的位址(如?Bill?Clinton【美国柯林顿总统】或您的?postmaster),然後它会确定位址中的主机名称可在?DNS中找得到。这个?script?跑起来不是很快,但至少有效。?

不少?CGI?scripts的作者使用另一个替代的方案:用一个简单的正规表示式,(如上头的那个)。如果一个位址能让这个式子对得上的话,那麽就接受这个位址。如果这个位址对不上这个式子的话,便再向使用者讯问,以确定她们填入的这个位?址正确无误。?


--------------------------------------------------------------------------------?

如何解?MIME/BASE64字串??
MIME-tools套件(可自?CPAN取得)不但可处理这个问题而且有许多其他的功能。有了这个套件,解?BASE64码就变得像这麽容易:?

use?MIME::base64;?
$decoded?=?decode_base64($encoded);?

一个比较直接的解法是先做一点简单的转译,然後使用?unpack()这个函数的?``u''?格式:?

tr#A-Za-z0-9+/##cd;?#去除非?base64字元?
tr#A-Za-z0-9+/#?-_#;?#转换成?uu码格式?
$len?=?pack("c",?32?+?0.75*length);?#计算长度字元?
print?unpack("u",?$len?.?$_);?#?uu解码後?print?


--------------------------------------------------------------------------------?

如何根据使用者帐户名称自动合成?email位址??
在支援?getpwuid【UNIX系统呼叫】、?$add('From',?'gnat@frii.com');?
$header->;add('Subject',?'Testing');?
$header->;add('To',?'gnat@frii.com');?
#制作本文?
$body?=?'This?is?a?test,?ignore';?
#产生?mail物件?
$mail?=?new?Mail::Internet(undef,?Header?=>;?$header,?Body?=>;?\[$body]);?
#送出?
$mail->;smtpsend?or?die;?


--------------------------------------------------------------------------------?

如何找出我的主机名/网域名/IP位址??
长久以来许多?code都很草率地直接呼叫?`hostname`这个程式来取得主机名。?虽然这麽做很方便,但也同时增加了移植到其他平台上的困难。这是一个很典型的?例子,在方便和可移植性之间作抉择,不论选哪一边,必须付出一些牺牲和代价。?

Sys::Hostname这个模组(标准?perl发行的一部分)可用来取得机器的名字,然後您便可利用?gethostbyname()这个系统呼叫来找出该机的?IP位址了(假定您的?DNS?运作正常)。?

use?Socket;?
use?Sys::Hostname;?
my?$host?=?hostname();?
my?$addr?=?inet_ntoa(scalar(gethostbyname($name?||?'localhost')));?

至少在?Unix底下,取得?DNS网域名最简单的方法大概要算是直接从?/etc/resolv.conf这个档案里面找。当然,这麽做的前提是?resolv.conf这个档?案的设定必须照惯例的格式,还有就是这个档案必先存在才行。?

(Perl在非?Unix系统下尚需要一有效的方法来测出机器和网域名)?


--------------------------------------------------------------------------------?

如何抓新闻讨论群的文章或群组名录??
使用?Net::NNTP或?News::NNTPClient模组,两者皆可自?CPAN下载。这些模组?让抓群组名录这类的差事变得这麽容易:?

perl?-MNews::NNTPClient?
-e?'print?News::NNTPClient->;;new->;list("newsgroups")'?


--------------------------------------------------------------------------------?

如何抓/丢?FTP档案??
LWP::Simple模组(可自?CPAN下载)可以抓,但不能丢档案。?Net::FTP模组(也可自?CPAN下载)虽比较复杂,但可用来丢、也能抓档案。?


--------------------------------------------------------------------------------?

如何用?Perl做?RPC??
有一个?DCE::RPC模组正在发展阶段(但尚未完成)。一旦完成後它会随着?DCE-Perl这个套件发行(可由?CPAN?下载)。至於?ONC::RPC这样的模组则还没听说有人在发展。


在此感谢萧百龄及两只老虎工作室的翻译



?rimrock 回复于:2003-04-30 15:45:48

hao


?轩辕砍刀 回复于:2003-05-01 16:47:54

真的不错谢


?williamw2000 回复于:2003-09-30 07:12:54

very?good!


?reason001 回复于:2004-12-28 15:02:06

Wonderful!


?superdoctor 回复于:2004-12-28 15:07:09

楼主自己翻译的么?不错


?Qiang 回复于:2004-12-28 16:15:55

是?2ti?(两只老虎)?翻译的.??2ti.com?是台湾很早的?photoshop/css/?的教程网站,?还翻译了不少东东.?由一对夫妇来主持的.?好像还出来一些书籍.??reminds?me?my?early?internet?days.?

hmm,?跑题了我.....?:)

oh,?这里是另外一个?perl?的翻译文章站点.?还不错.?http://www.1313s.com/f/index.html