CGI 程式寫法說明

原作者是誰, 我已不知道了, CGI 中的程式我修改過, 可能與本文中的些許不同, 但本篇文章的版權屬原作者的


 本 文 目 錄

1.何謂CGI程式 ?
2.如何使用CGI程式呢 ?
3.用什麼語言來撰寫CGI程式呢 ?
4.第一個簡易CGI程式寫作:現在幾點了???
5.第二個CGI程式寫作:寫什麼就秀什麼???
6.第三個CGI程式寫作:酸甜苦辣留言版???
7.第四個CGI程式寫作:讀者意見調查表???
8.CGI程式之 Q & A
9.CGI實驗室


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.
2.如何使用CGI程式呢 ?
在 HTML 文件中使用CGI程式的方法, 就如同其他種類的資源定位一般, 利用

<a href="http://電腦/目錄/CGI程式名稱">敘述</a>

的方式來取得資源.

3.用什麼語言來撰寫CGI程式呢 ?
筆者使用的 WWW 是建立在 SunOS 的工作站上, 屬於 Unix 的作業環境下, 因此筆者是利用 Unix 的 Shell Script 來撰寫 CGI程式. 事實上, 只要是在 WWW Server 上可以執行的可執行檔, 皆可以當作 CGI程式. 所以, 用什麼語言來撰寫 CGI程式都可以.
4. 第一個簡易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程式的執行結果吧!     

怎麼樣!有趣吧!接下來再看一個例子.

5. 第二個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>
賓果!恭喜您得到一個"應用程式錯誤"的大獎.
好強的您如果想要做到盡善盡美,下一個例子千萬不可錯過喔!

6.第三個CGI程式寫作:酸甜苦辣留言版???
這個CGI程式需配合 HTML 中 FORM 及 INPUT 使用, 如果您不熟悉 FORM 及 INPUT 的寫法, 請參考 本府 Home Page 中的文章.

首先,看看下面這個 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 href="http://alpha.secc.fju.edu.tw/~macgyver/skill/cgi/tools_text.html#formend"><img 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程式使用 perl 這個 shell 來處理字串有關的部份, 聽說 prel 在處理字串方面的能力很強, 但是這個程
式並非 Unix 的內建 shell , 需要另外安裝, 除此之外, 還得學習 prel 的語法, 筆者私下認為倒不如使用 Unix 的 shell script
來處理相關部份.

如果您想要筆者寫的這個轉換程式, 請在 trans.Z 這個字上按一下, 就可以拿到手啦!

拿到手時, 然後在 Unix 下, 執行下面的敘述, 就可以得到 trans 這個檔案了.

7.第四個CGI程式寫作:讀者意見調查表???
這個CGI程式將使用到 HTML 中的 FORM , INPUT 及 SELECT 等功能, 並配合一個極簡易的讀者意見調查資料庫工作, 如果您
不熟悉 FORM , INPUT 及 SELECT 的寫法, 請參考
本府 Home Page 中的文章.

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/cer
n_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
# 這個結構, 我們在&rdquo;秀字程式&rdquo;中曾經解說過.
# 如果您忘記了, 麻煩您回頭看一下吧!

# 下面的內容, 就是使用者所看到的表格.

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>◎ 您對於&rdquo;CGI程式寫法說明&rdquo;的評價:
<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>"

----------------------------------------------------------看看 reader 這個CGI程式的執行結果吧!     

這個CGI程式的 key point 有兩點:
首先, 請注意程式中如下的這一行

<form method=post action="/cgi-bin/reader??">
              ︿︿︿︿
看到了嗎?有兩個奇怪的&rdquo;?&rdquo;在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
Richar  man      1 1 1 1         0 1 0 0 0
......  ...      .......         .........

哈哈哈!恭喜您已經練成乾坤大挪移第四層的功力, 接下來...休息一下吧!

8.CGI程式之 Q & A
9.CGI實驗室

如果您有任何意見或指教, 您可以寫在"酸甜苦辣留言版", 也可以直接寫信給我.

E-mail : macgyver@alpha.secc.fju.edu.tw


如果您還有時間, 歡迎您來 輔仁大學理工學院電算中心全球資訊網逛逛.
並提供您的寶貴意見, 讓我們作為改進之參考.
謝謝