從這一講開始,我們將進入CGI 程式設計的學習過程。透過前面幾講的學習,您已經掌握了CGI 程式設計的基礎知識。現在,您可以坐下來編寫CGI 程式了!
三、CGI 程式設計
1、伺服器端附件(SSI) 及網關
2、網關:透過WEB 連接其他協定
在編寫CGI 程式的過程中,最好遵循以下幾個應用程式設計的要點:
(1)提出問題-- 您要解決的問題
(2)設計階段-- 構思出CGI 程式的基本架構與功能
(3)編碼階段-- 用行動實現思想
(4)程式移植-- 編寫可移植的程式碼
(5)精益求精-- 讓程式更上一層樓
1、伺服器端附件(SSI) 及網關
在本節將介紹伺服器端附件SSI(Server Side Include) 和網關。嚴格的說,SSI 並不是CGI 程式設計的內容,但SSI 可以完成一些簡單CGI 程式所能完成的工作,有時SSI 甚至是最好的選擇。因此,在這裡作簡單介紹。
SSI 定義了一組嵌入HTML 文字的指令,在HTML 文字送到HTTP 用戶端前,WEB 伺服器對這些SSI 指令先作預處理,將處理後的HTML 文字輸出到HTTP 用戶端的瀏覽器。
SSI 的命令格式是:
< !--# 指令參數=" 值" -->
SSI 指令同java 或JavaScript 不同,它是在伺服器端處理的,而不是在客戶端處理的,這點同CGI 程式是相似的。當然,在SSI 的功能範圍內,其優點同CGI 程式相同,可以提高伺服器的資源利用率,而且在客戶端用任何WEB 瀏覽器都可以瀏覽含有SSI 的HTML 文字。
以下是常用的六個SSI 指令:
(1)Include命令
(2)echo 命令
(3)exec 指令
(4)config 命令
(5)fsize 指令
(6)flastmod 指令
include 指令
唯一支援的參數是file,這是在目前HTML 文字中插入file 參數指定的檔案的內容。如果您了解C 語言,可以看出它和C 語言中的「#include」指令的功能是一樣的。例如,有兩個HTML 文字:main.html 和header.html,在main.html 中使用include 指令: main.html:
< html>
< tilte> Test Include SSI Command < /title>
< !--#include file="header.html" -->
< body>
The above header comes from header.html!
< /body>
< /html>
header.html:
< H1> This is a title in header.html! < /H1>
( 不過,好像OmniHTTPD 不支援include 指令,:< !)
echo 指令
唯一支援的參數是var,它用於顯示伺服器提供的變量,例如:
DOCUMENT_NAME:目前檔案名
DOCUMENT_URL:SSI 文本的相對路徑
DATE_LOCAL:當地日期
DATE_GMT:GMT(Creenwich 標準時間) 日期
LAST_MODIFIED:包含此SSI 指令的檔案的最近修改日期
HTTP_USER_AGENT:瀏覽器名稱。
例如:main.shtml < html>
This document was last updated on < !--#echo var="LAST_MODIFIED"-->
< /html>
當您用瀏覽器開啟main.shtml 時可以看到最後修改時間。 ( 要注意的是,必須將main.shtml 儲存在OmniHTTPD 的HtDocs 目錄下,在瀏覽器中以位址http://localhost/main.shtml 存取。)
exec 指令
兩個參數是cgi 和cmd。前者呼叫一個可執行文件,如cgi="/cgi-bin/finger.cgi";後者呼叫一個系統指令,如cmd="ls"。可惜的是,OmniHTTPD 不支援此SSI 指令( 也許現在的最新版支援)。
config 指令
此命令設定伺服器處理文件和顯示日期的方法。它有兩個參數:
(1)timefmt,決定顯示日期的格式。在UNIX 中以man strftime 查詢可用的值。
(2)sizefmt,決定顯示檔案長度的格式。值為bytes 或addrev。這個指令在OmniHTTPD 也不支援。
fsize 指令
此命令顯示給定檔案的大小。參數是file,指定檔案的路徑及檔案名稱。
flastmod 指令
此命令顯示指定檔案的最近修改日期。參數是file,指定檔案的路徑及檔案名稱。
2、網關:透過WEB 連接其他協定
HTTP 協定無法存取Internet 的所有資源,要存取HTTP 協定以外的資源時( 例如POP3 和SMTP 收發電子郵件),就需要網關。 CGI 程式是實現網關的好方法。
在許多UNIX 的HTTP 伺服器中提供一些常用的網關,例如finger、wais、archie 等。但在OmniHTTPD 中,並沒有提供這些網關。但我們可以透過編寫CGI 程式來為OmniHTTPD 增加網關功能。
表單及其處理
HTML 表單是WEB 文件的一部分, 用於將使用者填寫的資訊提交給伺服器。 通常, 這些資訊傳遞給CGI 程序, CGI 程序依據輸入資訊進行一系列操作或資料加工, 再產生表示處理結果的HTML 文件傳回給客戶瀏覽器。
由此可見, CGI 程式的關鍵部分是得到輸入資料和產生HTML 文檔, 而操作和資料處理部分與大多數應用程式相同。 在這一講, 我將介紹如何在Perl 和Delphi 中得到資料及輸出HTML 文件。
首先, 我們建立一個名為greeting.html 的HTML 文件:
greeting.html 檔案( 儲存在OmniHTTPD 的HtDocs 目錄下)
< html>
< head>
< title> This is a greeting page! < /title>
< h1> Greeting < /h1>
< body>
< hr>
< form action="/cgi-bin/greeting.pl" method=POST>
< p> Your First Name: < input type=text name="firstname" size=60 maxlength=80> < /p>
< p> Your Last Name: < input type=text name="lastname" size=60 maxlength=80> < /p>
< hr>
< p> < input type=submit value="All OK!"> < input type=reset value="Clear All"> < /p>
< /form>
< /body>
< /html>
下面是Perl 的CGI 程式greeting.pl :
greeting.pl 檔案( 儲存在OmniHTTPD 的cgi-bin 目錄下) # Greeting You!
require "cgi-lib.pl";
# ===================================
# get input values
&ReadParse(*input);
$mFirstName = $input{'firstname'};
$mLastName = $input{'lastname'};
# ===================================
# do some Operations here
$mFullName = "$mFirstName $mLastName";
# ===================================
# create HTML document to output
PRint &PrintHeader;
print "< html>< head>< title> Greeting You! < /title>< /head> ";
print "< body> Hello, < i>$mFullName< /i> ! ";
print "< hr> by Greeting.pl < /body>< /html>";
# ===================================
# All done!
透過瀏覽http://localhost/greeting.html 測試CGI 程式。
在上面的Perl 程式中, 作為CGI 程序, 必須用require "cgi-lib.pl" 來引用cgi-lib.pl 文件, 此文件有許多用於CGI 編程的函數和過程。 require 相當於C 中的#include , 但要注意的是, require 語句後面必須有分號。
ReadParse 程序讀取HTML 表單提交的數據, 參數是一個陣列指標。 要注意的是, 在Perl 中, 函數和過程的呼叫要在前面加上& 符號。
mFirstName 、 mLastName 和mFullName 是變數。 在Perl 中, 變數名前要有$ 符號。
PrintHeader 函數實際上傳回值是"Content-type: text/html " , 它告訴瀏覽器下面的資料是HTML 文件。
產生HTML 文件部分很簡單, 就是用print 語句將HTML 文件的內容輸出就可以了。 怎麼樣, 會用Perl 寫CGI 程式了吧?
下面, 我們來寫一段Delphi 程式來完成相同的功能:
先關閉Delphi 中的所有項目, 選擇選單File/New , 在對話方塊中選擇Web Server application 類型, 使用CGI Stand-alone excutable 選項, 則出現一個新項目, 其主視窗名為WebModule1 。
在WebModule1 的Actions 屬性上雙滑鼠滑鼠, 出現Actions 屬性編輯視窗。 在視窗中新建一Action , 名為WebActionItem1 , 將其Default 屬性設為True ; 並在它的Events 中雙擊OnAction 事件, 添入下面的程式碼:
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
mFirstName, mLastName, mFullName: string;
HtmlDoc: string;
begin
// Get Input Values:
mFirstName := Request.ContentFields.Values['firstname'];
mLastName := Request.ContentFields.Values['lastname'];
// Do some operations here
mFullName := mFirstName + ' ' + mLastName;
// Create HTML document to output
HtmlDoc := '< html>< head>< title> Greeting You! < /title>< /head>';
HtmlDoc := HtmlDoc + '< body> Hello, < i>' + mFullName + '< /i> !';
HtmlDoc := HtmlDoc + '< hr> by Greeting.cgi < /body>< /html>';
Response.Content := HtmlDoc;
end;
將此工程的單元存為cgimain.pas , 將工程存為greeting.dpr 。 編譯( 用Ctrl+F9) 後, 將greeting.exe 複製到OmniHTTPD 的cgi-bin 目錄下, 並改名為greeting.cgi 。 同時, 將前面我們寫的greeting.html 做如下修改:
將< form action="/cgi-bin/greeting.pl" method=POST> 改成
< form action="/cgi-bin/greeting.cgi" method=POST>
這樣, 透過瀏覽http://localhost/greeting.html 就可以測試用Delphi 編寫的CGI 程式了。
從這個程式可以看出, 在Delphi 中CGI 程式一得到一個請求就會發生WebActionItem 的OnAction 事件。 在這個事件中, 資料輸入和HTML 文件產生是這樣做的:
透過Request.ContentFields.Values[HTML 表單元素名] 得到表單元素的值。
透過對Response.Content 賦值產生HTML 文件。
以下是Delphi 程式的三個檔案內容: ---------------------------------------- -------------------
greeting.dpr :
program greeting;
{$APPTYPE CONSOLE}
uses
HTTPApp,
CGIApp,
cgimain in 'cgimain.pas' {WebModule1: TWebModule};
{$E cgi}
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TWebModule1, WebModule1);
Application.Run;
end.
-------------------------------------------------- ---------
cgimain.pas :
unit cgimain;
interface
uses Windows, Messages, SysUtils, Classes, HTTPApp;
type
TWebModule1 = class(TWebModule)
procedure WebModule1WebActionItem1Action(Sender: TObject;Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
WebModule1: TWebModule1;
implementation
{$R *.DFM}
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
mFirstName, mLastName, mFullName: string;
HtmlDoc: string;
begin
// Get Input Values:
mFirstName := Request.ContentFields.Values['firstname'];
mLastName := Request.ContentFields.Values['lastname'];
// Do some operations here
mFullName := mFirstName + ' ' + mLastName;
// Create HTML document to output
HtmlDoc := '< html>< head>< title> Greeting You! < /title>< /head>';
HtmlDoc := HtmlDoc + '< body> Hello, < i>' + mFullName + '< /i> !';
HtmlDoc := HtmlDoc + '< hr> by Greeting.cgi < /body>< /html>';
Response.Content := HtmlDoc;
end;
end.
-------------------------------------------------- ---------
cgimain.dfm :
object WebModule1: TWebModule1
OldCreateOrder = False
Actions = <
item
Default = True
Name = 'WebActionItem1'
OnAction = WebModule1WebActionItem1Action
end>
Left = 192
Top = 107
Height = 150
Width = 215
end