No, this guide is not for fools but by a fool, who had kept wondering how CGI.pm is supposed to work and finally got a clue. So here’s how (I think) it works in simplest cases. I hope this might make some other people’s learning curve a little better.
- Prerequisites
- Hello world
- Just echoing data
- Processing the data
- Checking data
- Quick reference to CGI.pm functions
- Further reading
Prerequisites
You need
-
a little idea of how Web pages are created, especially
a vague idea of HTML forms;
actually it might suffice to have used a simple query
form, and you can hardly have avoided them when surfing.
But just in case you have, here’s a sample form: - elementary knowledge about
Perl; something like the following
shouldn’t scare you too much:foo = 'hello world'; $foo =~ s/ / cruel /; print $foo;
- a vague idea of
what CGI is; you should faintly understand that some URLs,
when accessed, may activate a program (script) on a server;
the following does:1
2
3<a href=
"http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi"
>http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi</a> - some idea of what you might want to do with CGI scripting
- capabilities of using CGI scripting in Perl on some
server as well as local information on
how to do that; contact the local Web server’s documentation or
the server administration (1webmaster@servername)
for information.
Hello world
OK, first do this: Check that you have the above-mentioned
local information. Double-check that you have understood it.
You should now know where to put your Perl programs in order to run
them as CGI scripts and what you might need to do with them
(setting file protections, perhaps). Fine, then test this with
the following script:
print <<END; Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <title>Hello</title> <h1>Hello world!!</h1> END
That is, write that into a file,
perhaps adding something into it as needed according to local
instructions
(such as a “magic”
1 | #! |
line that tells the path name of
the Perl interpreter on the server)
store the file where you need
to put your CGI scripts, and try accessing it via a link or
by directly typing the URL to a browser. It should work
basically the same way as the following link:
1 | <a href="http://www.cs.tut.fi/cgi-bin/run/~jkorpela/hw.pl">http://www.cs.tut.fi/cgi-bin/run/~jkorpela/hw.pl</a> |
You will probably need some help to make
the script work. There are several practical things that need to
be set properly, and they vary from one server to another.
There’s a useful (though Unix-oriented) general resource: the
checklist
The Idiot’s Guide to Solving Perl CGI Problems.
You haven’t used CGI.pm yet. The trivial program above just
writes some fixed text. When executed as a CGI script, the first
lines of the output (up to the first empty line) will be taken as
HTTP headers and sent to the browser,
and the rest is sent to the browser as actual data (HTML document,
in this case, and quite often).
Just echoing data
Next we’ll actually use CGI.pm but for a very simple purpose:
we have a form with a text input field and we echo back the data
that the user has typed. Trivial, but it’s the start.
Our form is the following:
<form action="http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo1.cgi""> <div>Please type some text: <input name="sample" size="20"></div> <div><input type="submit"></div> </form>
It looks like the following:
Try it!
The Perl program referred to in the
1 | action |
attribute
is the following:
use CGI qw(:standard); $data = param('sample') || '<i>(No input)</i>'; print <<END; Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <title>Echoing user input</title> <h1>Echoing user input</h1> <p>You typed: $data</p> END
So how does it work? The line
1 | use CGI qw(:standard); |
is a prelude needed for using CGI.pm (in a particular mode).
And the line after it,
1 | $data = param('sample') || '<i>(No input)</i>'; |
is in this case the only part of the program that uses CGI.pm,
and it uses it only by calling the
1 | param |
function.
That function gives the value of the form field whose name is
passed as parameter. Note that the value might be undefined,
even if a field with that name is present in the form markup;
if the user does not fill out the text input field, there will
be no such field in the form data. (In Perl we can handle undefined
values conveniently; if the value is undefined,
the code above uses a fixed string instead.)
This works irrespectively of the
1 | <a href="../forms/methods.html">method</a> |
(
1 | "get" |
or
1 | "post" |
) of the form. More
generally, we need not worry about the mechanisms of
form data transmission, such as “URL encoding”.
You might have tried submitting text like <b>foo</b>
and noticed that the HTML markup “works”. This is simply because the
script writes the data as such into a document that will be sent to the
browser and treated as an HTML document. To prevent characters from
being treated as part of HTML markup, you could add
1 | $data = escapeHTML($data) |
into the script (before printing anything out).
Processing the data
If we’d like to store the data, we
could do it using Perl’s
normal file operations. So this isn’t interesting from the CGI.pm
point of view, though of course it can be very relevant for
practical purposes. The same applies to other processing
of data, like sending it by E-mail.
But for illustration, here’s
how to set up a simple form that collects data and saves it
onto a file:
#!/usr/local/gnu/bin/perl use CGI qw(:standard); print <<END; Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> END $regfile = '../public_html/perl/registrations.tsv'; $name = param('name'); $email = param('email'); $food = param('food'); open(REG,">>$regfile") or fail(); print REG "$name\t$email\t$food\n"; close(REG); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time); $now = sprintf "%4d-%02d-%02dT%02d:%02dZ\n", 1900+$year,$mon+1,$mday,$hour,$min; print <<END; <title>Thank you!</title> <h1>Thank you!</h1> <p>Your fake registration to Virtual Nonsense Party has been recorded at $now as follows:</p> <p>Name: $name</p> <p>E-mail: $email</p> <p>Food preference: $food</p> END sub fail { print "<title>Error</title>", "<p>Error: cannot record your registration!</p>"; exit; }
The form is simple:
<form action="http://www.cs.tut.fi/cgi-bin/run/~jkorpela/collect.pl" method="post"> <div>Fake registration to virtual party:<div> <div>Name: <input name="name" size="30"></div> <div>E-mail: <input name="email" size="25"></div> <div><input type="radio" name="food" value="" checked> Food preference (select one):<br> <input type="radio" name="food" value="Swedish meatballs"> Swedish meatballs<br> <input type="radio" name="food" value="Fish sticks"> Fish sticks<br> <input type="radio" name="food" value="Falafel"> Falafel (this is vegetarian food)<br> <input type="radio" name="food" value="no food"> None (i.e., will not eat)<div> <div><input type="submit"></div> </form>
OK, you can try it:
Notes:
- The time stamp is in
ISO 8601 notation. - The file format used is
Tab Separated Values, to allow
easy processing using various programs. - You can view the
registrations file.
(This file is in a directory different from the one where the script is.
Such arrangements are server-specific.) - There is no checking of input data, to keep the example
reasonably small. In a real-life situation, you would probably
want to check at least against empty fields.
Checking data
One of the great advantages of using CGI.pm is that it provides
very simple tools for
checking data acceptability and requesting the user to fix the data.
For example, we might wish to require that some name be given
(i.e. the name field is not empty or blank),
that an E-mail address satisfying some formal requirements is given,
and that some food preference is selected.
In real-life cases, you would probably want to do some real checking,
like verifying a user name and password combination.
But the basic techniques are perhaps best illustrated with an almost
trivial example. And let’s say that the E-mail is checked only against
a missing “@” sign; this at least filters out some
(accidental) erroneous submissions.
(Since you are about to ask anyway:
No, you can’t really check an E-mail address except by trying to send
E-mail to it. See entry
Can I verify the email addresses people enter in my Form?
in the
CGI Programming FAQ.)
The fundamental idea is to generate a form dynamically
by a CGI script and do this so that the same script also processes
the submitted data. Confused? Well, let’s take an example
(you could also
see the example in action):
#!/usr/local/gnu/bin/perl use CGI qw(:standard); $regfile = '../public_html/perl/registrations.tsv'; print header; if(param()) { $name = param('name'); $email = param('email'); $food = param('food'); if(ok()) { open(REG,">>$regfile") or fail(); print REG "$name\t$email\t$food\n"; close(REG); print <<END; <title>Thank you!</title> <h1>Thank you!</h1> <p>Your fake registration to Virtual Nonsense Party has been recorded as follows:</p> <p>Name: $name</p> <p>E-mail: $email</p> <p>Food preference: $food</p> END exit; } } %labels = ( '' => 'Food preference (select one):', 'Fish sticks' => 'Fish sticks', 'Falafel' => 'Falafel', 'no food' => 'None (i.e., will not eat)' ); print start_form, 'Fake registration to virtual party',br, 'Name: ', textfield('name'), br, 'E-mail: ', textfield('email'), br, radio_group(-name=>'food', -values=>\%labels, -linebreak=>'true', -default=>''), submit, end_form; sub fail { print "<title>Error</title>", "<p>Error: cannot record your registration!</p>"; exit; } sub ok() { $fine = 1; if(!$name) { print 'Your name is required!', br; $fine = 0; } if(!$email) { print 'Your E-mail address is required!', br; $fine = 0; } elsif(!($email =~ m/\@/)) { print 'An E-mail address must contain the @ character!', br; $fine = 0; } if(!$food) { print 'A food preference (even if none) is required!', br; $fine = 0; } if(!$fine) { print 'Please fix the data and resubmit', hr; } return $fine; }
Instead of writing a form which is statically part of an HTML
document, we have a script which generates an HTML document (which
contains a form). We can refer to the script using a normal link;
the URL is in this case
1 | <a href="http://www.cs.tut.fi/cgi-bin/run/~jkorpela/coll.cgi">http://www.cs.tut.fi/cgi-bin/run/~jkorpela/coll.cgi</a> |
and
what happens when that URL is referred to depends on the context:
- If a plain link to it is followed or there are otherwise
no parameters passed, the script just sends back an HTML document
(containing the form). - If parameters are passed but they fail the checks that the
script has been programmed to perform, an HTML document explaining the
errors and containing the form again, with previous data prefilled. - If parameters are passed and they are
accepted in the checks,
the action proper (whatever it is) is executed and then a “thank you”
page is returned. In this case, the “thank you” page echoes back the
form data. (This is very useful, since it gives the user feedback
that something happened, and the user can then print that confirmation
page for himself, save it locally, or whatever.)
Some key ingredients in the script:
-
1use CGI qw(:standard);
is a “standard” prelude for
using CGI.pm -
1header
is an example of a CGI.pm routine; it returns
a string that constitutes a suitable HTTP header for an HTML
document so that you need not worry about such things -
1param()
tests whether any parameters were
passed in the script invocation; note than when the script is
first invoked, that test probably yields false and we fall
down to code that generates the basic form -
1param()
with some string as argument can be used
to get the value of a parameter with a specific name (if defined,
i.e. if present in the form data; note that the code checks for
parameters being defined, using constructs like1if(!$name))
-
1start_form
etc. are CGI.pm routines for generating
form elements; technically they return strings that you need to print
out (using1print) to make things happen
- there are nice structured tools for constructing sets of fields,
like a set of radio buttons; in our example, the hash1%labelsdefines both the names of the fields (in the form
data) and the visible labels associated with them.
The details will not be explained here. This was basically
to give an idea of how things work with CGI.pm.
Note that if you wish to have a form embedded into a static HTML
page, you need something little more complicated. In effect, you would
need to duplicate things by writing a static
1 | form |
element
and the Perl code that generates a corresponding element dynamically
in the form handler when an error in data has been detected and
the form needs to be presented to the user. The reason is that dynamic
generation is the only way to use previous user input as default
values for fields so that the user does not need to type everything anew.
(Well, technically, you could save the data onto the server, but that
would be more complicated.)
Quick reference to CGI.pm functions
The following table lists some basic CGI.pm functions for
generating form fields and related elements.
Note that the statement
1 | use CGI qw(:standard); |
is needed to make these work and that the invocations
just generate HTML constructs as strings; you
need to use the
1 | print |
function to make them
actually appear in a document generated by your CGI script.
function invocation | meaning | ||||||
---|---|---|---|---|---|---|---|
|
starts a form | ||||||
|
starts a form that may contain a file input field | ||||||
|
single-line text input field | ||||||
|
multi-line text input field | ||||||
|
“password” input field | ||||||
|
file input field | ||||||
|
element |
||||||
|
element with
larger than 1 |
||||||
|
group of checkboxes with the same name | ||||||
|
a standalone checkbox | ||||||
|
group of radio buttons that work together | ||||||
|
submit button | ||||||
|
reset button | ||||||
|
reset to original defaults | ||||||
|
hidden field | ||||||
|
image submit button | ||||||
|
element, for client-side scripting |
Note: The parameters
1 | <nobr>-multiple</nobr>=>'true' |
and
1 | <nobr>-checked</nobr>=>'checked' |
are optional and used
to change the default (from allowing a single choice only
and from being initially unchecked, respectively).
For resetting fields, the
1 | reset() |
function is seldom useful. The
1 | defaults() |
function can
be used to set all fields to their very initial values as specified in
the script itself; the script will in fact be called as if it were called
the first time. In contrast, the button created with
1 | reset() |
will clear all changes that the user has made since the last invocation
of the script. Thus, if your code contains
1 | textfield(-name=>'foo',-value='42') |
, then
1 | defaults() |
will always set
1 | foo |
to
1 | 42 |
; but
if the user had changed the input box content to
1 | 100 |
and submitted
the form and got, in addition to other data, the same form in response, then
that form will (normally) contain the latest value
1 | 100 |
as response,
and
1 | reset() |
would set it back to
1 | 100 |
, not the
original
1 | 42 |
.
An array reference
could consist just of an “anonymous array”, like
1 | ['none','apples,'oranges,'kiwis'] |
, or a reference to a named array, such
as
1 | \@foo |
. In order to make the texts seen by users as different
from the strings used internally, which is often a good idea, you would
use a hash reference instead, e.g.
1 | -values=\%val |
with
1 | %val |
defined by
1 2 | %val = ( '0' => 'none', 'ap' => 'apples', 'or' => 'oranges', 'ki' => 'kiwis' ); |
But beware that in this case the order of the fields in the generated
HTML markup may not correspond to the order of the hash constructor
(since hashes are essentially unordered. Thus, to control the order,
use a
1 | -values |
array and, when desired, a separate
1 | -labels |
hash.
Further reading
- CGI.pm – a Perl5 CGI Library, a
description (manual) of CGI.pm by its author, L. Stein. - CGI Programming Made (Relatively) Easy Using Libraries.
Contains a summary and nice illustrations of basic use of CGI.pm. -
The Idiot’s Guide to Solving Perl CGI Problems.
Much more friendly than the name might suggest. A compact checklist
to be consulted when you can’t make your Perl program run as a CGI
script, even when it runs smoothly standalone. - Introduction to the Common Gateway Interface (CGI)
in the
Virtualville
Library. Helps you understand the basic
principles of CGI. -
An instantaneous introduction to CGI scripts and
HTML forms. -
How the web works: HTTP and CGI explained. More detailed
overview of CGI in the general context of the WWW, with interaction
between servers and clients. -
The CGI Resource Index, especially its section
Programming in Perl.
Contains a huge number of programs, many of them free. -
CGI Security : Better Safe than Sorry.
Pankaj Kamthan’s essential security notes to anyone intending
to do serious work with CGI scripts in Perl. - Perl Lessons.
A primer on Perl. You probably know Perl at this point, but you
might wish to check a few basic things.