12.6 怎样使用DELPHI编制CGI程序
DELPHI 3.0 虽然提供了编写CGI程序的向导程序,但并没有多大用处,应为CGI太象DOS程序,无法进行"可视"编程,一切均靠手动.
首先,DELPHI会建立工程文件 DPR 文件,在我们这个例子中,我们用CGI程序来判断FORM内的各元件传入的内容:
下面是CGI.DPR文件内容:
program Mil;
uses
sysUtils,
Pcgi in 'Pcgi.pas';
var
cgi:TCgi;
idx:integer;
ParameterName,ParameterValue:string;
begin
cgi:=TCgi.Create;
writeln('Content-type: text/html');
writeln;
writeln('<title>CGI Test Program</title>');
writeln('<body BACKGROUND="BACK.GIF">');
writeln('<h1>CGI Reply</h1>');
writeln('User Input String:'+cgi.ParamRawData+'<br>');
writeln('Parameter Count:'+IntToStr(cgi.Params.Count)+'<br>');
writeln('<HR>');
for idx:= 1 to cgi.Params.Count do
begin
ParameterName:=cgi.Params.Names[idx-1];
writeln(IntToStr(idx)+' Parameter Name = '+ParameterName+'<br>');
ParameterValue:=cgi.Params.values[ParameterName];
writeln(IntToStr(idx)+' Parameter Value = '+ParameterValue+'<br>');
writeln('<HR>');
end;
writeln('</body>');
cgi.Free;
end.
使用面向对象的编程使程序更加简洁,可以看出这个程序的第一步:
cgi:=TCgi.Create;
这个事件将产生各种初始化处理工作,生成各种我们需要的数据,即各种处理好的环境变量,紧接着,程序使用writeln 语句写入CGI输出的HTML文件头,最后输出详细内容:FORM中全部元件的内容。
当然上程序是不能单独编译的,必须带上程序的核心部分:PCGI.PAS 文件,下面是这个文件的程序清单:
unit Pcgi;
interface
uses
Windows,SysUtils,Classes;
const
DefaultBufferSize=4096;
type
TCgi = Class(TObject)
private
{Private Part Declare}
FInputRawData:String;
function ParamCount:Integer;
function GetToken(aString, SepChar: String; TokenNum: Byte):String;
function NumToken(aString, SepChar: String):integer;
function GetParamItemValue(inpStr:string;Cnt:integer):string;
function GetParamItemName(inpStr:string;Cnt:integer):string;
public
{Public Part Declare}
ContentLength:integer;
ContentType:string;
GatewayInterface:string;
HttpAccept:string;
HttpUserAgent:string;
Params:TStrings;
QueryString:string;
RemoteAddr:string;
RemoteHost:string;
RemoteUser:string;
RequestMethod:string;
ScriptName:string;
ServerName:string;
ServerProtocol:string;
ServerSoftware:string;
constructor Create;
destructor destroy ; override ;
function ParamRawData:string;
end;
implementation
constructor TCgi.Create;
var
buf
Char;
ContentLengthStr:string;
ret,idx:integer;
begin
inherited Create;
Params:=TStringList.Create;
// Get Server Variable
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('REQUEST_METHOD',Buf,DefaultBufferSize);
RequestMethod:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('CONTENT_LENGTH',Buf,DefaultBufferSize);
try
ContentLength:=StrToInt(StrPas(Buf));
except
ContentLength:=0;
end;
finally
freeMem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('SERVER_SOFTWARE',Buf,DefaultBufferSize);
ServerSoftware:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('SERVER_NAME',Buf,DefaultBufferSize);
ServerName:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('GATEWAY_INTERFACE',Buf,DefaultBufferSize);
GatewayInterface:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('SERVER_PROTOCOL',Buf,DefaultBufferSize);
ServerProtocol:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('HTTP_ACCEPT',Buf,DefaultBufferSize);
HttpAccept:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('SCRIPT_NAME',Buf,DefaultBufferSize);
ScriptName:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('REMOTE_ADDR',Buf,DefaultBufferSize);
RemoteAddr:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('REMOTE_HOST',Buf,DefaultBufferSize);
RemoteHost:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('REMOTE_USER',Buf,DefaultBufferSize);
RemoteUser:=StrPas(Buf);
finally
Freemem(Buf);
end;
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('CONTENT_TYPE',Buf,DefaultBufferSize);
ContentType:=StrPas(Buf);
finally
Freemem(Buf);
end;
if Uppercase(RequestMethod)='POST' then
read(FInputRawData)
else
begin
// Get Request Method
try
GetMem(Buf,DefaultBufferSize);
ret:=GetEnvironmentVariable('QUERY_STRING',Buf,DefaultBufferSize);
FInputRawData:=StrPas(Buf);
finally
Freemem(Buf);
end;
end;
for idx:= 1 to ParamCount do
Params.Add(GetParamItemName(FInputRawData,idx)+'='+GetParamItemValue(FInputRawData,idx));
end;
destructor TCgi.destroy;
begin
Params.Free;
inherited Destroy;
end;
function TCgi.ParamRawData:string;
begin
Result:=FInputRawData;
end;
function TCgi.GetToken(aString, SepChar: String; TokenNum: Byte):String;
var
Token : String;
StrLen : Byte;
TNum : Byte;
TEnd : Byte;
begin
StrLen := Length(aString);
TNum := 1;
TEnd := StrLen;
while ((TNum <= TokenNum) and (TEnd <> 0)) do
begin
TEnd := Pos(SepChar,aString);
if TEnd <> 0 then
begin
Token := Copy(aString,1,TEnd-1);
Delete(aString,1,TEnd);
Inc(TNum);
end
else
begin
Token := aString;
end;
end;
if TNum >= TokenNum then
begin
GetToken := Token;
end
else
begin
GetToken := '';
end;
end;
function TCgi.NumToken(aString, SepChar: String):integer;
{
parameters: aString : the complete string
SepChar : a single character used as separator
between the substrings
result : the number of substrings
}
var
RChar : Char;
StrLen : integer;
TNum : integer;
TEnd : integer;
begin
if SepChar = '#' then
begin
RChar := '*'
end
else
begin
RChar := '#'
end;
StrLen := Length(aString);
TNum := 0;
TEnd := StrLen;
while TEnd <> 0 do
begin
Inc(TNum);
TEnd := Pos(SepChar,aString);
if TEnd <> 0 then
begin
aString[TEnd] := RChar;
end;
end;
NumToken := TNum;
end;
function TCgi.GetParamItemName(inpStr:string;Cnt:integer):string;
var
tmpStr:string;
begin
tmpStr:= GetToken(inpStr,'&',Cnt);
result:=GetToken(tmpStr,'=',1);
end;
function TCgi.GetParamItemValue(inpStr:string;Cnt:integer):string;
var
idx:integer;
tmpStr,OutStr:string;
begin
tmpStr:= GetToken(inpStr,'&',Cnt);
tmpStr:= GetToken(tmpStr,'=',2);
idx:=1;
while (idx<=length(tmpStr)) do
begin
if tmpStr[idx]='%' then
begin
OutStr:=OutStr+ chr(StrToint('$'+Copy(tmpStr,idx+1,2)));
inc(idx,3);
end
else
begin
if tmpStr[idx]='+' then
OutStr:=OutStr+chr(32)
else
OutStr:=OutStr+tmpStr[idx];
inc(idx);
end
end;
result:=OutStr;
end;
function Tcgi.ParamCount:Integer;
begin
Result:=NumToken(FInputRawData,'&');
end;
end.
12.7 使用实例
我们就以前面提到的这个简单的例子来说明吧!
例: 建立一个站点,其中需要用户输入用户名称和密码已确认是否是会员,如果是会员,就显示"欢迎进入"的页面,否则显示"谢谢使用,请先注册"。为了说明问题,这里的会员数据库部分暂时省略,假使只有个用户LYP,密码是abcd.
第一步:编写CGI程序,将 CGI.DPR 改成以下内容:
program Mil;
uses
sysUtils,
Pcgi in 'Pcgi.pas';
var
cgi:TCgi;
idx:integer;
ParameterName,ParameterValue:string;
begin
cgi:=TCgi.Create;
writeln('Content-type: text/html');
writeln;
writeln('<title>CGI Test Program</title>');
writeln('<HR>');
if ((cgi.Params.values[cgi.Params.Names[0]]='lyp') and
(cgi.Params.values[cgi.Params.Names[1]]='abcd')) then
writeln('欢迎进入!')
else
writeln('谢谢使用,请先注册!');
writeln('<HR>');
writeln('User Input String:'+cgi.ParamRawData+'<br>');
writeln('Parameter Count:'+IntToStr(cgi.Params.Count)+'<br>');
for idx:= 1 to cgi.Params.Count do
begin
ParameterName:=cgi.Params.Names[idx-1];
writeln(IntToStr(idx)+' Parameter Name = '+ParameterName+'<br>');
ParameterValue:=cgi.Params.values[ParameterName];
writeln(IntToStr(idx)+' Parameter Value = '+ParameterValue+'<br>');
writeln('<HR>');
end;
writeln('</body>');
cgi.Free;
end.
上面这个程序和PCGI.PAS一块编译可以得到CGI.EXE这个文件,将这个文件拷入WWW服务器的CGI-BIN目录下.
第二步:建立HTML
建立一个内容如下的HTML: (目录为:HTTP://202.196.64.240/a/index.htm )
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=gb_2312-80">
<meta name="GENERATOR" content="Microsoft FrontPage 2.0">
<title>CGI实例</title>
</head>
<body>
<p align="center"><font color="#400040" size="7"
face="楷体_GB2312">CGI实例</font></p>
<form action="http://202.196.64.240/cgi-bin/cgi.exe"
method="POST">
<p align="left"><font color="#400040">请输入用户名:<input
type="text" size="20" name="T1"></font></p>
<p align="left"><font color="#400040">请输入口令 : <input
type="password" size="20" name="T2"></font></p>
<p align="left"><font color="#400040"><input type="submit"
name="B1" value="Submit"></font></p>
</form>
<p align="center"><font color="#400040"></font> </p>
</body>
</html>
文中的 <form action="http://202.196.64.240/cgi-bin/cgi.exe"一句中为CGI程序所处的位置,读者可以自行改变.
第三步:运行、试验
首先,我们使用浏览器调入该HTML页面,如图12-7-1
图12-7-1
此时输入正确的用户名和口令,得到图12-7-2:
图12-7-2
如果输出其他的用户名和口令,得到图12-7-3:
图12-7-3
为了方便大家研究,我们还特地留有元件的状态值显示。