Site hosted by Angelfire.com: Build your free website today!

Easy CGI 1.0

Documentation for the Units CgiUtil, HtmlUtil and the Sample Application Guestbook


Contents:


Introduction

Easy CGI is a package of Delphi 2 units and sample programs to support the creation of dynamic Internet/Internet applications using CGI, a standard for external gateway programs to interface with information servers such as HTTP servers (for details refer to NCSA). Web applications created with Delphi and this toolbox are extremely fast and easy to handle.

The Easy CGI package contains 2 units (CgiUtil and HTMLUtil) and a sample application for a guest book using different methods to access data that demonstrates how to

Back to index


Unit CgiUtil

This unit provides a powerful class to make the CGI communication with a web server as easy and fast as possible. Access the fieldnames, field values and parameters sent by the web server simply and comfortable as arrays/stringlists with a minimum of programming overhead. You don't have to care for handling different communication methods like GET or POST, conversion of special characters and translation of logical to physical path names.

Usually a CGI program communicates with the web server via standard input/output. You may use the variable InputFName to "redirect" input reading from a file. Default: Empty for Standard-I/O.

The unit CgiUtil provides a class TCGIInput containing a set of properties and methods to access the information sent by the web server.

Property Name Type Description
CGIInputStr string a string in the form 'fieldname1=fieldvalue1&fieldname3=fieldvalue2...'
count integer number of fields in the CGIInputString
FieldNames[index : integer] string fieldnames accessible as array in the range of 0..count-1
FieldList TStringList fieldnames accessible as stringlist
FieldValues TStringList fieldvalues accessible as stringlist

Refer to the form example to see how to use these methods and properties.

To parse and filter field contents the following functions / procedures are available:

Function / procedure name Returns Description
ParseField(const FieldName : String) string Returns value of field referenced by FieldName=...&...
Special chars (e.g. '+' for a blank and '%[hexcode]' are converted
FilterFields

-

Removes HTML-comments, Script-Tags and SSI-Tags from CGIInputStr to prevent hackers from including commands like <!--#exec cmd="format c:" -->

 

Additionally TCGIInput supports some basic database functions:

Function / procedure name Returns Description
OpenDatabase(const DatabaseName : String) - try to open database; at first the name is assigned to a dabase file, afterwards ResetDatabase is called
ResetDatabase - try to get access to database; if locked then retry for 20 seconds; if still locked it will raise exception ENoDBAccess; a name must already be assigned to (global text file) TF (e.g. via OpenDatabase)
ReadFromDatabase - reads a line from a database and interpretes this as a CGI input string e.g. setting FieldNames, FieldValues etc.
AppendDatabase(const DatabaseName : String) - Simply append record to database without existance-check of keyfields; currently no retry function implemented (if file is locked by other process); more sophisticated: see AddToDatabase
AddToDatabase(const DatabaseName : String; const KeyFields : array of string) integer add record (CGIInputStr) to database; if another record with same keyfields already exists, it will be removed and the new record will be appended. returns:
0 if record was simply appended,
1 if record replaced an existing one,
2 if an error occured
CloseDatabase - Closes database
parseDatabase(const DatabaseName : String; const KeyFields : array of string) boolean scans database for the first occurence of a record with the given keyfields; if found, record will be returned in CGIInputStr and result is TRUE otherwise result is set to FALSE
EOFDataBase boolean indicates that end of database is reached

 

Additional information from the calling server is provided via environment variables. The contents of the most important environment variables is stored in the following string vars:

Var Name / Const Name Description
ScriptName Name of Script (for self references)
ScriptTranslated Physical name of Script (ParamStr(0))
PathInfo Contents of the environment variable PATH_INFO
PathTranslated Contents of the environment variable PATH_TRANSLATED
or retrieved from an ini-file (Netscape C.Server gives no PATH_TRANSLATED)
HTTPReferer Contents of the environment variable HTTP_REFERER
RequestMethod Contents of the env. var. REQUEST_METHOD (GET or POST)
QueryString Contents of the env. var. QUERY_STRING
RemoteAddr IP address of remote user
RequestMethodRequired : boolean = True (default); disable method check e.g. for debugging if set to False
YesNoStr : array [False..True] of string[4] = ('No','Yes'); will be set at initialization to 'Nein', 'Ja', if language of operating system is german
TrueOptionStr = 'TRUE WAHR YES JA'; strings representing boolean True
FalseOptionStr = 'FALSE FALSCH NO NEIN'; strings representing boolean False

Additional environment vars can be retrieved using the function GetEnvStr (see below). More details about environment vars set by the calling server may be found at NCSA.

The following exceptions will be raised:

Exception name Description
ENoDBAccess DB is locked too long
EUnknownRequestMethod exception raised when REQUEST_METHOD < > GET or POST

 

Some utility functions are available too:

Function / procedure name Returns Description
GetEnvStr(const Key : ShortString) ShortString returns an environment string referenced by Key
ConvertToFieldValue(const S : string) String replaces FieldSeparators, AssignOperators ('&' and '='), '+' and CrLf with special characters ('%' + hexcode)

 

Example how to use the class TCGIInput

Here is a simple form:

Name:

Gender: male female

Operating system:

This is the HTML code for the form:

<form action="[insert your cgi program name here!]" method="POST">

  <p>Name: <input type="text" size="40" name="Name" value="Your name"></p>
  <
p>Gender: <input type="radio" checked name="gender" value="male">male
             <
input type="radio" name="gender" value="female">female</p>
  <
p>Operating system: <select name="system" size="1">
       <
option selected>Windows 95</option>
       <
option>Windows NT</option>
       <
option>OS/2</option>
       <
option>Mac OS</option>
       <
option>Other</option>
     <
/select></p>

     <input type="hidden" name="HiddenField" value="Hidden value">

  <p><input type="submit" name="SubmitBtn" value=" Submit ">
     <
input type="reset" name="ResetBtn" value=" Reset "></p>

</form>

Here are some examples how you can access the contents of the form within your CGI program using methods and properties of the class TCGIInput:

CGIInputStr will be set to 'Name=Your+name&gender=male&system=Windows+95&HiddenField=Hidden+value', the string that was posted from the server to your program.

Count will be set to 4, the number of fields in your form (there is also one hidden field!).

FieldNames[0] will be set to 'Name', FieldNames[1] will be set to 'gender' etc., the names of the fields in your form.

FieldValues.strings[0] will be set to 'Your name', FieldValues.strings[2] will be set to 'Windows 95' etc., the values of the fields entered in the form by the user.

ParseField('Name') will return 'Your name'.

Back to index


Unit HtmlUtil

This unit contains a set of functions to support the creation of dynamic web pages. You will find functions to create basic HTML prologues as well as advanced functions for dynamic tables and forms. A very powerful function is included to merge predefined HTML template pages with data retrieved online by your application - a comfortable way to get nice looking dynamic, interactive pages with a minimum of programming. Details about HTML (HyperText Markup Language) can be found at NCSA.

Generally everything that is written from your CGI-program to standard output will be sent from the server to the user as dynamically created HTML-page. One option of the unit HtmlUtil is to write the ouptut in a temporary file first and send the whole bunch of information in one go, when the program ends. The advantage is that the user will still see the previous page and an hour glass as cursor - he does not have to wait in front of an empty page with a standard cursor thinking that the server has already died meanwhile. The third option is to create or modify a file and hand over a link in the returned CGI-header that the server will recognize. Al these options are controlled via the variables OutputF, OutputFName and LocationName. See the unit interfaces and the demo application for details.

HtmlUtil will support creating HTML pages real-time using the following basic output procedures:

Basic Output Procedures Description
SendPrologue send a CGI prologue. Format and the way, how output will be handled depends on the global variables OutputFName and LocationName. Must be sent before any other text.
SendPageHeader(const Title : String; Refresh : integer) Sends several tags that define the header of a page including the title.
Refresh >= 0: Page will be reloaded in ... seconds;
Refresh = -1: Page does not change, can be reloaded from cache later;
Refresh < -1: Page must be reloaded every time, when called
SendPageFooter This will send several HTML tags to close a page
ShowMessage(const s:string) Sends a text line
ShowError(const s:string) Sends an error message 'Error: ...'
SendHREF(const RefLink,RefTxt : string) inserts a link


Table creation is simple using the the following
table procedures:

Table Procedures Description
StartTable(const TableCaption : string; BorderWidth : integer; Header : array of string) Open a new table giving a certain caption (can be left blank), borderwidth and a headline
ShowTableRow(const CS: array of string) Add a row to that table, fields are handed over as an array of strings (number of fields may change from row to row)
EndTable Close a table


Forms can be easily defined using the following
form procedures:

Form Procedures Description
SendFormHeader(const Method : string) open a form, parameter is the action-method (name of the CGI script to be executed plus path_info and parameters)
SendFormFooter(const SubmitStr, ResetStr : string) close a form with submit button and optional reset button (if ResetStr <> '')
SendFormSelectStart(const SelectLabel, SelectName : string) open an input field for a selection list
SendFormOption(const Option : string) send an option of a form-selection list
SendFormSelectEnd close a selection list
SendHiddenField(const Name,value : string) send a hidden field to pass invisible information to the CGI script


You can save a lot of programming if you already predefine the layout of your dynamic page using HTML templates created with a HTML editor and insert dynamically the actual information with your CGI program:

Template Procedures Description
CopyTemplate_L(const FileName : string; FromMarker, ToMarker : string; SearchStr, ReplStr : TStringList) copy a file with given Filename from FromMarker to ToMarker to OutputF and replace all occurences of SearchStr (StringList!) by ReplStr (StringList of same length); search is not case-sensitive, markers will not be copied.
CopyTemplate_A(const FileName : string; const FromMarker, ToMarker : string; const SearchStr, ReplStr : array of AnsiString) copy a file with given Filename from FromMarker to ToMarker to OutputF and replace all occurences of SearchStr (open array!) by ReplStr (open array of same dimension); search is not case-sensitive, markers will not be copied.
ScanForFieldnames(const FileName : string; FromMarker, ToMarker : string; Delimiter : char; var FieldList : TStringList) scan a file from FromMarker to ToMarker for strings enclosed in the given delimeter (e.g. '%'). These strings will be returned as Stringlist in FieldList.

Refer to the sample guestbook application that makes excessive use of templates.

Back to index


Sample Application Guestbook

The guest book sample program makes excessive use of the units CgiUtil and HtmlUtil; it can be compiled in three different ways:

The guest book application also shows how to merge data into predefined HTML template pages to minimize programming overhead and to improve the layout of dynamically created pages.

To control the method, how the CGI program will handle the database you can use two conditional defines for the compiler:

{$DEFINE UseBDE} will activate the usage of the Borland Database Engine instead of internal database procedures of the unit CGIUtil. Application code size grows significantly and requests delay due to a big overhead for initializing database access. This method will be prefered, if you have to handle huge databases or complex queries comfortable with the powerful BDE. The compiler will include an additional unit GBDBUtil that contains the code controlling the BDE.

{$DEFINE UseXL} will activate the usage of MS-Excel via OLE automation instead of internal database procedures of unit CGIUtil. The codesize of the CGI application is kept small and delays happen only the first time, when Excel and the database table is loaded. This is also a powerful way to create more sophisticated 3 Tier web applications that use transactions with several consequtive screens. The compiler will include an additional unit GBXLUtil that contains code to control OLE automated communication with MS Excel. Handling of the database table happens inside Excel.

Don't activate both conditional defines or you will end up with a compiler error.

If none of the conditional defines is set, the guestbook application will use the internal database procedures of unit CGIUtil. Code size is kept very small, you will recognize nearly no delay.

Installation of the Sample Guestbook

The sample guestbook application requires that you have access to a web server that supports the HTTP protocol and CGI scripts, but this is true for nearly every server on the market. You must have the permission to store executable files in the servers script directories. In the following steps the default directory structure is described.

1. Below your WWW-Root directory you should create a direcory 'GuestBk' with the following files:

[WWW-Root]
    |
    +---[GuestBk]
            |
            +---- register.htm  (the start page of your guestbook)
                  guestlst.htm  (a template for listing guestbook entries)
                  guestrcp.htm  (a receipt confirmation template)
                  graustr1.jpg  (a background image)

2. Below your scripts directory you should create a directory 'GuestBk' with the following files:

[Scripts]
    |
    +---[GuestBk]
            |
            +--- guestbk.exe    (the CGI program for the guestbook application)
                 guestbk.dat    (a guestbook database file)
                 guestbk.dbf    (another guestbook database file in dBase format)

Thats it!

If you do not store the files in the default directory structure you will have to update the HTML files. E.g. if you use a directory 'forms' instead of 'GuestBk' and your scripts are stored in a directory called 'cgi-bin' without any subfolders, an entry for the action method of a form would look like

<form action="/cgi-bin/guestbk.exe/forms?VIEW" method="POST">
              ==================== ===== ====
                       |             |     |
                  pathname of     path to  command passed to CGI program
                  CGI program    templates

instead of

<form action="/scripts/guestbk/guestbk.exe/guestbk?VIEW" method="POST">

The program GuestBk supports three commands:

ADD      Add a new data record to the guestbook
VIEW   View the guestbook
SHUTDOWN   With the 3 tier client/server version of the guestbook using Excel via OLE automation as database server, you can initiate a remote shutdown of Excel with this command
TEST   The CGI program will return a lot of useful information, e.g. a set of environment variables

You can call the program directly from your web browser e.g. by entering in your browser's address field:

http://127.0.0.1/scripts/guestbk/guestbk.exe?TEST

Back to index


Copyright © 1997 H.Hackbarth. All rights reserved.
Information in this document is subject to change without notice. Other products and companies mentioned are registered trademarks of the related licence owners.
Last updated: 15.01.97