This page deals with CGI programming in Perl. If you don't know
Perl, you would be best to go to the tutorial
on this site, or find another tutorial, so you know the basics of Perl
programming.

In order to run scripts you will need a web server running on
your computer. The following information explains how to configure a web server
and Perl on a Win32 computer in order to run CGI scripts. If you want
information on setting up the same things on Unix/Linux there is a lot of
information on the web, so I haven't written my own page about it.

This is a tutorial about how to run Perl CGI scripts with the Apache server
on Win95/98. Remember our purpose is to install and configure these so the
Windows environment mimics that of the Unix/Linux host computer, which is where
your web pages are hosted; this way we won't have to re-edit scripts when we
upload them.

If your version of Windows 95 doesn't have a little "a" after its
version number (go to Control Panel/System/General; you'll see your
version number under System; something like 4.00.950a), you will
have to include Perl's .exe extension in your shebang line:

!#/usr/local/bin/perl.exe
^^^

This little "a" is the result of having installed MS's Server Pack
1, a free download (if you can find it).

Click the following link to download
ActivePerl. Be sure to read this page's contents, since Win95 users will
have to download DCOM for Windows 95.

Double-click on the APi51?e.exe file. When you get to the part where you
choose an install directory, make sure it's the same as the Perl location on
your host site. For example, if Perl is located in /usr/bin/,
create a directory c:\usr and install ActivePerl into that (it
will create its own /bin directory). Your directory structure
should look like this when you're done:

Note that Perl differs from ActivePerl in that it makes /site a
subdirectory of /lib (Perl's root library).

When it asks you which elements you want installed, you should be aware
that mod_asp supplies PerlScript support to Apache (Thanks to Jerrad Pierce
for bringing me up to date on this). So select Perl for ISAPI
and PerlScript, if you're going to be working with these
things.

Next, choose to add perl.exe to your path, but don't associate .pl files
with perl.exe. Unlike WinNT, you can't run Perl scripts in Win95/98 by
double-clicking them; you have to open a command prompt window.

That should be it. When ActivePerl is done installing, reboot your
computer.

Here are two tests:

Open your command prompt window (C:\WINDOWS\COMMAND.COM),
type perl -v and hit Return. You should get a
message saying This is Perl..., etc..

Create the following script in a text editor like Textpad or Notepad:

#!/usr/bin/perl -w
print "Hello world, it works!\n";

Save it somewhere, like c:\tmp\test.pl. Now open the command
prompt window and type:

perl c:\tmp\test.pl

Hit the Return key. The message Hello world, it works!
should be printed on your screen.

The latest Apache Win32 binary is available from the
following directory: http://www.apache.org/dist/.
It's a typical self-installing .exe, but you might want to change the directory
it installs itself into to one that doesn't have spaces: c:\apache
would be fine. Be sure it is on the same hard drive as Perl. With Windows 95 you
may also need to download Winsock 2 from Microsoft.

For the following changes, we'll assume your base path on the Unix/Linux host
is:/usr/etc/htdocs/your_site
Therefore, you want to create this same directory structure on your PC. So make
a directory called c:/usr/etc/htdocs/your_site and install your web
pages there; thus c:/usr/etc/htdocs/your_site/index.html would be
the document that is called when someone hits http://www.your_site.com.

Open Apache's configuration file: c:\apache\conf\httpd.conf in a
plain text editor. The following instructions are for Apache 1.3.6; line numbers
may change with later versions.

That's it. Double-click on the apache.exe binary and a command prompt window
should open up and stay up. (You may get a message saying something like [Sun
Jul 04 15:50:18 1999] [warn] pid file c:/apache2/logs/httpd.pid overwritten --
Unclean shutdown of previous Apache run?; this is a known annoyance and
doesn't affect the running of Apache). Open your browser, write "localhost"
in the GoTo window, cross your fingers, hit Return, and your
homepage (the index.html page in whatever directory you assigned DocumentRoot
to) should be displayed.

And it's just that easy! Restart Apache and you can run through all your and
your clients' pages with the same addresses that you use when you're on-line.
For more info and cool stuff to play with, check the docs: C:\apache\htdocs\manual\vhosts.

Important note: You'll
have to rename the hosts file (to hosts.sam, for
example) when you go on-line, because the 127 series IP numbers will confuse
your browser. There are two little Perl scripts, one to rename hosts
to hosts.sam (for when you go on-line and want to see the versions
of your pages that are on the host server) and another to do the reverse (when
you want to run your pages off-line). Then there are two little .bat files that
call the scripts from your desktop or wherever.

CGI Programming

Environmental Variables

Every time you run a CGI, your web server sends a
whole host of variables to it. These detail information about your site and your
server, and also the visitor who is using the CGI. Here is a complete list of
those variables:

Variable

Data

DOCUMENT_ROOT

The root directory of the web server

HTTP_COOKIE

The visitor's cookie, if one is set

HTTP_HOST

The name of your server

HTTP_REFERER

The page that called the script

HTTP_USER_AGENT

The browser the visitor is using

HTTPS

Set "on" if it is called through a secure server

PATH

The system path your server is running on

QUERY_STRING

See the GET method of receiving data below

REMOTE_ADDR

The visitors IP address

REMOTE_HOST

The hostname of the visitor

REMOTE_PORT

The port on your web server the visitor is connected to

REMOTE_USER

The visitors username

REQUEST_METHOD

GET or POST - see below

REQUEST URI

The interpreted pathname of the requested document or CGI

SCRIPT_FILENAME

The full path name of the CGI

SCRIPT_NAME

The interpreted pathname of the CGI

SERVER_ADMIN

The email address of the webmaster

SERVER_NAME

Your domain name

SERVER_PORT

The port the server is set to

SERVER_SOFTWARE

Your server type eg. Apache 1.3.11

Depending on the server you are using, you might receive other environmental
variables as well. You will not necessarily receive every variable with every
CGI either.

These variables are sent to each CGI in a hash called %ENV.

To print out the visitors IP address you would write :

print "IP Address = $ENV{'REMOTE_ADDR'}\n";

Here is my version of a completely working CGI that prints out all the
variables in alphabetical order for the visitor in HTML. Call this env.pl (or
env.cgi if you are using UNIX - but remember to take this name into
account when we use this code below.) and place it in your cgi-bin.

#!/perl/bin/perl#Remember : this path will vary depending on where Perl is located

If you need to debug a script (eg you get ERROR 500) the best way to do that
is to run the script from the prompt rather than in the browser. Some things
won't work like that of course, but it will still give you a good idea of where
the problem is. The other thing I often do is comment out the lines I think are
problematic and see if it works then. Keep doing this until you find the
troublesome code.

The GET method

There are two ways to get data from an HTML page to your CGI -
the GET and POST methods. With the GET method, values are actually sent as part
of the URL to the CGI. This method is really only used if you have a small
amount of data to pass. Many databases and search engines use this method.

You can see the data being sent - everything after the ? in
the URL, plus it is saved in the environmental variable QUERY_STRING.

Create the following web page (eg copy and paste this code) -
or make one similar if you see how it works :

<html>

<head>

<title>

GET Method Demo</title>

</head>

<body>

<form action=

"http://localhost/cgi-bin/env.pl"
method="GET">

Enter your name :&nbsp;

<p>

<input
type="text"
name="Name"

size=

30>

</p>

<p>

Enter your address :

<p>

<input type=

"text"
name="Address"
size="30"><p>

<input type=

"submit"
value="Submit"
name="B1">

</form>

</body>

</html>

Obviously the form action should point to the env.pl
CGI you just created, so you may need to change the path.

When you enter data and press submit, the env.pl CGI
will be called. Have a look at the QUERY_STRING variable - it should contain the
values you enter - amongst quite a bit of confusing information.

I entered Dane and New Zealand into the text boxes and
received:

Name=Dane&Address=New+Zealand&B1=Submit

Basically, all words are separated by +'s and all fields are separated by
&'s. Other none alphanumeric characters will also look strange, but don't
worry about that yet.

Obviously you are going to want to convert this data, and this is one of the
reasons you use Perl for CGI scripting. Perl is a very powerful string
manipulation language.

Here is my rewriting of the env.pl script so that it prints out the
string on the first line, and then the field names followed by their values on
each successive line:

Note that you must test for Internet Explorer first, because it also has
Mozilla in its description.

This is really all there is to simply using the GET method, and utilizing
environmental variables.

The POST Method

You will usually want to use the POST method, rather than the GET method, in
order to send the results of a form to a CGI. The POST method is ideal for all
situations where you need to send more than a few words, or where the
information needs to be semi-secure.

With the POST method all alphanumeric characters are sent as themselves.
Aside from this, spaces are represented by +'s, and all other characters are
represented by something like %23 - this is a percent sign followed by two hexadecimal
numbers representing the ASCII position of the character. Don't worry about this
too much, there are standard methods you can use to parse data. Perl is also a
very easy language for doing substitutions in.

Try making a ,ore complex form than in the previous section :

<html>

<head>

<title>

The Post Method</title>

</head>

<body>

<form action=

"http://localhost/cgi-bin/post.pl"
method="POST">

Enter your name :&nbsp;

<p>

<input
type="text"
name="Name"

size=

30>

</p>

<p>

Enter your address :

<p>

<input type=

"text"
name="Address"
size="30"><p>

Enter Email :

<p>

<input type=

"text"
name="email"
size="30"><p>

Enter Phone Number:

<p>

<input type=

"text"
name="phone"
size="30"><p>

<input type=

"submit"
value="Submit"
name="B1">

</form>

</body>

</html>

The only thing that has really changed is that the method has been changed
from GET to POST.

Now create a CGI to accept the values and print them out. Mine is called
post.pl:

Notice that we read from standard input. We store the data in a variable
(called $line) here, which is $ENV{'CONTENT_LENGTH'} long
(remember, this was an environmental variable).

You may also want to change + signs into spaces before you print the data
out. I did that with this line :

$data =~ tr/+/ /;

You will also want to get convert all the non-alphanumeric characters into
their ASCII values - at the moment they will look like %26. To do that
use this line:

$data =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

You can either accept this because it works, or work out why it works - it
isn't all that difficult.

Instead of printing to the screen, you could also store the values in a hash
table like this:

$FORM{$varname} = $data;

Once they are in a hash, you can print them out like this:

foreach $key (keys(%FORM)) {
print "$key = $FORM{$key} <p>";
}

This code can be reused over and over again to handle forms of any length.

More Advanced Forms

The forms in the previous section work, but they do not have
the error checking necessary for real world CGI's. For instance, you might want
to specify that some fields be filled in while others can be left blank. In
fact, the CGI's in the previous section happily accept forms with nothing in
them.

For instance, we could program the CGI to do something if a
field equals one thing, otherwise do something else. Given the example in the
previous section I could put this in the CGI:

Now if I enter my name (Dane) it says "I'm glad to see you",
otherwise it says "Go away". Although this is a silly example, it is
easy to see from this how some interesting CGI's could be written that test for
important conditions.

This information is mainly of relevance if you are programming CGI on
Windows95/98.

It isn't particularly difficult to let users on your web page query a
database, and then have the results printed out in HTML format. As long as you
have a version of Perl that includes the Win32::ODBC library (the Active State
version includes it), and as long as you have ODBC in your Control Panel folder
(which you almost certainly have if you have any Microsoft products), then this
information is relevant.

The first thing you need to do is create a database. I used Access for this,
but, as you will see, you can build the database in anything that supports
ODBC.

For this I am using the Nwind.mdb database that comes with my version of
Access. It contains quite a number of tables, but this initial demonstration
only uses the table called Customers. This is what it looks like in
design view:

FIELD NAME

DATA TYPE

CustomerID

Text

CompanyName

Text

ContactName

Text

ContactTitle

Text

Address

Text

City

Text

Region

Text

PostalCode

Text

Country

Text

Phone

Text

Fax

Text

If you don't have a ready made version you can make this and enter data in
it, or you can use a database you already have.

The next thing you need to do is open ODBC in your Control Panel.
Click on the type of database you are using eg Microsoft Access Driver(*.mbd).
Give it a data source name eg. customer_data. Now press select and
find the database. Once you select the database this process is complete. You
can now access that database from within a program that supports ODBC by using
ODBC commands. This saves you the trouble of needing to know all the different
commands for all the different databases out there.

Now you need to create the HTML form that the user can enter their search
criteria into. This is my version:

38: print "<p>THIS IS THE END OF THE RECORDS<p>";
39: $db->Close();
40: print "</body></html>\n";

The first 18 lines are very familiar except for line 3 - use Win32::ODBC; This
tells the interpreter we want to use this library in our script. The rest of the
first 18 lines just get the user input and place it in a hash table - the same
as we have done in several other scripts.

In lines 19-22 we connect to the database. A string called $DSN is set
to the name we gave the database to the ODBC contoller. The database is
opened with the command:

$db=new Win32::ODBC($DSN)

but this has been written so that if the database is not successfully opened
an error message is given.

Then in line 24 we give an SQL command to get all the data from the table
called Customers:

$db->Sql("SELECT * FROM Customers");

Next we set up a loop to read the data from the SQL command one row at a
time.

while ($db->FetchRow()){

my(%data) = $db->DataHash();

You need to use two commands - one to fetch the data and another to put the
data in a hash.

Still inside the while loop, we print the data out in HTML format.
Firstly, if the name given matches a name in the ContactName field of the
database, it is printed out, along with the company name of that person.
(Actually, the data supplied by the user is in wildcard form - Th is
enough inforamtion to match the names Thomas and Thompson).

Writing data straight to a text file is easier than using a database. Here is
the HTML form the user will enter data into (it is exactly the same as the one
above:

<html>

<head>

<title>

This writes information to
a file</title>

</head>

<body>

<p><b>

Enter details below:</b></p>

<form action=

"/cgi-bin/fileop.pl"
method="POST">

<p><b>

Name :</b></p>

<p><input type=

"text"
name="name"
size="20"></p>

<p><b>

Position:</b></p>

<p><input type=

"text"
name="position"
size="20"></p>

<p><input type=

"submit"
value="Submit"
name="B1"></p>

</form>

<p>

&nbsp;</p>

</body>

</html>

The only change is that we are now calling a CGI form called fileop.pl.
This CGI collects the data the user enters, opens a text file for appending, and
writes each users entry on a newline in the following format:

name | position

This is called a flat database - the divider can be any character that won't
be included in the input data.

I have called my filehandle FP for filepointer, but you can use any
name. Next we open a file called results.txt which is in the CGI
directory (you can put it where you want, but give a full pathname). The >>
means open for appending. > would mean open for writing, while
just giving the filename means open for reading. Create an empty text file
called results.txt before you run this.

Next we print the information we want with print, but we give it the
filehandle as its first parameter. Then we can write whatever we want to the
file.

When you are finished close the file.

A potential problem arises if two people try to access the file at once. On
Unix you can lock the file with flock so that only one person can use it
at once. I am not sure what approach can be used with Windows.

It is easy to see how you can also make a web counter with this approach.
This is the same CGI as above, but it also opens a second file called counter.txt
(initially created with 0 on the first line), increments it by one,
and prints out the value:

print "<html><head><title>Writing to File</title></head>";
print "<body>\n";
print "<h2>Your Results have been written to file.</h2>\n";
print "<p>Thank You for your time.<p>";

open(FP2, "counter.txt");
$num = <FP2>;
close(FP2);

$num++;

open(FP3, ">counter.txt");
print FP3 "$num";
close(FP3);

print "<p>You are visitor number $num<p>";

print "</body></html>\n";

I have opened and read the data with:

open(FP2, "counter.txt");
$num = <FP2>;
close(FP2);

using $num reads one line. If I wanted to read more than one line, I
would use something like:

@data = <FP2>;

This would store each new line at a different index in the array.

After incrementing the value of $num, I write it back to the file.
This time I want to overwrite the previous value rather than append to it, so I
use a single >.

open(FP3, ">counter.txt");
print FP3 "$num";
close(FP3);

I then print out what number visitor you were. I find working with files one
of the easiest things with Perl, there is very little that can go wrong.

Setting up Server Side Includes

Server side includes allow you to do a variety of things by putting simple
one line tages into HTML code. These files are then saved as .shtml files so
that the server knows to scan the file for server side includes.

These are six different types of SSI, but before you can use any of them you
need to configure your server so that you can use them.

To configure the Apache server on a Win32 machine do the following (some of
these things may have been done by default):

Open httpd.conf in notepad (or some other text editor - just make sure
the editor has a Find facility so you can quickly find the code that
needs changing).

Uncomment these two lines:

AddType text/html .shtml
AddHandler server-parsed .shtml

Find the line that says something like:

Options Indexes FollowSymLinks Multiviews

and change it to

Options Indexes FollowSymLinks Includes

This is all I needed to do to my httpd.conf file.

Using Server Side Includes

There are six commands available to you:

1. Include : allows you to have another file (e.g. .txt, .html)
embedded in a .shtml file).

2. Echo : allows you to display environmental variables in the .shtml
page.

3. Exec : executes a Unix command or CGI script.

4. Fsize : returns the size of a file.

5. Flastmod : returns the date the file was last modified.

6. Confid : used to control things like the format of output.

I find that the Include and Exec are the most useful commands.

There are many uses for include. For instance, suppose each page on your site
must include a disclaimer. You could write this into each page, but then if you
wanted to change the disclaimer you would have to change each page. A far easier
way to do this would be to have the disclaimer in a separate file (either .txt
or .html), and then just include it in each page.

Supposing the file was called disclaimer.txt, and supposing it was in
the same directory as the .shtml file, you would embed it like this.

<!--#include file="disclaimer.txt"-->

Of course the file doesn't have to be in the same directory, but this
approach takes the directory the .shtml file in to be the root directory, so it
can't be in a directory higher in the hierarchy than the .shtml file's
directory.

It is possible to give the file address relative to the root directory with
the virtual keyword:

<!--#include virtual="c:\apache\disclaimer.txt"-->

I have found lots of good uses for Include. For instance, you might
want to keep Guest book comment in a .txt file, and then just include them in a
page displaying the Guest book.

The Exec option is very useful for calling CGI scripts. For instance,
here is a simple CGI that counts the visitors to a site :

#!/perl/bin/perl

open(FP, "counter.txt");
$num = <FP>;
close(FP);

$num++;

open(FP, ">counter.txt");
print FP "$num";
close(FP);

Obviously every time this CGI is called the number in the file counter.txt
is incremented by one. Since we don't actually want to display the CGI
results to the user, we can just call it from a .shtml page. The user isn't even
aware that the CGI is being called. Here is the tag to put in the .shtml page:

<!--#exec cgi="/cgi-bin/counter.pl"-->

Echo allows you to print out a whole assortment of Environmental
Variables on the .shtml page. Foe instance, to print out the local time every time
the page is loaded by a user, you would use the tag:

<!--#echo var="DATE_LOCAL"-->

Just change the variable name to suit. For instance:

<!--#echo var="HTTP_USER_AGENT"-->

This prints out the users browser.

Use Fsize to print out the size of a file. For instance

<!--#fsize virtual="comments.shtml"-->

This displays the size of the comments.shtml file that this tag is
embedded in. Obviously this type of tag would be used for more meaningful tasks
such as telling the user how big any downloads on your site are.

Flastmod is called in a very similar manner, except it prints out the
date the specified file was last modified:

<!--#flastmod virtual="comments.shtml"-->

The final command, config, is used to specify how the other SSI's
output their data. For instance, you may not like the way the date is being
displayed by these SSI's, so you can change the format:

<!--#config timefmt="%d-%m-%y"-->

The date will now be printed out like 1-1-00.

Size's of files can be abbreviated to something like 25k with:

<!--#config sizefmt="abbrev"-->

or displayed as 25bytes with:

<!--#config sizefmt="bytes"-->

This is really all there is to SSI's. They are very simple, and can't really
do much, but what they do, they do well. They can save you a lot of time and
trouble if you use them right, and they aren't likely to cause too many
problems.