CGI 與 Form 自修教材

CGI 是 Common Gateway Interface 的意思, 它是一個從瀏覽器利用 URL 傳喚伺服機去啟動一個執行檔案, 並且將執行結果傳回瀏覽器的標準介面。

1. 關於網頁伺服機設定

CGI 涉及伺服機或整個網站的安全性。 所以,每一個網頁伺服機關於 CGI 的支援程度或設定規則,不盡相同。 此處以中央大學數學系的設定為例。

1.1 放哪裡

只要放在您的 WEBHOME 資料夾內就可以了。 但是 CGI 程式本身,和它所在的資料夾,其檔案模式都不可以是 world writable。

如果對於網頁伺服機的相關術語還有疑問,您應該回頭參考 HTML 自修第三課。 如果對於 UNIX 檔案模式還有疑問,應該回頭參考 UNIX 自修教材

1.2 什麼程式

任何可以在網頁伺服機的作業系統中執行的程式都行,但是檔案名必須是 *.cgi 的形式。 如果是腳本程式,則必須知道在伺服機上的解譯程式是否存在, 以及它所在的位置。 例如

目前的網頁伺服機作業系統是 Solaris 2.6。 所以如果要製作一個本身可執行的程式出來當做 CGI 程式, 則此程式之原始碼必須在 Solaris 2.6 作業系統中編譯才行。 例如,我們可以用 C 語言寫一個簡單的 CGI 程式: test_cgi.c, 在一台作業系統為 Solaris 2.6 的工作站 (例如姜夔、王維) 上編譯:

gcc -o test_c.cgi test_cgi.c
得到結果
http://www.math.ncu.edu.tw/mcl/bcc16/B/html/test_c.cgi

1.3 檔案模式

以網頁伺服機的身份執行
如果 CGI 程式不放在 WEBHOME 裡面,或者 URL 不是指向個人網頁以內,例如
http://www.math.ncu.edu.tw/mcl/bcc16/B/html/uid.cgi
則此程式的檔案模式必須是域內 (world) 可執行, 例如 755,則是以網頁伺服機的身份來執行,也就是 httpd。 因此,當它執行的時候,如果需要用到其他的電腦資源, 例如要從其他檔案讀、寫資料,則都是以 httpd 的身份去讀、寫。 在以上例子,應該得到 http
以一般用戶的身份執行
如果 CGI 程式放在 WEBHOME 裡面,而且 URL 指向個人網頁以內, 例如
http://www.math.ncu.edu.tw/~shann/bcc16/B/html/uid.cgi
而且程式檔案所屬的用戶與群組編號符合:UID >= 100 且 GID >= 80, 則此程式的檔案模式只要是用戶 (user) 可執行, 例如 700 或 500 或 744 或 755 都可以, 就會以用戶的身份來執行。例如上述的 uid.cgi 是一個 C-Shell 腳本, 它的檔案模式是 755,屬於 shann 用戶,所以就是以 shann 的身份來執行。 在以上例子,應該得到 shann

2. CGI 程式的輸出

只要輸出到 stdout 的資料,就會被轉送給網頁伺服軟體。 因此,輸出必須是純文字資料,而且第一列必須是

Content-type:text/html
第二列必須是一個空列。這兩列資料是送去給網頁伺服軟體作辨別用的。

從第三列開始,就是一個正常的 HTML 文件該有的文字。

3. CGI 程式的輸入

HTML 提供一些機制 (包括 FORM 和 ISINDEX),使得使用者可以從網頁上輸入資料。 而這些資料就會回傳到網頁伺服機。 如果伺服機發現這個 URL 是要透過 CGI 介面啟動一個執行檔案 (由 URL 裡面的資料夾名稱、或是檔案的副檔名來判斷), 就會透過 CGI 介面啟動可執行檔, 並將網頁傳回的資料以某種形式傳送給執行檔。

將資料回傳伺服機的方法,分成 GET 和 POST 兩種。 資料本身的類型,分成 ISINDEX 和 FORM 兩種。

最簡單的狀況,是以 GET 方法回傳 ISINDEX 資料。 就直接寫在 URL 裡面,以一個問號 ? 隔開網址和回傳資料。 整個 URL 必須符合 URL 的編碼標準,例如空格編成 +, 而 + 自己編成 %2B。

如果對於 URL 編碼規則還有疑問,應該回頭參考 HTML 自修教材第三課
例如

http://www.math.ncu.edu.tw/mcl/bcc16/B/html/get.cgi?Hello+world
CGI 介面將會執行 get.cgi,將 ? 以後的所有字串, 當做線上參數 (command line arguments) 提供給程式。也就是說,就好像在 UNIX 文字介面上執行
get.cgi Hello world
一樣。有一些會讓 UNIX 的文字介面產生特殊動作的字元, 例如 &,會被 CGI 改成 \&。 讀者可以嘗試自己將上述 URL 輸入在瀏覽器的網址方格內, 並且多做些實驗。而 get.cgi 將會回應它所收到的的參數是什麼。

HTML 的 ISINDEX 標籤照規定應該用在 HEAD 環境內。 但是許多人認為寫在 BODY 環境內比較方便,所以瀏覽器通常會接受 (至少 IE 和 Netscape 都會接受)。 ISINDEX 會在瀏覽器中產生一個輸入格, 讓人打字輸入資料,按 Enter 之後,輸入的資料會以 GET 方式回傳到同一張網頁 (通常是一個 CGI 程式)。

如果伺服機看到 URL 包含 CGI 程式和回傳資料, 而且回傳資料中有等號 =,就會視之為 FORM 類型的資料。 被 URL 編碼起來的等號 %3D 不在此例。 如果這樣,這些回傳資料會被設定為一個環境參數 QUERY_STRING 的值。 其實 CGI 定義了將近二十個環境參數,稍後再說些別的參數。 我們就不再多說關於 GET 的回傳方法了。

用 POST 方法回傳的資料,不寫在 URL 裡面,卻是用一種特別的內容方式傳回 httpd。 然後 CGI 會將這些參數原封不動地從 stdin 交給執行檔。 用 POST 方法回傳資料,CGI 程式還是可以得到一些環境參數。 但是此時 QUERY_STRING 這個參數沒有了,但是有以下參數可以用:

CONTENT_LENGTH
參數字元數,沒有結尾的 '\0'
HTTP_REFERER
這筆 POST 資料,是從哪張網頁送來的。檢查這個訊息, 可以稍微提高安全性。CGI 程式可以只服務從某張特定網頁傳來的資料。
REMOTE_ADDR
這筆資料是從哪個 IP 地址發出來的。
REMOTE_HOST
如果 DNS 可解上述 IP 地址,則有定義;否則無定義。 利用這個參數也可以稍微提高安全性,可以只服務 DNS 可解的主機。
SERVER_NAME
自己這個 Web Server 的網路名稱或 IP 地址。
SCRIPT_NAME
自己這個 CGI 程式相對於 WEBROOT 的路徑。 用這兩個參數,可以組成 http:$SERVER_NAME$SCRIPT_NAME 這樣的 URL。
以下是一個 FORM 環境的使用範例,讀者請閱讀範例的 HTML 原始碼,從例中學習。

FORM 類型的回傳參數,就像以下形式

PARA=one%25&PARA=two+MORE
它總是只有一列,也就是當中沒有裸露的 '\n'。 而且它不是以一個 NULL 字元結束。 它用一個 & 符號分隔兩個項目,因此若有 N-1 個 & 則共有 N 個項目。 每個項目都有一個裸露的 = 號, = 號左邊是參數名,右邊是對應的值。

一個 CGI 程式的最基本動作,就是解讀 (parsing) 輸入的字串。 這是一批麻煩的小東西。所幸已經有一些熱心人士替我們寫好了。 我選擇採用 Thomas Boutell 寫的 Cgic 程式庫。這是一批 ANSI C 函式, 幫助我們取得參數的值,並且轉換成方便的資料的型態。

課外讀物:
[1] NCSA 的 CGI 說明與範例文件 http://hoohoo.ncsa.uiuc.edu/cgi/
[2] Netscape Cookie 說明文件 http://www.netscape.com/newsref/std/cookie_spec.html
[3] ANSI C 的 CGI 輔助工具庫 (CGIC), by T. Boutell http://www.boutell.com/cgic/
[4] Perl 5 的 CGI 輔助工具庫 (CGI.pm), by L. Stein http://stein.cshl.org/WWW/software/CGI/cgi_docs.html
[5] C++ 的 CGI 輔助工具庫 libcgi++

[ 回單元目錄 ]



單維彰
中央大學數學系
桃園,中壢 320
shann@math.ncu.edu.tw
(C) Copyright 2001 Wei-Chang Shann 單維彰
建立:2001/04/11‧修改:2001/04/23