調試PerlCGI程序
PerlMonth/Jeff Boes
——(譯者注:本文譯自PerlMonth—www.perlmonth.com,作者很幽默,但是有些語言我也翻譯不出精髓,如果你讀得不通或者覺得翻譯的與你所理解的有所不同,可以查看原文——http://www.perlmonth.com/columns/begin/begin.html?issue=11&print=1)
這個月我們來一起學習如何調試PerlCGI腳本。這里所有的技巧和方法都是簡單明了的;大多數方法你可能在你編程的第一課里就已經學到了,我說的是你要經過正式的Perl編程培訓。然而,這也可能正是你面臨的問題:如果你是一位自學的Perl程序員的話,你可能并沒有接受過正規的調試CGI程序方面的教育。
那么我們先從這里開始吧。
假如你剛寫了一個龐大的Perl程序,一個1000的CGI的經典腳本,來得到訂單,處理信用卡,統計存貨并且計算衛星的軌道J。你把它上傳到服務器上,打開你的瀏覽器調閱程序。你發現出現了下面的東東:
500 Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator, webmaster@foo.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.
More information about this error may be available in the server error log.
唔,這是什么玩意兒?
這有一個對CGI程序員來說非常好的資料—— The Idiot’s Guide to Solving Perl CGI Problems(解決Perl CGI問題的傻瓜指南 ftp://ftp.epix.net/pub/languages/perl/doc/FAQs/cgi/idiots-guide.html)不要因為題目而感到不快,其實我們都是傻瓜——在某些時候。先讓我們試試他們的建議,看看是什么出錯了。
第一步:檢查腳本是否是可執行的。
·確定你上傳到了一個合適的目錄。很多的服務器限定CGI程序只能在你的home或public_html目錄下的特定子目錄下執行——像是cgi-bin或是cgi-local。有時要放在統一的CGI目錄下,例如:/usr/local/apache/cgi-bin
·檢查腳本的文件擴展名是否與服務器設置的相符。一些服務器需要Perl CGI腳本以.cgi為擴展名;一些要以.pl為擴展名;其它的服務器沒有這樣的要求。
·如果是放在Unix主機上,要檢查腳本是“可執行”的。腳本的文件權限必須設置為允許執行。在telnet登錄時你可以這樣完成:
$ chmod 0755 myscript.cgi
或者可以使用FTP軟件來改變你上傳的腳本的可執行權限。
·檢查服務器上已經安裝了運行腳本所需的所有東西。
最后還有另外一些的工作。當我使用一些新的服務器的時候我首先要上傳兩個測試文件(作為一個自由作家,我每周都會遇到一兩個新服務器,有時候我甚至是在那個服務器上嘗試運行Perl CGI的第一個人)。一般最簡單的測試文件是這樣寫的:
#! /usr/bin/perl –w
use diagnostics;
print ‘Content-type: text/html
Hello,world.’;
這個腳本會讓你知道Perl CGI已經運行,服務器也設置好了可以正確處理Perl CGI。
如果你想要進一步的測試,那么我還是建議你試試perldiver(http://www.scriptsolutions.com/programs/free/perldiver/)。這是一個非常有用的腳本,你把它上載到服務器上運行,會得到一個詳細又容易理解的服務器報告——Perl解釋器的位置,安裝了什么模塊等大量信息。(你應該在檢查你的服務器之后立即把這個腳本刪除,它提供的很多信息會給不道德的使用者進行攻擊提供可乘之機。)
那么,通過這些步驟你還沒有找到錯誤所在?下一步就是要檢查你的腳本是否被干凈的編譯了。你應該完成重要的一步——在你所有的腳本以這樣的方式開始;
#!/usr/bin/perl –w
user diagnostics;
第一行是給操作系統的一個標準信號:通知Perl解釋器要把該文件的其余部分作為源碼解釋。但是附加的“-w”開關,打開編譯時和運行時的警告。第二行會打開“pragma”(一個編譯選項),所有的錯誤信息和警告信息都會詳細地顯示,包括令人痛苦的所有大量的細節解釋。這些細節信息有時也可以通過命令行的調試來得到——那時你的輸出多得讓屏幕不斷地上滾,你會被上百行的錯誤診斷信息煩惱的痛苦不堪。但是在CGI的世界里我們就提供這些東西,不管你愛不愛看。
你也可能想把第三行加入到你的代碼中:
use strict;
我對把這條推薦給所有人表示猶豫,因為我并不為這條標準所左右。(我想說的是你應該去嘗試,直到你知道了一種觀點的想要做的是什么,然后再按你自己的想法來決定。)通常來說,“use strict”編譯選項使Perl更像其他的需要預先聲明變量的語言。(當然這個選項不只做這些用途)
現在你把這幾行加入到你的腳本中,并按命令行方式運行你的代碼:
$ perl –c myscript.cgi
也許現在你可以看到一些語法錯誤或是其他的問題。(我在這里經常遇到的是缺少一個可選的包,如:Mail::Mailer)。你可以得到更多的出錯信息,這比在瀏覽器中蹦出的可怕的500錯誤提示要好多了。
但是如果你沒有權限,或根本不能在命令行方式下運行Perl解釋器該怎么辦呢?(這種可能性微乎其微,Perl在大多數操作系統中是可用的,盡管版本之間的差別可能會是很微小的也可能是很巨大的。但是也許你是在Windows系統中進行開發工作,卻又不想把Perl安裝到微軟的系統上,或者你想在一臺借來的計算機上快速調試一段腳本,你又不想為了幾分鐘的工作就安裝一大堆Perl系統)。
其實我們只需要一個FTP客戶端和一個瀏覽器就能完成所有的調試工作。首先我們要對你的腳本作一些改變:
use CGI qw(:standard);
user CGI::Carp qw(fatalsToBrowser);
BEGIN{
Print CGI::header();
Open (STDERR, ‘>myscript.log’);
}
上面的這幾行,或者是其他的與其相似的東東,被放在我寫的所有的CGI腳本中。第一行里引用的是標準CGI.pm包。的確,這是一個大包,大的有點像在港口外航行的航空母艦。但是它節省了你很多的時間,所以即使大一點也是值得的。除非你的Web服務器是運行在486機器上的,否則不要太在意載入這個包所多花的幾微秒時間。如果你的腳本所在的網站的點擊率像Yahoo!那樣的大網站一樣多,你也仍然可以使用CGI.pm包或其它的模塊,但是你也必須學習如何使用mod_perl(這已經超出了本文所討論的范圍。不過,使用CGI.pm對你來說是一個非常好的選擇,相信我,因為我是一個專家)
第二行引用的是另一個包叫做“CGI::Carp”,這是一個錯誤處理包它代替并擴展了我們經常看到的出錯信息。之所以要把它從CGI一族中提取出來是因為我們想更精細的格式出錯信息,而且還想通過內部程序fatalsToBrowser提供一個錯誤捕獲機制。當發生嚴重錯誤的時候這個fatalsToBrowser子程序會獲得腳本的控制權,并在瀏覽器上顯示這個錯誤的具體內容(代替了500錯誤)。
第三行定義了一個BEGIN塊。根據Perl的語法,你可以在程序中的任何部位插入代碼塊(包含文件或是模塊)。當程序被解析的時候,這些塊只被執行一次(所以它們是“編譯階段代碼”)。向我所演示的一樣,這些代碼會通過STDERR把進一步的輸出重定向到一個log文件中去。這在CGI環境中是比較方便的,因為大多數的錯誤不是被抑制了,就是被寫到一個集中的站點錯誤日志中,這個日志會非常大并且可能不易被你閱讀。
這里還有一樣東西被特意放到了BEGIN塊中來挽救你的不幸。那就是“print CGI::header”語句。在輸出任何錯誤之前,強制返回給瀏覽器一個合適的HTTP頭,通常的header的形式是這樣的:
Content-type: text/html
(包括那個空行)。如果你的腳本已經有了一個頭,那么你會在你的文檔開始處看到多出了一個以文本顯示的“header”。不用管它,當你結束調試的時候,你可以從BEGIN塊中刪除掉print語句,繼續使用你原來的頭。
當然,如果你的腳本使用了Content-type以外的header(比如說:cookie或是重定向),那么你的header會被BEGIN塊中的header忽略。當我們證明所有的bug都被清除之后,就可以移除BEGIN塊中的header。
現在,腳本中添加了這些行之后,你就可以很好地捕獲并處理錯誤,并防止“500”之類的錯誤提示了。
(譯自 PerlMonth / Jeff Boes)
——(譯者注:本文譯自PerlMonth—www.perlmonth.com,作者很幽默,但是有些語言我也翻譯不出精髓,如果你讀得不通或者覺得翻譯的與你所理解的有所不同,可以查看原文——http://www.perlmonth.com/columns/begin/begin.html?issue=11&print=1)
這個月我們來一起學習如何調試PerlCGI腳本。這里所有的技巧和方法都是簡單明了的;大多數方法你可能在你編程的第一課里就已經學到了,我說的是你要經過正式的Perl編程培訓。然而,這也可能正是你面臨的問題:如果你是一位自學的Perl程序員的話,你可能并沒有接受過正規的調試CGI程序方面的教育。
那么我們先從這里開始吧。
假如你剛寫了一個龐大的Perl程序,一個1000的CGI的經典腳本,來得到訂單,處理信用卡,統計存貨并且計算衛星的軌道J。你把它上傳到服務器上,打開你的瀏覽器調閱程序。你發現出現了下面的東東:
500 Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator, webmaster@foo.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.
More information about this error may be available in the server error log.
唔,這是什么玩意兒?
這有一個對CGI程序員來說非常好的資料—— The Idiot’s Guide to Solving Perl CGI Problems(解決Perl CGI問題的傻瓜指南 ftp://ftp.epix.net/pub/languages/perl/doc/FAQs/cgi/idiots-guide.html)不要因為題目而感到不快,其實我們都是傻瓜——在某些時候。先讓我們試試他們的建議,看看是什么出錯了。
第一步:檢查腳本是否是可執行的。
·確定你上傳到了一個合適的目錄。很多的服務器限定CGI程序只能在你的home或public_html目錄下的特定子目錄下執行——像是cgi-bin或是cgi-local。有時要放在統一的CGI目錄下,例如:/usr/local/apache/cgi-bin
·檢查腳本的文件擴展名是否與服務器設置的相符。一些服務器需要Perl CGI腳本以.cgi為擴展名;一些要以.pl為擴展名;其它的服務器沒有這樣的要求。
·如果是放在Unix主機上,要檢查腳本是“可執行”的。腳本的文件權限必須設置為允許執行。在telnet登錄時你可以這樣完成:
$ chmod 0755 myscript.cgi
或者可以使用FTP軟件來改變你上傳的腳本的可執行權限。
·檢查服務器上已經安裝了運行腳本所需的所有東西。
最后還有另外一些的工作。當我使用一些新的服務器的時候我首先要上傳兩個測試文件(作為一個自由作家,我每周都會遇到一兩個新服務器,有時候我甚至是在那個服務器上嘗試運行Perl CGI的第一個人)。一般最簡單的測試文件是這樣寫的:
#! /usr/bin/perl –w
use diagnostics;
print ‘Content-type: text/html
Hello,world.’;
這個腳本會讓你知道Perl CGI已經運行,服務器也設置好了可以正確處理Perl CGI。
如果你想要進一步的測試,那么我還是建議你試試perldiver(http://www.scriptsolutions.com/programs/free/perldiver/)。這是一個非常有用的腳本,你把它上載到服務器上運行,會得到一個詳細又容易理解的服務器報告——Perl解釋器的位置,安裝了什么模塊等大量信息。(你應該在檢查你的服務器之后立即把這個腳本刪除,它提供的很多信息會給不道德的使用者進行攻擊提供可乘之機。)
那么,通過這些步驟你還沒有找到錯誤所在?下一步就是要檢查你的腳本是否被干凈的編譯了。你應該完成重要的一步——在你所有的腳本以這樣的方式開始;
#!/usr/bin/perl –w
user diagnostics;
第一行是給操作系統的一個標準信號:通知Perl解釋器要把該文件的其余部分作為源碼解釋。但是附加的“-w”開關,打開編譯時和運行時的警告。第二行會打開“pragma”(一個編譯選項),所有的錯誤信息和警告信息都會詳細地顯示,包括令人痛苦的所有大量的細節解釋。這些細節信息有時也可以通過命令行的調試來得到——那時你的輸出多得讓屏幕不斷地上滾,你會被上百行的錯誤診斷信息煩惱的痛苦不堪。但是在CGI的世界里我們就提供這些東西,不管你愛不愛看。
你也可能想把第三行加入到你的代碼中:
use strict;
我對把這條推薦給所有人表示猶豫,因為我并不為這條標準所左右。(我想說的是你應該去嘗試,直到你知道了一種觀點的想要做的是什么,然后再按你自己的想法來決定。)通常來說,“use strict”編譯選項使Perl更像其他的需要預先聲明變量的語言。(當然這個選項不只做這些用途)
現在你把這幾行加入到你的腳本中,并按命令行方式運行你的代碼:
$ perl –c myscript.cgi
也許現在你可以看到一些語法錯誤或是其他的問題。(我在這里經常遇到的是缺少一個可選的包,如:Mail::Mailer)。你可以得到更多的出錯信息,這比在瀏覽器中蹦出的可怕的500錯誤提示要好多了。
但是如果你沒有權限,或根本不能在命令行方式下運行Perl解釋器該怎么辦呢?(這種可能性微乎其微,Perl在大多數操作系統中是可用的,盡管版本之間的差別可能會是很微小的也可能是很巨大的。但是也許你是在Windows系統中進行開發工作,卻又不想把Perl安裝到微軟的系統上,或者你想在一臺借來的計算機上快速調試一段腳本,你又不想為了幾分鐘的工作就安裝一大堆Perl系統)。
其實我們只需要一個FTP客戶端和一個瀏覽器就能完成所有的調試工作。首先我們要對你的腳本作一些改變:
use CGI qw(:standard);
user CGI::Carp qw(fatalsToBrowser);
BEGIN{
Print CGI::header();
Open (STDERR, ‘>myscript.log’);
}
上面的這幾行,或者是其他的與其相似的東東,被放在我寫的所有的CGI腳本中。第一行里引用的是標準CGI.pm包。的確,這是一個大包,大的有點像在港口外航行的航空母艦。但是它節省了你很多的時間,所以即使大一點也是值得的。除非你的Web服務器是運行在486機器上的,否則不要太在意載入這個包所多花的幾微秒時間。如果你的腳本所在的網站的點擊率像Yahoo!那樣的大網站一樣多,你也仍然可以使用CGI.pm包或其它的模塊,但是你也必須學習如何使用mod_perl(這已經超出了本文所討論的范圍。不過,使用CGI.pm對你來說是一個非常好的選擇,相信我,因為我是一個專家)
第二行引用的是另一個包叫做“CGI::Carp”,這是一個錯誤處理包它代替并擴展了我們經常看到的出錯信息。之所以要把它從CGI一族中提取出來是因為我們想更精細的格式出錯信息,而且還想通過內部程序fatalsToBrowser提供一個錯誤捕獲機制。當發生嚴重錯誤的時候這個fatalsToBrowser子程序會獲得腳本的控制權,并在瀏覽器上顯示這個錯誤的具體內容(代替了500錯誤)。
第三行定義了一個BEGIN塊。根據Perl的語法,你可以在程序中的任何部位插入代碼塊(包含文件或是模塊)。當程序被解析的時候,這些塊只被執行一次(所以它們是“編譯階段代碼”)。向我所演示的一樣,這些代碼會通過STDERR把進一步的輸出重定向到一個log文件中去。這在CGI環境中是比較方便的,因為大多數的錯誤不是被抑制了,就是被寫到一個集中的站點錯誤日志中,這個日志會非常大并且可能不易被你閱讀。
這里還有一樣東西被特意放到了BEGIN塊中來挽救你的不幸。那就是“print CGI::header”語句。在輸出任何錯誤之前,強制返回給瀏覽器一個合適的HTTP頭,通常的header的形式是這樣的:
Content-type: text/html
(包括那個空行)。如果你的腳本已經有了一個頭,那么你會在你的文檔開始處看到多出了一個以文本顯示的“header”。不用管它,當你結束調試的時候,你可以從BEGIN塊中刪除掉print語句,繼續使用你原來的頭。
當然,如果你的腳本使用了Content-type以外的header(比如說:cookie或是重定向),那么你的header會被BEGIN塊中的header忽略。當我們證明所有的bug都被清除之后,就可以移除BEGIN塊中的header。
現在,腳本中添加了這些行之后,你就可以很好地捕獲并處理錯誤,并防止“500”之類的錯誤提示了。
(譯自 PerlMonth / Jeff Boes)