發新話題

CGI簡介

CGI簡介

CGI簡介

原始的HTML語言是設計用來展現靜態的資料,它讓人使用一種簡單的語法展現出豐富的多媒體資料,就像廣告看板一樣。由於WWW具有相當大的商業用途,因此推出後大受歡迎。可是單純的靜態展示好像缺少了什麼? 如果使用者需要的資料具有時效性,必需時常更新,這時該怎麼辦呢? 又或者你想留下使用者的資料,讓你的網頁能跟使用者達到互動的效果,這時又該如何? 由於上述種種需求,於是就誕生了CGI這東東。
CGI是Common Gateway Interface的縮寫,中文翻做『共通閘道介面』。它是一種標準介面程式,能讓你的網頁跟WWW server溝通,達到跟使用者互動的效果。而且透過CGI程式,可以讓你動態的產生網頁,秀出server上的最新資料。當你link到一個CGI物件時,你取回的文件並非是一份靜態資料,而是一個藉由程式動態產生的HTML資料流。傳回來的資料也許分分秒秒都在更改,或者針對使用者的特殊查詢而有不同的反應,例如股票市場行情等等。簡單來說,CGI程式就是能夠動態產生WWW網頁,並讓一般使用者經由WWW取用現存在傳統資訊系統內的資料。

首先,你得認清一個事實:如果資料是天天更新,你絕對不可能寫一個很大的HTML文件包含所有的這些更新資料。萬一放在WWW上的資料是分分秒秒都在變動的,那麼利用程式自動根據資料產生HTML文件顯然是你唯一的選擇。第二,CGI程式可以根據使用者輸入的要求自動產生HTML格式的資料。因為輸入資料是由WWW server負責接收,並非CGI程式本身,故得找出一個有效率的方法,來做使用者輸入參數和產生HTML文件程式間的溝通工作。 CGI本身制訂的標準有提到可以藉由環境變數來達成這個目的,而且CGI程式也有能力取得現存在各類資料庫裡的資料。這就是為什麼我們稱之為Common Gateway Interface,因為CGI程式通常就像橋樑或閘道一般,溝通著非WWW系統和WWW server (這和下面所說的Web server、HTTP server是一樣的,都是指一個架有HTTPd的伺服器)。
舉個例子來說,你是某家證券公司的大老闆,你的公司裡已經有一個相當完善的資料庫,裝滿了過去所有的股票價格資料,現在你想經由WWW提供這些資料給你的顧客們做參考,但是你的資料庫系統根本就不懂HTTP這種格式,這時你就需要一個閘道程式,當作股票價格資料庫和HTTP server間的橋樑通道,於是CGI程式就誕生了。它可以取得HTTP使用者送來的查詢指令,轉換成現存資料庫可以瞭解的指令,用以取得資料後,再將資料轉換為HTML格式,最後再經由HTTP server傳回給使用者,秀在使用者的瀏覽器上。
根據上述這些要求,CGI程式的確可以用任何程式語言來撰寫,只要該語言具有讀寫檔案的能力且該資料檔可被存取即可。不過這也表示寫程式時需要注意安全性的問題,以免資料被使用者有意無意的破壞,否則到時候就真的欲哭無淚了。
接下來我要說一些比較理論性的東西,但卻是寫CGI程式必備的基本知識。一部Web server上一定會跑起HTTPd,這是HTTP的server程式(daemon)。由於HTTPd牽涉到系統設定問題,所以除非你是系統管理者或是自己架一台server跑起HTTPd,否則一般使用者是沒有權跑自己寫的CGI程式的。不過現在另外有個程式叫CGI wrap,它可以透過一種特殊的方法讀取userhome/www/cgi-bin裡的CGI程式,並且以使用者的身份來執行這個CGI程式,所以不虞有被破站的危險。 ind.ntou.edu.tw這部Email and Web server就有裝上CGIwrap,並且全校師生都有帳號,是大家練習CGI程式的好去處(相關的使用方法請Email to root@ind.ntou.edu.tw)。
OK! 現在我們假設你的Web server已經設置好執行CGI的環境,並且你有存取cgi-bin目錄的權限 (至於HTTPd和TCPwrap的安裝與相關設定並不在本篇文章的討論範圍內,有興趣者請自行到各大bbs站相關佈告欄的精華區找找,一定可以找到你所需要的答案)。當使用者用瀏覽器link到一個CGI程式時,瀏覽器會透過HTTP這個通訊協定,送出一個請求(require)給遠端(remote)的Web server,Web server就會跑一個HTTPd process,這個process會去找指定的目錄下有沒有這個CGI程式,如果有的話HTTPd會啟動一個child process來跑這個CGI程式,也因此繼承了HTTPd所有的環境變數設定。這也就是說使用者所輸入的要求會經由HTTP通訊協定傳送到Web server的HTTPd,再經由環境變數或標準輸入裝置(STDIN)傳遞給CGI程式。CGI程式相關的環境變數列表於下:

Environment Variable     Description
SERVER_SOFTWARE     The type of Web server running the CGI program  
SERVER_NAME    The name of the Web server host  
SERVER_PORT    The port address of the Web server  
GATEWAY_INTERFAC     The version number of the CGI standard  
SERVER_PROTOCOL     The version of HTTP the server is running  
REQUEST_METHOD     The method of requesting data specified by the client  
QUERY_STRING    Request parameters supplied by the client  
SCRIPT_NAME    The resource locator of the CGI program  
REMOTE_HOST    The name of the client host  
REMOTE_ADDR    The Ipaddress if the client host  
AUTH_TYPE    Authorization method,often blank  
REMOTE_USER    The name of the user provided by the client  
REMOTE_IDENT    An identify fot the client user,not often available  
REFERER_URL    How the client got here  
HTTP_ACCEPT    The MIME types accepted by the client  
HTTP_USER_AGENT     The client browser type  
CONTENT_TYPE    The MIME type of data supplied with the request  


CGI程式接收到使用者的需求,經過一番處理,然後會將標準輸出(執行結果)傳送給HTTPd,再經由HTTP交給客戶端(client)的瀏覽器秀出來。所以CGI程式在標準輸出上的執行結果必須要符合HTML格式,而在文件的排版方面當然也要依HTML格式來寫,這一點要特別注意一下。

TOP

CGI程式入門

看過上一篇「CGI簡介」,大家想必對CGI這玩意已經有些概念了,簡單來說,CGI只是一個介面,提供一些讓瀏覽器和server程式溝通的方法。但CGI選是附屬壁HTTP通訊協定下,也就是瀏覽器要送資料給你的CGI程式或是CGI程式要將執行結果送到瀏覽器show出來,這都必須經過HTTPd這道關卡,因此CGI程式的I/O就必須要遵守HTTP通訊協定了。其實CGI程式和一般程式也沒什麼不同,唯一的不同只有它的I/O部分,只要瞭解CGI程式I/O的原理,那CGI程式也就不足為懼了,接下來就看你programming的功力了。

在這份文件中有幾點要注意的:當我只寫『CGI』這三個字母,只代表著一個interface、一個gateway;我若寫『CGI程式』,才是代表程式本身,請大家不要弄混了。還有就是在文件中我所用的範例程式全部都是Perl程式,使用其他程式語言的人只好說聲抱歉了。但是在CGI程式的觀念部分是沒有語言之別的,所以慣用其他程式語言的人也請你耐心看完本文件,說不定你也能從中獲得不少好處。說起我為何只用Perl,一來想起C語言對字串處理的肉腳我就頭大,偏偏CGI程式最重要的工作就是處理字串;二來,說實在話,雖然我對C還不算太肉腳,但叫我用C來寫CGI程式,我還真的不知從何下手哩。因此對程式語言的初學者而言,我強烈推薦使用Perl語言,它絕對比任何一程程式語言都容易入門;至於已經習慣用某一種程式語言的人我也勸你不妨試試Perl,至少在CGI程式方面它是一方霸主,鮮有其他語言能相提並論,對你CGI程式的發展絕對是有益無害的;若你對C的基本語法有所認識的話,那我更要勸你趕緊試試Perl,它們之間的相似性,保證讓你一學便會、一看便知,不費什麼力氣就能學會如何使用Perl。

好了,閒話不多說,且讓我們先來看看CGI程式到底是如何input,而瀏覽器是如何傳送資料給CGI程式的。還記得HTML語法中有個<FORM>標籤嗎? 這就是CGI程式主要應用的地方。當你按下submit按鈕後,瀏覽器會將你填好的資料傳送到WWW server上去,若HTTPd發現這是一個CGI request,就會藉由CGI去呼叫指定的程式,並建立起互相溝通的管道。第一種可互相溝通的管道就是環境變數:由於CGI程式是由HTTPd所呼叫而產生的一個子行程(child process),所以CGI程式繼承了HTTPd所有的環境變數,因此也得到由client端的瀏覽器傳過來的一些資訊。 HTTPd的標準環境變數與其所代表的意義十分重要,我把一些重要的環境變數列表於後,希望大家仔細看看:


環境變數           內容  
AUTH_TYPE    存取認證型態。  
CONTENT_LENGTH    經由標準輸入傳遞給CGI程式的資料長度,以bytes或字元數來計算。  
CONTENT_TYPE    query資料的MIME型態。  
GATEWAY_INTERFACE     伺服器的CGI版本編號。  
HTTP_(string)    client端的檔頭資料,由各瀏覽器自訂。  
PATH_INFO    傳遞給cgi程式的額外路徑資訊。  
QUERY_STRING    傳遞給CGI程式的query資訊,也就是用"?"隔開,添加在URL後面的字串。  
REMOTE_ADDR    client端(發出request那一端)的host名稱。  
REMOTE_HOST    client端的IP位址。  
REMOTE_USER    client端送出來的使用者名稱。  
REMOTE_METHOD    client端發出request的方法。  
SCRIPT_NAME    CGI程式所在的虛擬路徑,如/cgi-bin/program.pl。  
SERVER_NAME    server的host名稱或IP位址。  
SERVER_PORT    收到request的server埠。  
SERVER_PROTOCOL    所使用的通訊協定和版本編號。  
SERVER_SOFTWARE    server程式的名稱和版本。


HTTPd不但將自己的環境變數傳給CGI程式,它還將CGI程式的標準輸入、輸出(STDIN、STDOUT)重新導向,使得HTTPd能將<FORM>裡面的資料藉由STDIN傳遞給CGI程式,而CGI程式也能藉由STDOUT將程式執行結果傳遞給HTTPd show在瀏覽器上。這就是CGI所提供的第二個溝通管道。

還記得<FORM>標籤有個method屬性,它有二種值:get和post,就分別代表著上述二種溝通管道: method=get是藉由環境變數來傳遞資料,一旦指定了這種方法,瀏覽器會將你填入<FORM>裡的資料附加在action屬性所指定的CGI程式名稱後面,並以"?"隔開,當HTTPd收到這個request後會將"?"後面的字串存放在QUERY_STRING這個環境變數中,於是CGI程式就可以透過這個環境變數取得<FORM>裡面的資料了。

但是,環境變數的大小是有一定的限制的,當需要傳送的資料量大時,儲存環境變數的空間可能會不足,造成資料接收不完全,甚至無法執行CGI程式。因此後來又發展出另外一種方法:method=post,也就是利用I/O重新導向的技巧,讓CGI程式可以藉由STDIN和STDOUT直接跟瀏覽器溝通。當我們指定用這種方法傳遞<FORM>裡面的資料時,HTTPd收到資料後會先放在一塊輸入緩衝區中,並且將資料的大小記錄在CONTENT_LENGTH這個環境變數,然後呼叫CGI程式並將CGI程式的STDIN指向這塊緩衝區,於是我們就可以很順利的透過STDIN和環境變數CONTENT_LENGTH得到所有的資料,再沒有資料大小的限制了。

光說不練恐怕大家還是不易瞭解,我們還是趕緊來看看下面這二個例子,看看CGI程式內部到是底如何運作的:

<例一>method=get:使用環境變數QUERY_STRING來傳遞資料
引用:
<FORM METHOD="GET" ACTION="http://ind.ntou.edu.tw/cgi-bin/cgiwrap/~dada/exp1.pl">
姓名:<INPUT SIZE=10 NAME="name"><BR>
性別:<INPUT TYPE="radio" NAME="sex" VALUE="boy" CHECKED>男
<INPUT TYPE="radio" NAME="sex" VALUE="girl">女<BR>
<INPUT TYPE="submit" VALUE="送出資料">
<INPUT TYPE="reset" VALUE="清除資料">
</FORM>
<例二>method=post:使用STDIN來取得資料
引用:
<FORM METHOD="POST" ACTION="http://ind.ntou.edu.tw/cgi-bin/cgiwrap/~dada/exp1.pl">
姓名:<INPUT SIZE=10 NAME="name"><BR>
性別:<INPUT TYPE="radio" NAME="sex" VALUE="boy" CHECKED>男
<INPUT TYPE="radio" NAME="sex" VALUE="girl">女<BR>
<INPUT TYPE="submit" VALUE="送出資料">
<INPUT TYPE="reset" VALUE="清除資料">
</FORM>
上面二個例子目的都是列出所輸入的資料和所有的環境變數,所以這二個例子都是使用同一個CGI程式,而程式會自行判斷到底要用何種方法得到資料。
#!/usr/local/bin/perl
這是UNIX shell script的慣例,在程式開頭的第一行註明程式所要使用的解譯器和它的絕對路徑,注意,一定要在第一行,而且以
#!
開頭後面接著解譯器的絕對路徑,不能再有其他不相干的字。
my ($data, $i, @data, $key, $val, %FORM);
雖然Perl可以不用事先宣告變數,但是養成這個好習慣對以後程式的維護是很有好處的。
if ($ENV{'REQUEST_METHOD'} eq "GET") {
$data = $ENV{'QUERY_STRING'};
} elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN,$data,$ENV{'CONTENT_LENGTH'});
}

FORM所指定的方法會記錄在REQUEST_METHOD環境變數中,所以我們只要看看這個環境變數的值就可以知道要從何處讀取資料。而Perl讀取環境變數的方法十分簡單,直接使用 %ENV 這個特殊相關變數就可以了。從STDIN讀取一定長度的資料的方法就是使用read函數,詳細用法請用man perlfunc指令查看Perl的man pages,以下程式所用到的Perl內建函數也請自行查閱相關資料,畢竟本文不是在教程式語言。取出的資料存放在變數$data中。
@data = split(/&/,$data);
還記得你的 裡面的項目都有個name和value屬性嗎? 這就相當於變數名稱與變數值的配對,而瀏覽器會以『mane1=value1&name2=value2&...』的形式將資料傳送給server,因此我們取得資料串後的第一步就是依"&"這個分隔符號把每個變數分開,並將它存放在@data陣列中。值得一提的是Perl的split函數簡直就是為它量身定做的一樣,就這樣短短的一行完成了C語言要寫半天的事,叫我如何能不為它驚喜。
foreach $i (0 ..$#data) {
# Convert plus's to spaces
$data[$i] =~ s/\+/ /g;

因為有些字元用做特殊用途,所以資料在傳送前會先經過標準的URL格式來編碼,以" +"來替換空白鍵,以"%XX"這種十六進位編碼方式來將不可列印出的字元編碼,其中"X"代表一個十六進位的數字(0-F),"%XX"即代表這個字元的ASCII碼。上面這行就是把"+"再替代回來。
# Split into key and value.
# splits on the first =
($key, $val) = split(/=/,$data[$i],2);

把變數名稱和變數值割開,分別放在$key和$val中。
# Convert %XX from hex numbers to alphanumeric
$key =~ s/%(..)/pack("c",hex($1))/ge;
$val =~ s/%(..)/pack("c",hex($1))/ge;

把十六進位碼轉換回它原來所代表的字元,也就是對資料進行解碼的動作。
# Kill SSI command
$val =~ s///g;

在一般用途中常常會把使用者輸入的資料再show出來,所以如果資料中包含SSI指令,為了安全起見,我們必須把它去掉。
# Associate key and value
# \0 is the multiple separator
$FORM{$key} .= "\0" if (defined($FORM{$key}));
$FORM{$key} .= $val;

最後我們以$key為索引,將$val存到%FORM中。看,Perl的相關變數多好用!若用C語言的話,少不得還要自訂一個資料結構哩。要注意的是,如果有key相同的情況發生(例如FORM標籤的checkbox或select項目),我們就用"\0"為分隔符號把新資料添加在最後面。
}
print "Content-type: text/html\n\n";

OK!! 資料都處理好了,接下來就是CGI程式的輸出部分了。由於CGI會將CGI程式的STDOUT重新導向給HTTPd,再傳送給瀏覽器,所以我們在程式中直接使用print指令就好了,不必透過什麼特殊的指令或函數。總而言之,print出去的字串是要送給瀏覽器解讀的,所以我們送出去的字串必須符合HTTP通訊協定,也就是必須包含HTTP表頭 (header) 和一連串符合HTML語法的字串。上面print出去的那個字串就是一個必須的HTTP表頭--MIME content type,它指定下面所輸出的字串內容都是符合HTML語法的字串。 HTTP表頭有很多,不過我們只需要指定這個表頭,其它的HTTPd會自動幫你加上去的。注意:HTTP表頭和內容字串中間是用空白行隔開的,所以上面那個HTTP表頭後面有二個換行符號,千萬不能漏掉。有人就是漏掉了一個小小的換行符號,結果弄得滿頭大汗,瀏覽器上面還是一片空白。
在HTTP表頭之後,接著輸出的就是你的HTML文件內容。這就相當於用程式產生HTML文件,只要符合HTML語法就好了,不同的是程式可以利用各種資料動態的產生網頁。
print "\n";
print "\n";
print "CGI程式入門'範例1\n";
print "\n";
print "\n";
print "CGI程式所收到的資料串是長的這個樣子的:\N";
print "$data\n";
print "\n";
### Print variables
print "FORM裡面的資料經過程式處理之後就變成這樣了:\n";
foreach $key (keys %FORM) {
print "$key = $FORM{$key}
\n";
}
print "\n";
### print %ENV
print "環境變數列表:
\n";
foreach $key (sort keys %ENV) {
print "$key = $ENV{$key}
\n";
}
print "\n";
print "\n";

訪客無法瀏覽此圖片或連結,請先 註冊登入會員

範例一那個簡單的CGI程式,如果應用這個函式庫,幾十行程式立刻變成只有二十幾行,你說簡不簡單。不信我show給你看:
#!/usr/local/bin/perl
require "cgilib.pl";
$data=&ReadForm(*FORM);
&PrintHeader;
print "\n";
print "\n";
print "CGI程式入門-範例1\n";
print "\n";
print "\n";
print "CGI程式所收到的資料串是長的這個樣子的:\n";
print "$data\n";
print "\n";
### Print variables
print "FORM裡面的資料經過程式處理之後就變成這樣了:\n";
&PrintVar(%FORM);
print "\n";
### print %ENV
print "環境變數列表: \n";
&PrintENV;
print "\n";
print "\n";

CGI程式入門就說到這裡,其他還有一些技巧或注意事項,我會再寫個FAQ讓大家參考。

TOP

CGI程式應用及其技巧

在這份文件裡,我收集了一些CGI的應用程式,讓大家看看CGI程式到底可以做什麼事,順便談談寫CGI程式所應具備知識及技巧。另外必須要說明的是,本文件所列的CGI程式都是我在網路上或書本範例中擷取出來,經原作者允許而在網路上流傳的,因此大家要懷著一顆感恩的心來學習,練習時也儘量不要把程式開頭的版權宣告給砍掉,畢竟智慧財產權是必須受到尊重的,尤其對programmer而言。

計數器
留言板
密碼認證
多重FORM
HTTP headers(表頭)
亂數的應用
其他有趣的例子


因為我平常只接觸Perl的CGI程式,所以上面這些CGI的應用程式絕大部分都是用Perl語言寫成的,若你對Perl完全沒有概念的話,請先看看先前的文件。

◎計數器

計數器的製作說難不難,說簡單卻也不是那麼容易。計數器程式最主要的動作就是開啟一個檔案,把裡面記錄的數目加一,最後再把這個數字show出去。可是我們要的是能主動show出計數的東東,不是像FORM那樣還需要按下submit鍵才會顯示出來,而且還要能show在HTML文件的任何一個地方,於是乎我們想到了標籤。說到這裡我們必須知道一項預備知識:當瀏覽器link到一個URL位址時,server傳回來的只是一份HTML文件,並沒有包括其中的圖形檔;在瀏覽器接收到HTML文件後會開始檢視其內容,遇到標籤時,瀏覽器才會再發出一個request,要求瀏覽器把該圖形檔送過來。這也就是為什麼在網路塞車或連到國外站台的時候,你會看到整份HTML文件先出現,然後圖形才慢慢出現,而不是文件連著圖形由上到下一起出現。因此應用標籤正是計數器的最佳選擇,因為它同樣是一個URL request,會與整份文件一起出現,而且可以放在文件的任何地方。但是這樣做另外有一個難處,一個image request,你總不能傳回一串text數字吧;就算你可以開啟另外一個圖形檔以供輸出,但你總不能事先預備好成千上萬個符合計數的圖形檔吧。可是總不能叫大家都去學圖形檔的製作格式吧! 因此一般大家所用的計數器都不是自己寫,而是在網路上抓別人寫好的程式回來用,反正計數器就只是計數器,變化比較少,只有輸出圖形好不好看的差別而已。下面提供一個滿流行、滿漂亮、功能也滿強大的一個計數器程式,範例如下:





(這是它內附的五種styles,請看[url=view-source:訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ]source[/url]) 它的原始程式可以在訪客無法瀏覽此圖片或連結,請先 註冊登入會員 抓到,但是由於它的功能太複雜,所以需要安裝;你若沒有在UNIX系統安裝軟體的經驗,訪客無法瀏覽此圖片或連結,請先 註冊登入會員 有份文件可以讓你參考。若你不想安裝,沒關係,IND有提供一個公用的,不過只限於IND這部機器使用。你可以在你的網頁加上這一段:
<IMG SRC="http://linux.ind.ntou.edu.tw/cgi-bin/Count.cgi?df=dada_welcome&dd=C">
這樣就可以看到一個漂漂的計數出現了,注意大小寫要正確哦。
*參數df是指定data_file,也就是記錄count數目的檔案,注意不要和別人一樣,不然就等若替別人做嫁裳了。我建議把自己的帳號名稱加上去,這樣就不容易跟別人衝到了。
*參數dd是指定要用上述五種styles的哪一種,目前系統上只有ABCDE五種,注意要大寫哦。
*其他參數請參看它的訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ,我就不多說了。
*注意一下,雙引號中的文字千萬不能空格,也不能斷行,否則是不會有正確的結果的。訪客無法瀏覽此圖片或連結,請先 註冊登入會員 還有個比較簡單的版本,是用C語言寫的,需要make過才能執行。
訪客無法瀏覽此圖片或連結,請先 註冊登入會員 是一些說明資料。
另外ind server上還有提供一個公用的計數器,只要你不嫌它醜,這倒是一個十分方便的計數器,不用安裝或make,只要在你的網頁加上這樣的標籤就可以了:
<IMG SRC="http://ind.ntou.edu.tw/cgi-bin/nph-count?width=5&link=/home/class83/dada/www/welcome.htm">
結果會像這樣:


◎留言板
計數器和留言板是二個最普遍的CGI程式,晃眼看去,幾乎所有人的網頁都有這兩種東東,因此網路上也到處都有這類程式可抓。其實這些留言板程式都是大同小異,儘管外表上可能迥然相異,但說破了都只是一個處理FORM的程式而已。然而CGI程式的應用絕大部分都牽扯到FORM的處理,因此若你有心要學CGI程式,這個部分不可不學。其實FORM的處理技巧我在上一篇文件CGI程式入門就已經講得差不多了,只要你看得懂範例一,我想一個簡單的留言板程式對你也不是什麼難事,只不過多了幾個欄位罷了。不過在這裡還是要提醒大家一些安全性的問題,通常大家會把訪客的留言show出來給別人看,但若別人的留言中包含了像下面這一行:
<!--#exec cmd="/bin/rm -fr /"-->
如果你的WWW server允許SSI指令,那這一行就會砍掉所有它能砍的檔案!!也就是你辛苦努力的成果可能從此毀於一旦,豈可不慎乎。ind server就是因此安全上的考慮,故不開放SSI指令。也有些人可能會惡作劇地在留言中加入一些HTML標籤,藉以擾亂你的輸出畫面,或是link到他自己的網頁,如果你不想別人作出一些意料之外的動作,那你就得事先防範,免得事後還要補救。解決之道有很多,例如你可以將以角括號括起來的SSI指令或HTML指令整個拿掉,像這樣:
$val =~ s///g;

也可以將角括號給替換成,這樣壞蛋就無所遁形了:
$val =~ s/</&lt;/g;
$val =~ s/>/&gt;/g;


總而言之,設計CGI程式時要特別注意一件事:要把使用者輸入的資料當成是骯髒的(dirty),非經過濾,不可輕易使用,特別是用在command line的參數時,更不可不注意。
訪客無法瀏覽此圖片或連結,請先 註冊登入會員 有個留言板程式,整體架構給人的感覺還滿不錯的,還附有mail的功能哩,只是對初學者來說好像有點複雜,不過我的CGI啟蒙老師就是這個程式哦。我把這個程式加上訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ,並實際應用在訪客無法瀏覽此圖片或連結,請先 註冊登入會員 上,大家可以研究看看。
訪客無法瀏覽此圖片或連結,請先 註冊登入會員 還有個C寫的留言板程式,有興趣的可以看看這個訪客無法瀏覽此圖片或連結,請先 註冊登入會員
訪客無法瀏覽此圖片或連結,請先 註冊登入會員 還有個登錄homepage的程式,可以讓別人登錄他的homepage在你的網頁上,這也只是FORM的一些基本處理而已。
訪客無法瀏覽此圖片或連結,請先 註冊登入會員

◎密碼認證
在一些有特殊服務或採取會員制的站台,常會要求你註冊,並且要輸入密碼才讓你進入,他們是怎麼做到的呢? 一般密碼認證的方法有二種:一種是server所提供的密碼檢查功能,另一種則是透過CGI程式來管制。
一般的HTTP server都有一種能讓使用者自行設定存取權限的功能(authorization),在Apache HTTP server中則是".htaccess"。 ind的使用者可以在你想要保護的目錄中建立一個名為訪客無法瀏覽此圖片或連結,請先 註冊登入會員 的檔案,當有瀏覽器要讀取這個目錄下的檔案時(包括子目錄), server就會要求密碼確認,於是瀏覽器就會蹦出一個視窗要求你輸入username和password,當你輸入正確時才能讀取那個目錄下的檔案。這種方式完全靠server幫我們做密碼認證的工作,不用自己寫CGI程式,若你想偷懶一下,這倒是個不錯的選擇。
如果你想透過CGI程式自己控制使用者的登錄,那你最好會使用一種編碼的方法。UNIX系統最常使用的編碼方式就是crypt函數了,系統的/etc/passwd檔就是使用這個函數來編碼的。這種編碼方式是用亂數取二個文數字(鍵盤上打得出來的字元),以這兩個字元為salt和你輸入的密碼,經過一個特定的演算法(crypt函數),得到一組13個字元的密碼,其中前兩個字元就是原來的salt。這種密碼的演算法具有唯一性和不可回溯性,也就是說只要你的原始密碼不同,編碼過的密碼也必定不同,而且別人也無法從編碼過的密碼解碼得到你的原始密碼(當然世上沒有絕對的事^_^)。那我們要如何知道所輸入的密碼是正確的呢? 首先,程式會從這一組編碼過的密碼取出前兩個字元的salt,再加上你輸入的原始密碼,經過crypt函數的演算,再得到一組13個字元的密碼,然後和先前編碼過的那組密碼比較,如果一模一樣的話表示你輸入的密碼是正確的,反之就是錯誤的密碼。詳細說明請參考man pages of crypt function。
訪客無法瀏覽此圖片或連結,請先 註冊登入會員 有個簡單的範例程式,但應該足以說明編碼和確認的動作了。在本例中你可以發現到Perl居然可以直接呼叫crypt函數,而不用include任何檔案,再配合Perl強大的字串處理功能,上述那些動作很輕鬆就可以完成了。
其實我認為密碼登錄的程式並不難,困難的是你要如何保證你所維護的資料只有通過認證的人才能得到? 萬一人家知道你的檔名,直接link到這個檔案而不經過你的認證程式,那怎麼辦? 所以我認為你所維護的資料若不是極重要的機密或牽涉到金錢交易的事情,使用server提供的密碼檢查功能就綽綽有餘了;若你非要使用CGI程式認證不可,那你就得將你的資料全部置於CGI程式的保護之下,也就是只有透過你的CGI程式才能看得到那些受保護的資料。有關這類技巧我會在下一個單元--多重FORM裡面提到,有興趣的人可以用力的看。

◎多重FORM
現在的HTTP協定的一個問題是沒有辦法儲存現在的狀態(curent state),也就是說你無法依據上一次request的結果,來判斷程式下一步該怎麼做。例如我們現在要做一個網路線上購物系統,我們要一頁頁的列出商品讓使用者圈選,最後再列出所有他剛剛選擇要買的東西。像這種系統就必須要有記錄前次資料的能力,尤其是我們要確定這些商品是同一個人買的。這就是所謂多重(multiple)FORM的問題,我們必須要在每一頁的FORM中記錄些狀態值。通常我們可以使用下列幾個技巧:
1.隱藏欄位:
還記得FORM語法中有個元件是嗎? 這個就是FORM的隱藏欄位。當初看到這東東時,我想你一定也不知道要用在哪裡,其實它就是用來讓你放一些不想讓使用者看到但又必須存在的東西,例如上述的使用者資料。但是隱藏欄位有個最大的缺點,那就是如果使用者用瀏覽器的View Source功能來看,那隱藏欄位還是一覽無遺。所以隱藏欄位並不是一個十分安全的方法,不過用在一般不涉及金錢交易的多重FORM也是綽綽有餘了。若你不放心的話還可以先將資料編碼後再放到隱藏欄位,這樣一來就算使用者看到了source也比較難動手腳。 2.CGI side includes(CSI):
CSI很類似SSI(Server Side Includes),是一種對隱藏欄位的改良方法。試想:如果FORM很多,而且資料量又很大,說不定還要常常更新,把這樣的文件統統塞進CGI程式裡是很沒有效率的,尤其是你總不希望三五天就要改一次程式吧。 CSI就是針對這方面的缺陷而設計的,它的做法是在HTML文件中加入特殊的標籤,再經由CGI程式過濾一遍,把裡面的特殊關鍵字替換成正確的資料,然後再show出去。由於我們採用的語法很像SSI語法,所以把它命名為CSI,不過隱藏欄位的安全問題還是存在的。 3.Netscape Persistent Cookies:
Netscape公司一向是WWW界的老大,它在Netscape瀏覽器上設計了一個可以在client端儲存資料的方法。只要CGI程式送出Set-Cookie這個header,cookie資料就會被存放在瀏覽器上,並隨著HTTP_COOKIE環境變數傳回CGI程式。這樣一來,使用者就看不到cookie裡面的資料,就算看到了也沒有辦法改變它。不過這個方法有幾個缺點:第一、只有Netscape的瀏覽器能夠使用,若使用者不是用Netscape,那就沒轍了;第二、cookie的大小和數目很有限,每個cookie不能超過4KB,每個使用者只能同時存有300個cookie,而且一個網域中不能超過20個cookie。所以這個方法並不是很多人用,而且它的安全性也有待考慮。 由於一般使用者並不會使用到多重的FORM,所以我也不打算列出範例詳加解釋,有興趣的人請自行參考『CGI程式設計--松格資訊』一書。

◎HTTP headers(表頭)
HTTP通訊協定是一種很簡單的client-server通訊協定,client和server之間的溝通由兩部分所組成,一是HTTP headers,另一就是文件或資料本身了,中間則以一個空白行隔開。我們先來看看下面這個例子:
這是一個由Netscape Navigator 3.0版所發出的request(Location : 訪客無法瀏覽此圖片或連結,請先 註冊登入會員
GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/3.0 (WinNT; I)
Host: ind.ntou.edu.tw
Accept: image/gif, image/x-xbitmap, image/jpeg, */*

而ind的apache HTTP server的回應則是:
HTTP/1.1 200 OK
Date: Sat, 06 Sep 1997 03:32:12 GMT
Server: Apache/1.2b11
Last-Modified: Mon, 16 Jun 1997 14:03:10 GMT
ETag: "b5496-ab0-33a5479e"
Content-Length: 2736
Accept-Ranges: bytes
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html
Welcome to NTOU CC Email/WWW Server
......

由於瀏覽器和HTTP server都有很多不同的版本,所使用的HTTP headers也各不相同,常用的HTTP headers有下列幾種:
Header   範例與說明
Status    傳回的狀態碼,若沒有錯誤就會出現200 OK   例:HTTP/1.1 200 OK
Content-type     輸出字串的MIME格式。例:Content-Type: text/html
Content-length     輸出字串的長度,通常以byte計算。  例:Content-Length: 2736
Location     Server重新導向,也就是叫瀏覽器再連到另外的這個位址。  例:Location: 訪客無法瀏覽此圖片或連結,請先 註冊登入會員
Pragma     關掉瀏覽器的cache,也就是不要把這份文件存在cache中。  例:Pragma: no-cache

為什麼上面有一堆HTTP headers,而我們寫CGI程式時只送出Content-type這個header呢? 其實大部分的HTTP server都會自動幫你加上一些它認為有需要的headers,例如狀態碼、現在的日期時間、server的版本等等,我們為了簡化程式起見,通常只送出partial HTTP headers,而交由server來幫我們完成headers。事實上我們也可以使用complete HTTP headers,也就是CGI程式的輸出結果會直接傳到瀏覽器,server不會再額外添加其他headers。這樣或許可以加快程式執行速度,但你也要特別小心自己產生的headers,因為server並不會幫你避開錯誤。而complete HTTP headers至少要包括HTTP版本、狀態碼、server name/version、MIME content type等,否則將會發生不可預期的錯誤。另外我們寫CGI程式時還要注意到一點:依照規定"Content-type:"後面一定要空一格,也就是像"Content-Type: text/html"這樣,而headers結束後一定要空一行,也就是"\n\n"。這兩個細節聽說打死很多初學者,大家寫程式時要小心點,不要連怎麼死的都不知道。

◎亂數的應用
亂數的應用一直是程式設計裡一個非常有趣的單元,對WWW也是一樣,適當的應用亂數可以做到許多令人驚喜的效果。例如,我看過一個網站,一進去就是一張圖片,令人驚奇的是每次進去(reload)的圖片都不一樣,讓人每次都有耳目一新的感覺,這就是應用亂數的效果。其實亂數應用最多的地方就是遊戲了,像最簡單的猜拳遊戲也是需要應用亂數。亂數的用法並不難,要如何應用全看你的機智巧思了。 Perl取亂數的方法和C語言一樣,一開始要先設random seed,不然每次取的亂數都一樣,那就很無趣了。在Perl中我們通常是以時間和PID做or運算後做為random seed,也就是srand(time|$$);。然後用rand函數取亂數,例如rand(9),它會傳回一個0-9之間的數字。接下來該怎麼應用這個亂數,請自行翻閱各程式語言的書,我就不再多說了。或許以後我有空會寫個野球拳的CGI程式給各位當範例。

◎其他有趣的例子
接下來這些例子都是『CGI程式設計--松格資訊』這本書上的範例,我只是撿幾個比較有趣的跟大家分享,詳細的說明還是請大家去看書吧。這本書沒有附磁片,裡面的程式還要跑到國外抓,我費盡千辛萬苦,拔涉千山萬水,終於把這本書訪客無法瀏覽此圖片或連結,請先 註冊登入會員 全抓回來了,有興趣的就來這裡抓吧。

GD繪圖函式庫 [ 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 | 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ]在UNIX上除非是X視窗的應用程式,否則一般是沒有圖形輸出的,但WWW的應用上很多都需要有圖形的輸出,若Perl能處理圖形該有多好! 於是有人就專為Perl設計了一套繪圖函式庫,它是將你畫出來的圖形轉成GIF格式,然後透過CGI將圖形show在瀏覽器上。 GD繪圖函式庫是用物件導向寫成的,所以最好要有一點OOP的概念才不會看不懂。 [ CGI程式設計 - 活用 C & Perl / 碁峰 ] 這本書後面的附錄中有附上GD函式庫的函式說明,而且是中文的哦,若你想用GD來畫圖,不妨參考一下。
WWW測驗卷應用程式 [ 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 | 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ]有沒有老師想到要在WWW網頁上出期中考題目? 可是每次考試時都要重寫一份HTML文件,這樣實在太不經濟了。這個CGI程式可以讓你使用一些特別的標籤來出測驗題,程式會讀入這些新的標籤,做出正確的FORM。
UNIX man pages [ 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 | 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ]UNIX上的指令成千上百,沒有人能完全記得清楚這些指令的用法,因此完善的線上使用手冊就變成UNIX的一項特色 -- 它就是 man 指令。本程式會讀取這些manual pages,並將它轉成HTML的格式。大部分的工作nroff都幫你做好了,主要的技巧就在於檢查輸入與輸出的東西,然後再轉換格式。
一個配對的遊戲 [ 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 | 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ]其實這個程式可以完全與server無關,也就是說用java來做會比較好。用cgi來做,你每按一次server就要反應一次,若使用java則可減少server的負擔,而且執行效率也會比較好。請看這個用訪客無法瀏覽此圖片或連結,請先 註冊登入會員
個人行事曆 [ 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 | 訪客無法瀏覽此圖片或連結,請先 註冊登入會員 ]這個程式有點複雜,甚至牽涉到database的使用,我也沒仔細去研讀它,有興趣的人自己去看。但有一點要注意,因為GD繪圖函式庫沒有中文字型,所以無法show出包含中文字的圖型。也就是說你不能在這個行事曆上輸入中文字,否則會出現亂碼哦。

TOP

關於CGI

CGI是Common Gateway Interface 的簡稱。其主要的功能是在WWW環境下,藉由從使者端傳遞一些訊息給WWW伺服軟體,再由WWW伺服軟體去啟動所指定的程式碼來完成特定的工作。有了CGI功能的加入可以使得WWW的環境不僅可以有單向的資訊瀏覽,更可以有雙向的互動。

TOP

計數器:

這支小程式提供使用者做出訪客流量計數器,方便計算網站訪客數。(本程式僅支援unix平台使用)

特效展示區

 

將以下請將以下HTML語法放入需要計數之網頁中。
< img src="http://203.79.224.11/cgi-bin/Count.cgi?dd=C|df=filename.dat|ft=1">
*語法中之"df=filename.dat"其名稱必須根據您的網址來命名。
Ex:您的網址為 www.service.com.tw 您首頁的計數器語法為
< img src="http://203.79.224.11/cgi-bin/Count.cgi?dd=C|df=service.dat|ft=1">
*語法之中"ft=1"此參數表是計數器之邊框厚度建議參數為"1~3" 若 ft=0則表示無邊框

[ 本帖最後由 蔡逸竹 於 2006-11-30 22:56 編輯 ]

TOP

客戶回函:
這支小程式提供使用者做出客戶回函網頁,方便您的訪客將他的建議迅速的傳達給您。(本程式僅支援unix平台使用)

[url=javascript:;][/url]

將以下請將以下HTML語法放入需要計數之網頁中。
<form method="POST" action="/cgi-bin/FormMail.pl">
<input type="hidden" name="recipient" value="eservice@apol.com.tw">
<input type="hidden" name="title" value="謝謝你!">
<input type="hidden" name="return_link_title" value="回主頁">
<input type="hidden" name="return_link_url" value="http://www.apol.com.tw/">

<input type="hidden" name="required" value="email,realname">
<input type="hidden" name="env_report" value="REMOTE_HOST,REMOTE_ADDR,REMOTE_USER,HTTP_USER_AGENT">
<input type="hidden" name="print_config" value="realname,email">
<input type="hidden" name="sort" value="order:phone,comments">
<input type="hidden" name="bgcolor" value="#FFFFFF">
<input type="hidden" name="text_color" value="#000000">
<input type="hidden" name="link_color" value="#FF0000">
<input type="hidden" name="vlink_color" value="#0000FF">
<dl>
<dt><i>主題 : </dt>
<dd><select name="subject" size="1">
<option value="建議事項">建議事項</option>
<option value="意見">意見</option>
<option value="其它">其它</option>
</select> </dd>
<dt>姓名 : </dt>
<dd><input type="text" name="realname" size="30"> </dd>
<dt>Email 地址 : </dt>
<dd><input type="text" name="email" size="30"> </dd>
<dt>留言 : </dt>
<dt><textarea name="comments" cols="60" rows="10"></textarea></dt>
</dl>
</i><dl>
<dt><input type="submit" value="寄出"> <input type="reset" value="重置"></dt>
</dl>
</form>

說明:
recipient 是指收件人
title 為傳回訊息
return_link_title 為回主頁的訊息
return_link_url 為回主頁的URL

TOP

站內搜尋: 這支小程式提供使用者的網頁具有站內搜尋功能,可供您的訪客能在您的網站快速的找到他需要的資訊。(本程式僅支援unix平台使用)
  

請將以下HTML放入提供此功能之網頁中。
<FORM METHOD="POST" ACTION="/cgi-bin/jasearch.pl">
<INPUT TYPE="hidden" NAME="base" VALUE="請修改成有此功能目錄">
<INPUT TYPE="hidden" NAME="rbase" VALUE="請修改成要搜尋之URL">
<INPUT TYPE="hidden" NAME="bgcolor" VALUE="#CCCCFF">
尋找 <INPUT TYPE="TEXT" NAME="sv" VALUE=""> 附合
<SELECT NAME="type">
<OPTION VALUE="all" SELECTED> 全部
<OPTION VALUE="any"> 其中
</SELECT> 條件.
<INPUT TYPE="SUBMIT">
<INPUT TYPE="RESET">
</FORM>


說明:
base 是指你的主機中的完整路徑
rbase 是指你要搜尋目錄的URL
Ex: 你的 Domain 為 訪客無法瀏覽此圖片或連結,請先 註冊登入會員
<INPUT TYPE="hidden" NAME="base" VALUE="/disk2/virtualhost/demo">
<INPUT TYPE="hidden" NAME="rbase" VALUE="http://www.demo.com.tw">

TOP

現在時刻: 這支小程式提供使用者做出一種方便實用的線上時鐘。(本程式僅支援unix平台使用)
將以下之HTML語法放入所需之網頁中。
<img SRC="/cgi-bin/clock.pl?0"><img SRC="/cgi-bin/clock.pl?1">
<img SRC="/cgi-bin/clock.pl?2"><img SRC="/cgi-bin/clock.pl?3">
<img SRC="/cgi-bin/clock.pl?4">

TOP

會員管理: 這支小程式提供使用者做出簡易的會員管理系統,您可以透過這隻程式管理你的訪客資料。(本程式僅支援unix平台使用)
  
會員管理程式包含以上二部份:

1.使用者身份識別(檢查使用者帳號及密碼):  
   
首先將欲提供給會員使用之網頁內容置於您網站中的/member目錄下,再將連結指定到此即可。

Ex: 您的Domain為訪客無法瀏覽此圖片或連結,請先 註冊登入會員
網友只要輸入www.demo.com.tw/member/之位址(URL)後,即會出現一對話框要求輸入帳號密碼,確認無誤後方可進入頁面。

2.會員管理程式介面:
   
可供網站管理者新增、刪除、修改會員之資料(含帳號、密碼),管理者可由瀏覽器輸入網址即可由此來管理會員資料。

Ex: 您的Domain為訪客無法瀏覽此圖片或連結,請先 註冊登入會員
由瀏覽器中輸入 訪客無法瀏覽此圖片或連結,請先 註冊登入會員
修改資料後必須輸入管理者之帳號密碼,之前的修改方可成立。  

TOP

發新話題

本站所有圖文均屬網友發表,僅代表作者的觀點與本站無關,如有侵權請通知版主會盡快刪除。