1.何謂CGI(Common Gateway Interface)程式 ?
一般的 HTML
文件內容在經過編輯整理後, 便固定不變(除非作者本身視需要修改).
可
是當文件中的資料會隨時間而變動時,
也就是說文件的內容並非一成不變的情況下, 上
述 " 固定式的 HTML " 文件便無能為力了.
CGI程式就是為了建立 " 可變式 HTML "
所採用的一種方法之一.底下有一段英文說明,
不妨參考看看
The Common Gateway
Interface, or CGI, is a standard for external gateway programs to
interface with information servers such as HTTP servers.
在 HTML
文件中使用CGI程式的方法,
就如同其他種類的資源定位一般, 利用
<a href="http://電腦/目錄/CGI程式名稱">敘述</a>的方式來取
得資源.
可利用 Unix
的 Shell
Script 來撰寫
CGI程式. 事實上, 只要是在 WWW
Server
上可以執行的可執行檔, 皆可以當作 CGI程式.
所以, 用什麼語言來撰寫
CGI程式都可以.
date 程式內容如下:
------> date <------
#!/bin/sh
# 第一行的 #! 是 Unix shell script 的固定寫法
# 其後的 /bin/sh 是說這個CGI程式是在 /bin/sh
這個shell下執行
# 第二行後以 # 開頭的行,皆是當作註解使用
echo Content-type: text/plain
echo
# 上面這兩行是固定要寫的
# 事實上,經測試 echo Content-type: text/plain
這一行亦可省略
# 但是 echo 這一行一定要存在
echo -n '現在時間是 : '
# 顯示 '現在時間是 : ' 這段文字
# -n 參數表示印完文字後不換行
/bin/date
# 執行 Unix 中 date 的指令
--------------------
看看 date 這個CGI程式的執行結果吧!
print_input
程式內容如下:
------> print_input <------
#!/bin/sh
echo Content-type: text/html
echo
if [ $# = 0 ]; then
# 在 shell script 中 $#
代表傳到本程式的所有引數個數
# 當呼叫此程式時如未給任何參數, 則 $# = 0
# 下面這一段有特別的技巧, 叫做"行中的輸入重定向"
# 如果字串' << '在一命令之後,如 command <<
word
# 則 shell 會用其後的輸入行當作 command
命令的標準輸入,
# 直到碰到一行內只有字串 word 才停止.
# 下列幾行就是將 <TITLE> .......EOM 間的資料傳給
cat 命令
# 結果就是將這幾行字顯示在螢幕上.
cat << EOM
<TITLE>秀字程式</TITLE>
<H1>秀字程式</H1>
<ISINDEX>
您想印出"什麼東東",就在方格內輸入"什麼東東"
EOM
# <ISINDEX> 會產生一個輸入方格,讓您輸入任何東西
# 但是程式要在完全執行完畢後, 才讓您輸入東東(
特別注意這點 )
# 當您按下<Enter>時,
就會將輸入的資料當作本程式的引數
# 重新執行本程式.
#
# 在 shell script 中有幾個特別的參數
# 1. $# : 所有引數的個數
# 2. $0 : 目前這個程式的名稱
# 3. $1,$2,.. : 位置參數, 也就是第一個引數,第二個引數,..
# 4. $* : 所有的引數, 也就是 $* = $1 $2 ...
else
# 以下這一段是有輸入引數時才執行的,
也就是您在輸入方格
# 按下<Enter>後,再次執行本程式時才動作
# 請注意下面幾行的寫法和 HTML
文件的寫法完全相同, 只是都被包含在" "之間
# 並且都是用 echo 來顯示
echo "<pre>"
echo $*
echo "<hr>"
echo "<a href="/cgi-bin/print_input"><img
src="/image/leftenter.gif">回秀字程式</a>"
echo "</pre>"
fi
---------------------------
看看 print_input 這個CGI程式的執行結果吧!
如果您未輸入任何東東,就按下<Enter>將會出現一個"應用程式錯誤"
這個CGI程式需配合 HTML 中 FORM 及 INPUT 使用
首先,看看下面這個 HTML 文章( 注意:不是CGI程式喔!)
note_board.html
內容如下:
------> note_board.html <------
<html>
<title>酸 甜 苦 辣 留 言 版</title>
<body>
<h1>酸 甜 苦 辣 留 言 版</h1>
<hr>
當您看完了後,<br>
相信您也有話要說,<br>
別客氣, 通通寫在留言版上,<br>
我會一一參考改進,<br>
謝謝<p>
<form method=post action="/cgi-bin/note_board">
<pre>
您的大名 : <input name="visitor" size=42>
標 題 : <input name="subject" size=42>
</pre>
留言版很大, 不要浪費了, 想寫什麼就寫什麼,
歡喜就好!
<textarea name="comments" rows=15 cols=60>留言:</textarea><p>
<input type="submit" value="8-) 哈哈哈
確定留言!!!">
<input type="reset" value="8-< 寫錯了
擦掉重來!!!">
</form>
</body>
</html>
實例說明
上面這一部份要當作下面CGI程式的輸入界面.
請您注意一下<form ... >這一行的
"/cgi-bin/note_board", 這才是我們所要介紹的CGI程式.
下面的表格就是
note_board.html 所產生的.
酸 甜 苦 辣 留 言 版
當您看完了後,
相信您也有話要說,
別客氣, 通通寫在留言版上,
我會一一參考改進,
謝謝
您的大名 :
標 題 :
留言版很大, 不要浪費了, 想寫什麼就寫什麼,
歡喜就好! 留言:
或許您會問當已經寫好了,
要怎麼樣才能送出去呢? 其實很簡單, 您只要按下
"8-)哈哈哈 確定留言!!!" 這個按鈕,
就可以了.
接下來, 要講最重要的地方, 請您集中精神.
當您按下按鈕, 程式便將所有資料傳給 "/cgi-bin/note_board" 這個程式.
傳送的格式如下:
visitor=JoJo&subject=Just+test&comments=%AF%64%A8%A5%3A........
您可以清楚的看到下面的幾點:
a) 程式傳給 "/cgi-bin/note_board"
的資料只有一項, 就是 "visitor..." 這一項.
b) 變數的名稱(visitor,subject,comments)及出現順序,
皆與 note_board.html 中的一樣.
c) 變數間以 "&" 符號互相隔開.
d) 變數名稱和輸入變數值以 "="
符號互相隔開.
e) 大小寫英文字母,數字,某些符號可以正確無誤的傳送.
f) 空白以 "+" 來代表. 其他符號以 "%符號的ASCII值"
來代表. 例如: ":"以"%3A"來代表.
g) 中文字則以兩位元的 BIG5 碼表示. 例如: "留"這個字的
BIG5 碼為 af64,
以"%AF%64"來表示.
看到這裡, 想必您已經猜到
"/cgi-bin/note_board"
這個CGI程式的作用就是讀取傳送到的資料,
將資料還原成原來的樣子,
並依照我們的需求來處理.
note_board 程式內容如下:
------> note_board <------
#!/bin/sh
echo Content-type: text/html
echo
read data
echo $data > /tmp/data.tmp
# 讀取資料並放入 /tmp/data.tmp 中
visitor=`cut -d"&" -f1,1 /tmp/data.tmp`
subject=`cut -d"&" -f2,2 /tmp/data.tmp`
comments=`cut -d"&" -f3,3 /tmp/data.tmp`
# 因變數間以 "&" 相互隔開, 故利用 cut
來得到單一變數.
echo $visitor > /tmp/data.tmp
visitor=`cut -d"=" -f2,2 /tmp/data.tmp`
echo $subject > /tmp/data.tmp
subject=`cut -d"=" -f2,2 /tmp/data.tmp`
echo $comments > /tmp/data.tmp
comments=`cut -d"=" -f2,2 /tmp/data.tmp`
# 因變數名稱與輸入變數值以 "=" 隔開,
故利用 cut 來得到輸入變數值.
rm /tmp/data.tmp
# 刪除暫存資料檔
# 至此, 我們已經得到每個變數的輸入值
# 以下便是依照個人需要來處理變數.
echo "Visitor : $visitor" >> /tmp/note
echo "Subject : $subject" >> /tmp/note
echo "Comments : $comments" >> /tmp/note
echo
"---------------------------------------------------"
>> /tmp/note
echo "<pre>"
echo "我已經記下您的留言,
"
echo "如果有需要, 我會儘快給您回信,
"
echo "謝謝.
" echo "<hr>" echo "<a
http://http://alpha.secc.fju.edu.tw/~macgyver/skill/cgi/tools_text.html#formend
src="/image/rightenter.gif"></a>
回CGI程式寫法說明." echo "</pre>"
------------------------------------------- 看看 note_board
這個CGI程式的執行結果吧!
仔細的您, 在看完上面的程式, 可能會有一個小小的疑問, 我們好像還沒有將被更改的
中文字, 符號 及空白恢復原狀? 沒錯, 目前為止, 我們只是取出變數值, 並依照需要予以
處理而已. 您或許會問為什麼我們沒有處理這些字碼的轉換的呢? 原因有二, 一則字碼
轉換程式可以適用於每個使用 FORM , INPUT 的CGI程式, 為了使用上的方便, 所以
寫成另外一個轉換程式; 二則如果每次有新的留言, 就執行轉換程式一遍, 只是徒然浪
費時間罷了. 基於上述兩個理由, 筆者另外寫了一個轉換程式, 只有當您想看留言的內
容時, 才執行轉換程式, 這樣就能達到省時又省力的目的.
使用 Unix Shell Script (
Bourne Shell ) 的一個轉換程式, 格式如下:
trans
(輸入檔) ==> 直接輸出到螢幕
或
trans (輸入檔) > (輸出檔)
==> 輸出到目的檔案
以"酸甜苦辣留言版"這個CGI程式而言, 若想看留言的內容, 則需做下列的轉換工
作.
trans /tmp/note >
Object_file
Object_file 就是所有留言的資料,
作者只要看這個檔案, 就可以知道您的寶貴意見囉!
這個CGI程式將使用到 HTML 中的 FORM , INPUT 及 SELECT 等功能, 並配合一個
極簡易的讀者意見調查資料庫工作.
reader 內容如下:
------> reader <------
#!/bin/sh
echo Content-type: text/html
echo
if [ $# != 0 ]
then
# 當呼叫 reader 時, 若有給定參數(也就是輸入資料),
則會執行下面的程式段.
# 這部份程式段的功能在將讀者輸入的個人資料,
和調查結果分別取出.
# 然後加入讀者意見調查資料庫中.
read data
name=`echo $data | cut -d"&" -f1,1 | cut
-d"=" -f2,2 | /home/User/WWW/cern_httpd_3.0/docs/work/trans
| cut -c1-6`
# 將名字由 data 中取出, 經過 trans 轉換成中文,
然後只取前 6
# 個字母(三個中文字)來顯示.
sex=`echo $data | cut -d"&" -f2,2 | cut
-d"=" -f2,2`
# 取出性別的輸入資料
unit1=`echo $data | grep "unit1" | /usr/ucb/wc -l`
unit2=`echo $data | grep "unit2" | /usr/ucb/wc -l`
unit3=`echo $data | grep "unit3" | /usr/ucb/wc -l`
unit4=`echo $data | grep "unit4" | /usr/ucb/wc -l`
value1=`echo $data | grep "value1" | /usr/ucb/wc -l`
value2=`echo $data | grep "value2" | /usr/ucb/wc -l`
value3=`echo $data | grep "value3" | /usr/ucb/wc -l`
value4=`echo $data | grep "value4" | /usr/ucb/wc -l`
value5=`echo $data | grep "value5" | /usr/ucb/wc -l`
# 分別設定 unit1-4 , value1-5 之值.
# 1 : 表示得到一票 0 : 表示沒有.
# unit1-4 分別表示四個 CGI 單元得票與否.
# value1-5 分別表示您對本文的評價等級.
echo "<pre>"
echo
$name'~'$sex'~'$unit1$unit2$unit3$unit4'~'$value1$value2$value3$value4$value5
| tr ~ '\11' >> /home/User/WWW/cern_httpd_3.0/docs/work/reader.db
echo "</pre>"
# 這三行是把讀者的輸入資料,
加入讀者意見調查資料庫中.
fi
# cat << EOM
# ... anything ...
# EOM
# 下面的內容, 就是使用者所看到的表格.
cat << EOM
<title>讀 者 意 見 調 查 表</title>
<center><h1>讀 者 意 見 調 查 表</h1></center>
<hr>
<form method=post action="/cgi-bin/reader??">
<dl>
<dt>◎ 您的基本資料:
<p>
<dd>您的大名:<input name="name" size=16>
<dd>您的性別:<input type="radio"
name="sex" value="man" checked> ♂
<input type="radio" name="sex"
value="woman"> ♀
<p>
<dt>◎ 您最喜歡的單元:(複選)
<p>
<dd><input type="checkbox" name="unit"
value="unit1">現在幾點了???
<dd><input type="checkbox" name="unit"
value="unit2">寫什麼就秀什麼???
<dd><input type="checkbox" name="unit"
value="unit3">酸甜苦辣留言版???
<dd><input type="checkbox" name="unit"
value="unit4">讀者意見調查表???
<p><p>
<dt>◎
您對於”CGI程式寫法說明”的評價:
<p>
<dd><select name="value" size=1>
<option value="value1">好極了
<option value="value2"> 好
<option value="value3">普 通
<option value="value4"> 爛
<option value="value5">爛透了
</select>
<dt><hr>
<dd><input type="reset" value="重寫一張"><input
type="submit" value="投進票箱">
<dt><hr>
</dl>
</form>
<pre>
<h3>目前意見調查情形如下:</h3>
單單單單 好 普 爛
姓 名 姓
別 元元元元 極好 爛透
一二三四 了 通 了
</pre>
EOM
echo "<pre>"
cat /home/User/WWW/cern_httpd_3.0/docs/work/reader.db
echo "</pre>"
#
上面這幾行就是列印選項說明及讀者調查資料庫的資料.
echo "<hr>"
----------------------------------------------------------
這個CGI程式的 key point 有兩點:
首先, 請注意程式中如下的這一行
<form method=post action="/cgi-bin/reader??">
︿︿︿︿
看到了嗎?有兩個奇怪的”?”在CGI程式
reader 的後面. 這兩個問號( 三個問號也
可以 )的作用是把讀者輸入 的資料傳給自己 (也就是 reader), 如果不加上這兩個問號,
則只是執行 reader 而已, 並不將讀者輸入的資料傳入.看到這裡, 您當會發現這個
CGI程式執行時, 可能有兩種情況, 不帶參數和帶參數兩種. 不帶參數的情況發生在
html 直接呼叫 reader . 而帶參數的情況發生在由 FORM 呼叫 reader 時, 也就是讀者輸入資料, 然後按下 submit 或 return 時.
由於上述兩種執行情況的不同,
才產生第二個 key point , 也就是
if [ $# != 0 ]
then
...
fi
這個 if ... else ... fi 的結構. 當執行 reader
且沒有參數 ( #$ =0 ) 時, 就會略過這段程式.
如果附帶有參數 ( $# != 0 ) 時, 則會執行這段程式碼. 而這段程式就是負責處理讀者的
輸入資料, 並將該資料加入讀者意見調查資料庫中.
讀者意見調查資料庫( reader.db )的格式如下, 提供您參考看看:
王小明 man 0 0 0 1 1 0 0 0 0 kevin man 1 1 1 1 0 1 0 0 0 ...... ... ....... .........
很多重要的 CGI 應用程式需要的訊息都是由 UNIX 環境變數所提供的. 在 Perl 中可由
$ENV 來取得環境變數
環境變數 | 說明 |
GATEWAY_INTERFACE | Server 使用的 CGI 版本 |
SERVER_NAME | Server 的 host 名稱或 IP 位址 |
SERVER_SOFTWARE | 回應 client request 的 Server 軟體名稱和版本 |
SERVER_PROTOCOL | 傳遞資訊所用的協定名稱或版本 |
SERVER_PORT | Server 正在執行的 port number |
REQUEST_METHOD | 發出 request 的方法 |
PATH_INFO | 傳遞給 CGI 程式的額外路徑 |
PATH_TRANSLATED | 存在 PATH_INFO 中的給定路徑的傳遞版本 |
SCRIPT_NAME | 程式執行時的 virtual path |
DOCUMENT_ROOT | 網路提供的文件服務所在路徑 |
QUERY_STRING | 傳遞給程式的 query 資訊 |
REMOTE_HOST | 使用者發出 request 的遠端 host 名稱 |
REMOTE_ADDR | 使用者發出 request 的遠端 IP 位址 |
AUTH_TYPE | 用來確定使用者合法性的鑑定方法 |
REMOTE_USER | 使用者的合法名稱 |
REMOTE_IDENT | 發出 request 的使用者 |
CONTENT_TYPE | query 資料中的 MIME 型別 |
CONTENT_LENGTH | 資料長度,以 byte 或字元數來計算 |
HTTP_FORM | 使用者發出 request 的電子郵件訊息 |
HTTP_ACCEPT | client 可以接受的 MIME 型別列表 |
HTTP_USER_AGENT | client 用來發出 request 的瀏灠器 |
HTTP_REFERER | 在讀取 CGI 程式前,client 所指的文件 URL |