CGI腳本工作原理
引言
新的網站設計人員在建立網站之后經常問到一個問題就是:“什么是CGI腳本,如何在我的網站上使用它?”或“如何在我的網站上創建交互式表單?”。
在本文中,我們將回答有關CGI腳本的問題,并演示如何創建自己的腳本。
在此過程中,您還將了解有關Web服務器的一些知識。讓我們開始吧!
Web服務器
如Web服務器工作原理一文中所述,Web服務器相當簡單。從根本上說,Web服務器只是從磁盤中檢索出文件,并通過網絡將其發送到發出請求的瀏覽器。假設您鍵入URL:http://www.bygpub.com/books/tg2rw/author.htm。Web服務器將會獲得一個針對文件/books/tg2rw/author.htm的請求。查看下圖,您可以了解服務器是如何解決該請求的:
|
在安裝過程中,Web服務器已被告知c:My Documentswww是服務器的根目錄。然后,該服務器會從根目錄中找出/books/tg2rw/author.htm。當您請求URL http://www.bygpub.com/books/tg2rw/時,該服務器就會知道您正在查找該目錄的默認文件。它會查找一些不同的文件名以試圖找到默認文件:index.html、index.htm、default.html和default.htm。根據服務器的不同,它也可以查找其他文件名。因此,該服務器會將 http://www.bygpub.com/books/tg2rw/轉換為 http://www.bygpub.com/books/tg2rw/index.htm并傳送該文件。所有其他文件必須通過明確給出文件名來指定。
這就是所有Web服務器處理靜態文件的方式。大多數Web服務器還可以通過稱作通用網關接口(CGI)的機制處理動態文件。您已經在Web上的各種地方看到過CGI,只不過您當時可能對它并不了解。例如:
- 您可以在任何留言簿上通過HTML表單輸入消息,當下一次查看此留言簿時,頁面將會包含您輸入的新條目。
- Network Solutions上的WHOIS表單允許您在表單上輸入域名,返回的網頁將根據輸入的域名而有所不同。
- 任何搜索引擎都允許您在HTML表單上輸入關鍵字,然后它將根據您輸入的關鍵字動態創建頁面。
所有這些動態頁面使用的都是CGI。
CGI機制
在大多數Web服務器上,通過以下方式使CGI機制標準化。在服務器視為根目錄的普通目錄樹中,可以創建一個名為cgi-bin的子目錄。(可以在上一頁的圖示中查看此目錄。)然后,服務器了解到不應只是讀取和發送從特殊cgi-bin目錄中請求的任何文件,而應執行它們。執行的程序的輸出內容是它實際發送給請求該頁的瀏覽器的內容。一般來說,可執行程序既可以是一個純可執行程序(就像C編譯器的輸出),也可以是一個PERL腳本。PERL是一種用于CGI腳本的最流行的語言。
假設您在瀏覽器中鍵入URL:http://www.howstuffworks.com/cgi-bin/search.pl。由于服務器了解到search.pl位于cgi-bin目錄中,因此它會執行search.pl(一個PERL腳本),并將執行的輸出內容發送到瀏覽器。
您可以編寫自己的腳本并試驗CGI,前提是:
- 您了解某種編程語言,如C或PERL。
- 您對處理CGI腳本的Web服務器擁有訪問權限。如果您已為用于承載您的網站的Web托管服務付費,則可以選擇通過您的主機來訪問CGI腳本。有關詳細信息,請查看托管服務。如果您沒有為用于承載您的網站的Web主機服務付費,則可以通過在家用計算機上安裝Web服務器并學習如何使用它來進行試驗。盡管第二種選擇要稍微復雜一些,但您在此過程中肯定可以學到很多知識!
簡單的CGI腳本
假定您對cgi-bin目錄擁有訪問權限(請參閱上一節),了解C編程語言或PERL,則可以使用CGI執行一系列有趣的試驗。讓我們從創建最簡單的CGI腳本開始。
在網頁基礎知識一文中,我們研究了可能存在的最簡單的HTML網頁。這個網頁的形式如下:
這個可能存在的最簡單的CGI腳本在執行時,將會創建上述的簡單的靜態頁面作為其輸出。以下是用C語言編寫此CGI程序的形式:
在Web服務器上,將此程序輸入到文件simplest.c中,然后通過以下命令進行編譯:
(有關如何編譯C語言程序的詳細信息,請參見C語言入門教程。)
將simplest.cgi放置在cgi-bin目錄中,它就可以執行了。您現在就可以通過鍵入或單擊此URL來嘗試一下:http://www.howstuffworks.com/cgi-bin/simplest.cgi。您可以看到,該腳本所做的全部工作就是生成顯示“Hello there!”的頁面。唯一沒有預料到的部分就是下面這行內容:
“Content-type:text/htmlnn”這行內容是一段特殊的文本,任何CGI腳本必須首先將它發送給瀏覽器。只要您記住這一點,就一切ok了。如果您忘記了這一點,則瀏覽器將拒絕輸出腳本。
您可以在PERL中執行相同的操作。將下面這段PERL代碼鍵入到一個名為simplest.pl的文件中:
將該文件放置到cgi-bin目錄中。在UNIX計算機上,鍵入以下內容也許會有用:
這將告知UNIX該腳本是可執行的。您現在就可以通過鍵入或單擊此URL來嘗試一下:http://www.howstuffworks.com/cgi-bin/simplest.pl。
您現在已經了解了CGI腳本的基本概念。相當簡單!實際上就是,執行一個程序,然后將程序的輸出發送到調用腳本的瀏覽器。發送給stdout的正常輸出就是發送給瀏覽器的輸出。
不過,CGI腳本的重點在于創建動態內容——每次執行腳本時,輸出應該是不同。畢竟,如果每次運行腳本時的輸出都是相同的,您也可以使用靜態頁面。以下C語言程序演示了非常簡單的動態內容:
使用一個文本編輯器,將此程序鍵入到一個名為count.c的文件中。通過鍵入以下命令對其進行編譯:
創建另一個名為count.txt的文本文件,并在其中放入一個零。將counter.cgi和count.txt放置在cgi-bin目錄中,即可以運行腳本。您現在就可以通過鍵入或單擊此URL來嘗試一下:http://www.howstuffworks.com/cgi-bin/count.cgi。您可以看到,腳本所做的全部工作就是生成一個顯示“The current count is:X”的頁面。運行一次腳本,其中的X就會遞增一次。嘗試將腳本運行幾次,并注意觀察頁面內容的變化!
count.txt文件保留當前計數,同時小的incrementcount()函數使count.txt文件中的計數遞增。此函數將打開count.txt文件、從中讀取數字、遞增數字并將其寫回到文件中。實際上,此函數會嘗試打開文件兩次。這樣做是為了防止兩個用戶試圖同時訪問該文件。這項技術并非萬無一失,但對于這類簡單情況還是有效的。如果在第二次嘗試時無法打開文件,則將為調用者返回錯誤值-1。更加完善的程序將識別返回值-1,并會生成相應的錯誤提示。
gcc count.c -o count.cgi
#include
int incrementcount()
{
FILE *f;
int i;
f=fopen("count.txt", "r+");
if (!f)
{
sleep(1);
f=fopen("count.txt", "r+");
if (!f)
return -1;
}
fscanf(f, "%d", andi);
i++;
fseek(f,0,SEEK_SET);
fprintf(f, "%d", i);
fclose(f);
return i;
}
int main()
{
printf("Content-type:text/htmlnn");
printf("n");
printf("n");
printf("
The current count is:")
printf("%dn", incrementcount());
printf("n");
printf("n");
return 0;
}
chmod 755 simplest.pl
#! /usr/bin/perl
print andquot;Content-type:text/htmlnnandquot;;
print andquot;andlt;htmlandgt;andlt;bodyandgt;andlt;h1andgt;Hello World!andquot;;
print andquot;
nandquot;;
printf("Content-type:text/htmlnn");
gcc simplest.c -o simplest.cgi
#include
int main()
{
printf("Content-type:text/htmlnn");
printf("n");
printf("n");
printf("andlt;h1andgt;Hello there!andlt;/h1andgt;n");
printf("n");
printf("n");
return 0;
}
andlt;h1andgt;Hello there!andlt;/h1andgt;
HTML表單
我們已了解到CGI腳本的創建過程相當簡單。Web服務器執行放置在cgi-bin目錄中的任何可執行程序,并且可執行程序發送給 stdout的任何輸出都將出現在調用該腳本的瀏覽器中。現在,我們需要找到一種用于將輸入發送到腳本的方法。發送輸入的一般方法是使用HTML表單。
表單在網絡上隨處可見。可以接受內容輸入的任何頁面都是表單。您可以在搜索引擎、留言簿、問卷等上面看到這些表單。您在HTML頁上創建表單,并在表單的HTML標記中指定CGI腳本的名稱,當用戶單擊表單上的Submit按鈕時將調用該腳本。用戶輸入到表單中的值將會進行打包并發送到CGI腳本,這樣腳本就可以隨意使用這些值。
實際上,上述情況是很常見的,只是您可能沒有意識到而已。例如,轉到 http://www.lycos.com,在“Search for:”框中鍵入“test”一詞并按“Go Get It!”按鈕。結果頁的 URL 類似于下面這樣:
您會發現Lycos主頁就是一個表單。Lycos在cgi-bin目錄中有一個名為pursuit的腳本。表單會向此腳本發送五個參數:
- matchmode=and
- cat=lycos
- query=test
- x=10
- y=9
第三個參數正是我們輸入的搜索字符串。其他四個參數也為腳本提供了一些信息。CGI腳本在Lycos數據庫中查詢“test”一詞,然后返回結果。這就是任何搜索引擎的核心!
讓我們創建一個簡單的表單進行試驗。創建一個名為simpleform.htm的文件,然后在其中輸入以下 HTML:
可以單擊此URL進行試驗:http://www.howstuffworks.com/simpleform.htm。
您可以看到,HTML代碼指定創建一個使用GET方法的表單,并將該方法發送給http://www.howstuffworks.com/cgi-bin/simpleform.cgi上的CGI腳本。該表單內包含一個文本輸入區域以及標準的“Submit”和“Reset”按鈕。
該表單引用的文件http://www.howstuffworks.com/cgi-bin/simpleform.cgi是一個C程序。它開始是作為一段C代碼放置在名為simpleform.c的文件中:
使用以下命令對這段代碼進行編譯:
然后,將其放置在cgi-bin目錄中。此程序只是收集表單發送的值并顯示出來。例如,您可能會看到以下內容:
Name是表單中的文本輸入字段的標識符(表單上的每個輸入字段都應具有唯一的標識符),John+Smith是可能在表單上輸入的典型姓名。請注意,“+”將替換空白字符。
通過本示例,您可以看出設置表單并將表單中的數據發送到CGI腳本中的基本過程是相當簡單的。有幾個細節需要注意:
- 表單上的每個輸入字段應具有唯一的標識符。
- 表單需要使用GET或POST方法。使用GET方法的好處是,您可以在發送給腳本的URL中查看表單的值,從而使調試更簡單。
- 由于對可以通過GET方法發送的字符數目存在一定的限制,因此對于大型表單,應優先使用POST方法。
- 使用GET方法發送的數據可以通過查看QUERY_STRING環境變量(通常使用 C 語言程序中的getenv函數和PERL中的$ENV工具讀取)接收。使用POST方法發送的數據可以通過STDIN(使用C語言程序中的gets或PERL中的 ead)獲取。
- 發送的數據會將所有字段串接在一個字符串中,并將替換許多字符,因此需要進行轉換。例如,所有空白將替換為加號。
提到QUERY_STRING環境變量,有必要在此大致介紹一下環境變量。您可以在CGI 腳本中看到大量環境變量,其中包括:
- AUTH_TYPE
- CONTENT_LENGTH
- CONTENT_TYPE
- GATEWAY_INTERFACE
- HTTP_ACCEPT
- HTTP_USER_AGENT
- PATH_INFO
- PATH_TRANSLATED
- QUERY_STRING
- REMOTE_ADDR
- REMOTE_HOST
- REMOTE_IDENT
- REMOTE_USER
- REQUEST_METHOD
- SCRIPT_NAME
- SERVER_NAME
- SERVER_PORT
- SERVER_PROTOCOL
- SERVER_SOFTWARE
這些環境變量中隱藏了許多有用的信息,其中包括輸入字符串的長度 (CONTENT_LENGTH)、使用的METHOD(GET 或 POST -- REQUEST_METHOD可讓您清楚是在STDIN 中還是在QUERY_STRING中查找輸入)、用戶計算機的IP地址 (REMOTE_ADDR),等等。有關這些變量的完整說明,請參閱CGI環境變量。
?
The value entered was:Name=John+Smith
gcc simpleform.c -o simpleform.cgi
#include#include The value entered was:")int main() { printf("Content-type:text/htmlnn"); printf("n"); printf("n"); printf("
printf("%sn", getenv("QUERY_STRING"));
printf("n");
printf("n");
return 0;
}
A super-simple form
Enter Your Name:
http://www.lycos.com/cgi-bin/pursuit?matchmode=and andcat=lycosandquery
創建真實表單
一個真實的表單將包含各種輸入區域,并需要在腳本中編寫一些代碼來撤消字符映射并分析出單個字符串。讓我們先看看表單上的標準輸入控件。這些控件包括:
- 單行文本輸入
- 多行文本輸入
- 選擇列表
- 復選框
- 單選按鈕
- 專用按鈕 - 用于提交或清除表單
以下的一些示例演示了如何使用不同的控件標記:
單行編輯
“input”一詞標識單行編輯區域。“name”字段為控件提供了一個用于 CGI 腳本的標識符,此標識符對于表單上的每個控件都應是唯一的。“size”字段指示表單上的輸入區域的寬度(以字符為單位);“Maxlength”對輸入區域內的最大字符數進行限制。“value”設置初始值。
Enter Name:
通常,輸入區域的前面是一段靜態文本,用于標識輸入字段的用途。此處顯示的是靜態文本“Enter Name:”。
可以添加值“type=int”,以便將輸入限制為整數值。默認情況下,值的類型為“text”,可接受任何字符。
多行編輯
多行編輯區域與輸入區域類似。你可定義該控件的名稱,并定義其在表單上的大小(以行和列為單位)。你在 標記之前輸入的任何內容都將作為默認值出現在控件中。
復選框
復選框是類型設置為“checkbox”的特殊形式的輸入區域。
如果選中復選框,則將返回值。
單選按鈕
單選按鈕與復選框類似,但它們可以組合在一起呈現:
Choose the search area:
Stocks Canadian Stocks Money Markets Mutual Funds
請注意,可以用 CHECKED 一詞來標記默認的單選按鈕。還請注意,同一組中的所有單選按鈕的名稱是相同的。
選擇列表
選擇列表使用戶可以在許多選項中進行選擇。選擇列表的標記可讓你在“size”字段中指定可見行的數目,并可讓你指定所有選項的值。
Select an Option
MULTIPLE 一詞將創建多選功能。
專用按鈕
下列標記將創建兩個專用按鈕,一個按鈕用于向服務器提交表單,另一個按鈕用于重置表單:
?
示例:創建網頁問卷
?
假設您要為某個網頁創建一份簡單的問卷。例如,您想要詢問讀者的姓名、性別、年齡和意見,然后在CGI腳本中進行處理。HTML表單可能存在于一個名為http://www.bowenwang.com.cn/survey.htm的文件中,形式如下:
?
BWW Survey Form
?
此表單引用的CGI腳本將接收四條不同的數據:提交表單的讀者的姓名、年齡、性別和意見。腳本將對這四個值進行分析并處理所有字符轉換。文件http://www.bowenwang.com.cn/survey.c用于創建腳本survey.cgi,其長度可能為100行。
?
關于CGI的一些知識
?
在這個關于CGI腳本的簡明教程中,我們已了解到:
- CGI腳本是一個程序——通常為C語言程序或PERL腳本。
- 在大多數服務器上,CGI腳本位于一個名為cgi-bin的目錄中。當瀏覽器請求腳本的URL時,將執行該腳本。
- 腳本發送給STDOUT的任何內容都將被發送給瀏覽器。首先發送字符串“Content-type: text/htmlnn”。然后,再發送其他內容;但是一般來說,將發送有效HTML文檔的有效HTML標記。
- 通過創建HTML表單并使用其中的 ACTION指定腳本的URL,可將輸入內容發送給腳本。
- 當腳本接收到表單中的數據后,需要分析出不同的字符串并轉換所有修改過的字符。我們演示了一個可以執行這些任務的簡單C語言程序。PERL的CGI庫(參見下一頁)使PERL腳本可以輕松轉換。
評論
查看更多