
Perl Case Study - Form CGI
By Lisa Hui
A short introduction is on order for the leap into this programming void.
The purpose of the following CGI script is to receive data sent from a
form. (This script can
thus be called via the ACTION attribute in a <FORM> but that is not
necessary to pass data!) The data is automatically
URL encoded (certain
characters are substituted with a corresponding code). This case study piece
is heavily commented due to the ambiguous nature of the perl code.
#!/usr/local/bin/perl
#################
# File Name: form.cgi
# Determining whether or not the <FORM> method is GET or POST
# if it is GET, that means all the data was appended to the URL
# if it is POST, all the data was put into STDIN, a data buffer
if ($ENV{"REQUEST_METHOD"} eq 'GET') { $buffer = $ENV{'QUERY_STRING'}; }
else { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }
# All the data has now been copied into the variable called $buffer
# The purpose of this is to associate each set of name of form field
# with the data entries in the form field
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;
}
#################
# An associative array (hash) called %FORM was created to
# store the value pairs. Now you can get the data from a
# form field simply by calling it by name. If you had a form
# that was like <INPUT Type="text" Name"YourName">
# this piece of data is stored in $FORM{'YourName'}.
# This is derived from the NAME and VALUE (pair) attributes in
# form input fields.
#################
# Print out all the form data on a results page
# See the form and associate its values to this page.
print qq~
<HTML>
<HEAD>
<TITLE>$FORM{'title'}</TITLE>
</HEAD>
<BODY>
Name: $FORM{'YourName'}<br>
How are you today? $FORM{'feeling'}<br>
Have you been able to understand this tutorial?
$FORM{'understand'}<br>
Comments: $FORM{'comments'}
</BODY>
</HTML>
~;
See this script in action:
form.cgi (POST method) or
form.cgi (GET method)
Since I we've only briefly gone through the parsing process, let's take a
closer look at the foreach loop:
foreach $pair (@pairs) {
# Each pair has been stored as $name=$value so now we
split them
($name, $value) = split(/=/, $pair);
# $value's with more than one word may have a + sign
joining them together
# this line will replace the + with a space.
$value =~ tr/+/ /;
# pattern matching and substitution to decode the URL
encoded value
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
# Associate the $name and $value pair using hash
syntax
# As the foreach loops through all the pairs of data,
they will be added to the
# hash %FORM
$FORM{$name} = $value;
}
You may have noticed that I didn't add these comments in the actual script
printed at the top. (Only because adding comment lines in loops will result
in errors messages.)
Since we've gone over hashes
and splitting data, the elements that may have not been so familiar are
the looping and patternmatching, although looping has a very literal type
of diction.
Looping
There are three major types of loops, which are theoretically similar to
each other. In most cases, it will be a matter of preference.
While would probably be the simplest to work with. In a primitive
sort of English, it is basically saying "While this condition is true, perform
these set of instructions again and again (checking during each iteration
whether the condition is true)." In Perl-speak, the schematic becomes:
while (condition is true) {
perform these actions
}
Nevertheless, all three are essentially the same. In a foreach loop,
the idea is that you iterate these actions "for each element in an array."
The schematic:
foreach $element(@array) {
perform these actions
}
For is a handy loop because it allows you to display all the initialized
variables, the condition, and the incremeter all at the beginning. Check
below to see what I mean:
for (intialized values; condition; increment) {
perform these actions
}
I'm not going to go over for syntax here, but you can find the explanation
in the C++ tutorial (what
a coincidence, they use the same syntax for this loop!).
What could the condition be? Anything that would evaluate to a "true" or
"false," 1 or 0, filled or unfilled. Let's take a very simple example in
which the variable is 0 - or false - and the action (printing the value
of the condition) are not performed:
$condition = 0;
while ($condition) {
print $condition;
}
If you ever write in an "absolute" condition (which always causes the loop
to reiterate), you may find the last and exit; commands useful.
Last works like the C++ command break; It will "break" out of the loop
and continue on with the program. (Exit, on the other hand, will end the
execution of the program.)
$i = 0;
while (true) {
if ($i eq 100) { last }
$i++; #increment the variable
}
A tip: you can negate the value of the condition (reverse its value) by putting
an exclamation in front of it. !true is the same as writing
false.
Below is an example of a while loop that checks if the STDIN buffer
is filled;
while (<STDIN>) { print; }
Notice that print automatically prints out each line of STDIN and the condition
is that "while STDIN is still filled with some data." You could have set
each line of STDIN to a variable and then printed out the variable, but either
way should work: while($line = <STDIN>) { print $line; }
Let's take this same example with a foreach loop:
@array = <STDIN>;
foreach $line(@array) {
print $line;
}
And with a for loop; we don't need to "initialize" or "increment"
any values, much like the while loop, so we can leave those blank:
for( ;<STDIN>; ) { print; }
Pattern Matching - Part One
Pattern Matching is probably more of a "menial" task, you might say. You
tell the script a word or phrase etc that you want to match. If you asked
why we would even need it, you just saw an important example in the
form.cgi script. We'll get a chance to sneak a peek at some simple
ways to translate, substitute, and get to the real gory (and when I say gory,
I mean gory!) pattern matching later on in
Perl Case Study - Prelude
to Search Engine CGI.
translation tr///
substitution s///
pattern match //m
assertions
modifiers

Perl Case Study - Time CGI