The due date is 11:30 a.m. on Friday, February 12. Because this is being handed out only five days in advance, if you need more time check with me individually beforehand. Get started soon in any case, because you'll be able to follow the lectures much better. There is actually less to do in this assignment than may appear.
From now on, please hand in all homework files, including HTML
and CGI scripts, using submit
. Of course, you'll still
need to test HTML files and CGI scripts by putting them in
public_html
and viewing them.
1. More HTML
Fix up your home page index.html
so that it contains all of
the following features. Then view it to check it. Then
submit
it.
UL
or OL
tag pairs.
For a table,
<TABLE>
and later </TABLE>
go before and
after the whole table.
<TR>
for ``table row''.
The closing </TR>
after the row is optional.
<TD> ... </TD>
. (Presumably this stands for ``table data''.)
Here is an example of a table. A couple of optional ``attributes'' that you can use are included in the opening tag. (The alignment tells where to put the table across the page. The border thickness can be 0, 1, 2,...)
<TABLE BORDER=1 ALIGN=CENTER>
<TR>
<TD> If </TD>
<TD> you're </TD>
<TD> able </TD>
<TR>
<TD> use </TD>
<TD> a </TD>
<TD> table. </TD>
</TABLE>
2. A helpful routine
Make, test, and submit a Perl script called cgi_helper
that
contains subroutines to output the appropriate header for a CGI
program, and also the appropriate ending HTML tags. Details:
require 'cgi_helper';
in the other
script. Then the other script will be able to use the subroutines
you put here.
#!/usr/....
is not needed, so leave it
out. (If you did include it, it would just count as a Perl
comment when this file is read by Perl.) Also, this script
doesn't have to be executable.
CGI_Header
should have one parameter (i.e, one
argument) to represent a title string. It does not return a value.
When called, this subroutine simply prints out the right header.
CGI_Header
subroutine, you probably will want to
use the ``Here document'' way of defining a string, which is
described on p. 43 of the Perl textbook. Suppose you want to
set $s
equal to a string that has several lines of text in
it; as an example suppose there are three lines, containing the
words her cats
, your dogs
, and his $animals
, where
$animals
was defined earlier in the program. One way would
be to use
$s = "her cats\nyour dogs\nhis $animals\n";
But that's not too clear. To use the ``Here document'' feature of
Perl instead, choose a terminating string; I use ---
but you
can use something else. (This terminating string gets discarded.)
To tell Perl you're using a ``Here document'', use <<
immediately
followed by your terminating string, in double quotes if you
you want substitutions to be allowed in your string, which we
do in this example.
$s = <<"---";
her cats
your dogs
his $animals
---
Much clearer! There should not be any whitespace after <<
or
around either copy of ---
. Also, don't indent the desired
text unless you do want extra spaces in the string. Notice that
the semicolon goes on the line before the text! You can do other
things to the string, for example, print
instead of $s =
.
(If you don't want substitutions, for example if you really want
$animals
to have a dollar sign and the word ``animals'', then
use '---'
instead.)
So, your subroutine should look like this. (Fill in the missing things.)
Be very sure to put a blank line after the Content-type:
line!
sub CGI_Header
{
my($title) = ...
print <<"---";
Content-type: text/html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4/0 Final//EN">
<HTML>
...
<TITLE> $title </TITLE>
...
<BODY>
---
}
Don't put <H1> $title </H1>
in this subroutine; the printed
heading can be printed by the calling program. The <!DOCTYPE>
part isn't in our current CGI books, but will probably be in new ones.
CGI_Ender
has no parameters and no return
value. It just prints out the ending </BODY>
and </HTML>
for an HTML page. Optionally you could include your ``mailto''
information, but perhaps it's best to wait to add that in the future.
CGI_Header
and forget to give a title string;
then Perl might give an error and the CGI page would abort. If no
title is given, then inside the subroutine $title
will be undefined.
In that case we need to invent a title. So right after the line
with my(...)
put a line
defined($title) or $title = "Page produced with CGI_Header";
(Here or
works better than ||
, which is confused by the =
.)
1;
The reason is that the require
command in the other script
expects to see a ``true'' value as the last thing in this file.
help_test.cgi
to test this
one. You don't need to submit this test script. The test script
can simply have the usual first two lines and then have
require 'cgi_helper'; &CGI_Header("Test of cgi_helper"); print "whatever\n"; &CGI_Ender;
Run this script from the command line to see if it gives the ``virtual page'' you are hoping for. Then access it through your browser.
3. The CGI environment
When a UNIX program runs, there are actually four ways it can get information from outside itself. You have seen the first three.
Environmental variables are set by the system before the program runs. As a warmup, try the UNIX command
printenv
and see what you get. Some environmental variables you will
understand, others not. In each programming language there is
some way for a program to read these variables. (It is also
possible to invent and set more environmental variables
yourself, but we won't need that.)
In Perl, it is very easy to get the values of environmental variables;
they are in a hash named %ENV
that is already set when you run
the script. You don't need to know in advance which ones are
defined since you can get that from keys %ENV
. As you know,
the keys may come out in any order but you can always sort them
if you want a nicer order. Also as you know, if one of the
environmental variables is the string ID
, then its value
is $ENV{"ID"}
or if $evar
is an unspecified
environmental variable name, then its value is $ENV{$evar}
.
Now make, test, and submit a Perl script environ.cgi
that
require 'cgi_helper';
CGI_Header
with an appropriate title string as parameter
<H1> ... </H1>
<UL>
or <OL>
%ENV
In order to make them come out on separate lines of the virtual
HTML page, for each variable print <LI>
, then the variable name,
then ``='', then the value of the environmental variable, and then
a newline.
CGI_Ender
When you run this script from the UNIX command line, you should see the same variables as before.
However, when you access this script through your browser using its URL, you will see a different list of environmental variables. These are supplied by the Apache web server software. Later these variables will help to get information from web forms filled in by users.
4. An access counter
Make, test, and submit a CGI script counter.cgi
that counts the
number of times it has been called and shows the result on a
web page. This is a ``naive'' version that has some defects to
be fixed in a more sophisticated future version.
A CGI program can't remember information by itself, so the
current count has to be kept in a file. The file can't be
standard input, since the CGI program is run by the Apache web
server software and not on a command line by you. Call the count
file access_count.dat
. (The .dat
doesn't mean anything in
UNIX but it suggests data when you see it listed among other
files.)
Your script should
require 'cgi_helper';
CGI_Header
with an appropriate title string as parameter
access_count.dat
exists; if it
does not, then open that file for writing with a filehandle,
print a 0 to it, and close it again (important!).
FH
, you can get the
value by using $count = <FH>;
There's only one line to read,
so you don't need a loop. For safety, put in a check that
$count
is an integer (or die).
$count
by one
<H1> ... </H1>
CGI_Ender
You can first test this program by running it on its own. But you should also be able to access it through your browser, with the appropriate URL, and it should keep count. To force a new access, click on the browser ``RELOAD'' button. If you return to the page after browsing elsewhere, again click the ``RELOAD'' button; otherwise you may see an older cached copy of the page.
The weakness in this program is that two different users might access it at the same time and compete for reading and writing the count file. One user might get frozen out, or the file might even be damaged. Our future version will ``lock'' the file so that only one user at a time can access it.