Apache HTTP Server 版本 2.4
相關模組 | 相關指令 |
---|---|
CGI(共通閘介面)定義了網頁伺服器與外部產生內容的程式互動的方式,此類程式通常稱為 CGI 程式或 CGI 腳本。這是使用最熟悉的程式語言在網站上放置動態內容的簡便方式。本文將簡介如何在 Apache 網路伺服器上設定 CGI,以及撰寫 CGI 程式的入門知識。
為正常運行 CGI 程式,您需要設定 Apache 以允許執行 CGI。有數種做法。
httpd.conf
中,您需要確認 LoadModule
指令未被註解。設定正確的指令可能類似這樣LoadModule cgid_module modules/mod_cgid.so在 Windows 或使用非執行緒 MPM(如 prefork)的情況下,設定正確的指令可能類似這樣
LoadModule cgi_module modules/mod_cgi.so
指令 ScriptAlias
告知 Apache 將特定目錄預留給 CGI 程式。Apache 會假設此目錄中的每個檔案都為 CGI 程式,並在客戶端請求該資源時嘗試執行。
指令 ScriptAlias
看起來像這樣
ScriptAlias "/cgi-bin/" "/usr/local/apache2/cgi-bin/"
如您將 Apache 安裝在預設位置,顯示的範例出自我電腦預設的 httpd.conf
組態檔案。ScriptAlias
指令與用於定義應對應到特定目錄的 URL 字首的 Alias
指令非常類似。Alias
和 ScriptAlias
通常會用於位於 DocumentRoot
目錄外部的目錄。Alias
和 ScriptAlias
之間的差異在於,ScriptAlias
有額外的意義,即在該 URL 字首底下的一切都會被視為 CGI 程式。因此,上述範例會告訴 Apache,任何以 /cgi-bin/
開頭的資源請求都應使用 /usr/local/apache2/cgi-bin/
目錄提供服務,並應做為 CGI 程式處理。
例如,如果要求的 URL 為 http://www.example.com/cgi-bin/test.pl
,Apache 會嘗試執行檔案 /usr/local/apache2/cgi-bin/test.pl
並傳回輸出。當然,檔案必須存在且可執行,並且以特定方式傳回輸出,否則 Apache 會傳回錯誤訊息。
考量安全性因素,CGI 程式通常會受限於 ScriptAlias
'ed 目錄。藉此,管理員可以嚴格控管哪些人可以使用 CGI 程式。然而,如果採取適當的安全性防護措施,就沒有理由不能從任意目錄執行 CGI 程式。例如,您可能希望讓使用者在其內部目錄中擁有 Web 內容,且方法是使用 UserDir
指令。如果他們想擁有自己的 CGI 程式,但無法存取主 cgi-bin
目錄,就需要能夠在其他地方執行 CGI 程式。
要允許在任意目錄中執行 CGI,共有兩個步驟。首先,必須使用 AddHandler
或 SetHandler
指令啟用 cgi-script
處理常式。其次,必須在 Options
指令中指定 ExecCGI
。
您可以在主伺服器組態檔案內部明確使用 Options
指令,以指定允許在特定目錄中執行 CGI。
<Directory "/usr/local/apache2/htdocs/somedir"> Options +ExecCGI </Directory>
上述指令會告訴 Apache 允許執行 CGI 檔案。您還需要告訴伺服器哪些檔案是 CGI 檔案。以下 AddHandler
指令會告訴伺服器將所有副檔名為 cgi
或 pl
的檔案都視為 CGI 程式。
AddHandler cgi-script .cgi .pl
如果您無法存取 `httpd.conf`,.htaccess
教學課程示範如何啟動 CGI 程式。
若要允許執行使用者目錄中任何以 `cgi` 結尾的檔案的 CGI 程式,您可以使用以下設定。
<Directory "/home/*/public_html"> Options +ExecCGI AddHandler cgi-script .cgi </Directory>
如果您想指定使用者的目錄中的 `cgi-bin` 子目錄,並將其中所有內容當作 CGI 程式處理,可以使用以下設定。
<Directory "/home/*/public_html/cgi-bin"> Options ExecCGI SetHandler cgi-script </Directory>
``一般的'' 編寫程式和 CGI 編寫程式有兩個主要的相異處。
第一,您的 CGI 程式的所有輸出都必須先加上 MIME 類型 標頭。這是 HTTP 標頭,用來告訴客戶端所接收的是何種內容。大多數時候,會看起來像這樣
內容類型:文字/html
第二,您的輸出需要是 HTML 或瀏覽器可以顯示的其他格式。大多數時候,會是 HTML,但有時您可能會撰寫一個 CGI 程式來輸出 gif 影像,或其他非 HTML 內容。
除了這兩點以外,撰寫 CGI 程式的寫法會和其他您可能撰寫的程式非常類似。
下列是一個示範的 CGI 程式,它會在您的瀏覽器列印一行。輸入下列內容,儲存成一個稱為 `first.pl` 的檔案,並放在您的 `cgi-bin` 目錄中。
#!/usr/bin/perl print "Content-type: text/html\n\n"; print "Hello, World.";
即使您不熟悉 Perl,也應該看得出這裡發生了什麼事。第一行告訴 Apache(或您正在執行的 shell)這個程式可以用位於路徑 `usr/bin/perl` 的直譯器讀取檔案來執行。第二行列印我們談論過的內容類型宣告,接著是兩個換行符號。這會在標頭之後放置一空白行,以標示 HTTP 標頭的結束,以及本文的開始。第三行列印字串「Hello, World.」。就是這樣了。
如果您開啟您最愛的瀏覽器,然後告訴它讀取位址
http://www.example.com/cgi-bin/first.pl
或您放置檔案的任何位置,您會在瀏覽器視窗中看到單行文字 `Hello, World.`。這並不令人興奮,但一旦您讓它運作,您就能夠得到任何您想要運作的東西。
在您試圖從網路存取您的 CGI 程式時,您的瀏覽器中可能會出現四項基本項目。
請記住,伺服器並非以您的身分執行。也就是說,當伺服器啟動時,它會使用不具特權的使用者權限(通常是 nobody
或 www
)執行,因此會需要額外權限才能執行您擁有權限的檔案。通常,讓 nobody
擁有足夠權限來執行的檔案方式,就是對此檔案給予所有人都可執行的權限
chmod a+x first.pl
此外,如果您的程式會從其他檔案中讀取或寫入其他檔案,則這些檔案需要擁有正確的權限才能執行這項動作。
當您從指令列執行程式時,系統會傳遞特定資訊給 shell,而您無需手動執行。例如,您有一個 PATH
,用來告知 shell 在何處找尋您參考的檔案。
當程式透過網路伺服器執行,作為 CGI 程式時,可能不會有相同的 PATH
。您的 CGI 程式中會呼叫到的任何程式(例如 sendmail
),都必須透過完整路徑指定,如此一來,shell 才能在嘗試執行您的 CGI 程式時找到它們。
此狀況的常見表現是,CGI 程式第一行中顯示的指令碼翻譯器路徑(通常是 perl
),看起來類似
#!/usr/bin/perl
請確認這的確是翻譯器路徑。
如果您的 CGI 程式依賴非標準的環境變數,您需要確保 Apache 傳遞這些變數。
如果環境中缺少 HTTP 標頭,請務必遵照RFC 2616第 4.2 節的格式建立它們:標頭名稱必須以字母開頭,後續僅能接字母、數字或連字元。違反此規則的任何標頭都將靜默地刪除。
大多數時候,當 CGI 程式失敗時,都是程式本身的問題。一旦你掌握這個 CGI 程式,且不再犯上文中提到的兩個錯誤時,這情況尤其明顯。首先要做的是確認在經由網路伺服器測試你的程式時,這個程式會在指令列執行。舉例來說,請嘗試
cd /usr/local/apache2/cgi-bin
./first.pl
(不要呼叫 Perl 這個直譯程式,shell 和 Apache 應該會在指令稿的第一列使用 路徑資訊 來找到這個直譯程式。)
你的程式寫的第一件事應當是一組 HTTP 標頭,其中包括 Content-Type
,接著是一行空白列。如果你看到其他任何內容,如果你試圖透過伺服器執行它,Apache 會傳回 Script 標頭過早結束
錯誤。有關更多詳細資料,請參閱上述 寫入 CGI 程式。
錯誤記錄是你的好夥伴。任何錯誤都會在錯誤記錄中產生訊息。你應該常常首先查看錯誤記錄。如果你架設網站的地方不允許你存取錯誤記錄,你或許應該將你的網站架設到別的地方。學習閱讀錯誤記錄,你會發現你幾乎所有的問題都能快速地識別出來,並快速地解決掉。
支援程式 suexec 允許在不同的使用者權限下執行 CGI 程式,這取決於它們位於哪一個虛擬主機或使用者家目錄中。Suexec 執行非常嚴謹的權限檢查,而且任何檢查失敗都會導致你的 CGI 程式錯誤,並顯示 Script 標頭過早結束
。
如要查看你是否使用 suexec,請執行 apachectl -V
,並檢查 SUEXEC_BIN
的位置。如果 Apache 在開機時找到 suexec
二進位檔,suexec 便會啟用。
除非你完全了解 suexec,否則你不應該使用它。如要停用 suexec,請移除 (或重新命名) SUEXEC_BIN
指向的 suexec
二進位檔,然後重新啟動伺服器。如果你在閱讀完有關 suexec 的內容後,仍然想要使用它,請執行 suexec -V
,以找出 suexec 記錄檔的位置,並使用該記錄檔找出你違反哪些政策。
當你成為更進階的 CGI 程式員時,瞭解幕後發生的事,將會對你有所幫助。特別是瀏覽器和伺服器如何彼此溝通。因為雖然撰寫一個印出「Hello, World」的程式是很棒,但它並未特別的有用處。
當你使用電腦時,環境變數會作為值在你身邊飄動。它們有用的情況包括你的路徑(當你輸入時電腦會在其中尋找實作指令的實際檔案)、你的使用者名稱、你的終端機類型等等。若要查看你日常所有環境變數的完整清單,請在命令提示字元輸入 env
。
在 CGI 交易過程中,伺服器和瀏覽器也會設定環境變數,以利彼此通訊。舉例來說,它會包括瀏覽器類型(Netscape、IE、Lynx)、伺服器類型(Apache、IIS、WebSite)、正在執行的 CGI 程式的名稱等等。
這些變數可供 CGI 程式設計師使用,並形成 client-server 通訊的一半。必要變數的完整清單位於 Common Gateway Interface RFC。
這個簡單的 Perl CGI 程式將顯示正在傳遞的所有環境變數。cgi-bin
目錄中包含兩個類似的程式。請注意,有些變數是必要的,而有些則是選用的,因此你可能會看到一些不在官方清單中的變數。此外,Apache 提供多種不同的方式供你為預設提供的基本變數 新增自己的環境變數。
#!/usr/bin/perl use strict; use warnings; print "Content-type: text/html\n\n"; foreach my $key (keys %ENV) { print "$key --> $ENV{$key}<br>"; }
伺服器和 client 之間的其他通訊會透過標準輸入 (STDIN
) 和標準輸出 (STDOUT
) 進行。在一般日常情境下,STDIN
指的是鍵盤,或程式用來處置的檔案,而 STDOUT
通常指的是主控台或螢幕。
當你將網頁表單 POST
到 CGI 程式時,表單中的資料會以特殊格式打包,並透過 STDIN
傳送到你的 CGI 程式。然後,程式便能處理資料,就好像資料來自鍵盤或檔案一樣」
這種「特殊格式」很簡單。欄位名稱和其值會以等號 (=) 符號連接,而值對會以與號 (&) 連接。空格、與號和等號等不便的字元會轉換成其十六進位等值,以防阻礙作業。整個資料字串可能會如下所示
name=Rich%20Bowen&city=Lexington&state=KY&sidekick=Squirrel%20Monkey
有時你還會看到這種類型的字串附加到 URL。當這麼做時,伺服器會將該字串放入稱為 QUERY_STRING
的環境變數。這稱為 GET
要求。你的 HTML 表單會透過設定 FORM
標籤中的 METHOD
屬性來指定是用 GET
還是 POST
傳送資料。
然後,你的程式負責將該字串分割成有用的資訊。很幸運地,市面上有許多函式庫和模組可以協助你處理這些資料,並處理 CGI 程式的其他層面。
編寫 CGI 程式時,您應該考慮使用程式碼函式庫或模組,以協助您完成大多數繁瑣工作。這能減少錯誤,並加快開發速度。
如果您使用 Perl 撰寫 CGI 程式,則可在 CPAN 取得模組。最受歡迎的此類模組為 CGI.pm
。您也可以考慮 CGI::Lite
,它實作一組最基本的功能,這已足以應付大部分程式。
如果您使用 C 編寫 CGI 程式,有多種選擇。其中之一是來自 https://web.mit.edu/wwwdev/www/cgic.html 的 CGIC
函式庫。
您可以於 Common Gateway Interface RFC 取得目前的 CGI 規範。
當您在寄件清單或新聞群組張貼關於 CGI 問題的疑問時,請務必提供有關發生狀況、預期發生狀況、實際發生狀況有何不同、您執行的伺服器、CGI 程式使用的語言以及(如果可能)造成問題的程式碼等充足資訊。這將使找出您的問題容易得多。
請注意,除非您確定已在 Apache 原始碼中找到問題,否則絕不要將有關 CGI 問題的疑問張貼至 Apache 錯誤資料庫。