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