Building Your Own Basic CGI Program.
Okay, I don't intend for this to be any kind of replacement for buying
a couple of books and doing your own homework. What I hope this is, is
a chance for you to take what you already know and maybe with the aid
of this mold that into a useable base of knowledge.
Also, this tutorial is primarily for those just getting into Perl and
CGI. I'm going to assume you know a little about both. Meaning, you
know that Perl is a programming language and that CGI is a means in
which a client "talks" to a server and vice versa (in the plainest
English I could think of!).
What I'd like to suggest to you, is that you go out and get yourself a
book or two on Perl. There are several excellent texts devoted to
just learning Perl. One such book is "Learning Perl" by Randall
Schwartz. Its published by O'Reilly Associates, and you can get it at
any good book store. When it comes to learning Perl, there really are
no short cuts.
For my basic intro to Perl, check out the my Opinions on Perl. I
tried to encapsulate a simple introduction to the language. Many have
done it better than I have, so look around.
Okay. First. People always ask, "what do you actually create a program
in?" The answer is really simple: What ever you want. I happen to use
Wordpad. A simple word processing program. All you need is the ability
to type text in and save it as a ASCII text file.
_________________________________________________________________
So, pop open your text editor of your choice and start with a fresh
page.
The first line of many Perl programs is the "pound bang" line. That
looks like this: #! This is a special syntax used on Unix machines.
This is the item that tells the operating system that it must send
this data to an interpreter. What follows after the pound bang line is
the path to the interpreter you want to use. In this case the Perl
interpreter, which on many machines is located in the: /usr/bin/
directory. So, your pound bang line should look something like this:
#!/usr/bin/perl If you don't know where Perl is on your system, at the
command line, simply type: which perl. The machine will give you the
path.
Okay, now we have to decide what we want this program to do. Planning
is essential when writing a program, and the more planning you do, the
better your program will be. So, right now, lets decide what this
program will do. We must be as specific as possible. We can't just say
"uh, lets make it an order form program" That isn't enough. We must
plan each procedure this program must perform. So, I've taken the
liberty (since this is your first program, he he!) of deciding for
you:
We'll call this program "mylog" And here's what it will do:
1. mylog will control an HTML form that asks for a user's name, e-mail
and ask for some comments.
2. mylog will decode and parse that input from the form.
3. mylog will return the user a thank you screen using some of the
user's input.
4. mylog will send you (the maintainer) an e-mail reporting that
someone filled in that form.
5. mylog will create/append a log file, writing each entry in a
formatted, logical manner, so that you can user that information.
Okay, lets take this step by step. The first thing we need, is a quick
little HTML form. I've taken the liberty and created one for you. Just
cut and paste this into another new text file and save it, then upload
it to your space.
MyLog Entry Form
Please fill in the below information
Okay, I'm sure you've seen this all before, but there is one thing
that is very important with forms, and that is the "name" and if you
have checkboxes or radio buttons, the "value" fields are as equally
important. Make sure you name the "name" and/or "value" fields with
names you can remember and names that make sense!
So, we've got our form, now we need the program that is going to
"drive" that form. You should have your text editor at the ready with
a fresh page.
First we enter in our pound bang line:
#!/usr/bin/perl
Side not: whenever you see a pound sign # in a Perl program, that
means that what ever is after the # is a comment, meaning the
interpreter ignores it, unless! an exclamation mark follows it.
On the next line, I like to comment what the program is.
# MyLog CGI program to process form input from mylog.html
notice I started that line with a # The interpreter will ignore that
line.
All right. Now we get into some of the dirty work. Remember in our
outline of what our program has to do we said that mylog must send
e-mail, create/append a log file? That means we have to do some work
with files and use an external program (the e-mail program on your
machine). So, as good programming, the first thing we do is tell Perl
where all this good stuff is! Now, Perl handles every thing as data,
no matter if its a process or a directory path. And Perl handles data
in primarily three methods: in scalar variables, in arrays and
associative arrays. We'll get into each one later on, but right now we
have to concern ourselves with scalar variables. This is the most
basic method in which Perl handles data. Since we are dealing with
singular items (handling a file and sending e-mail) we are going to
store the information on both functions in two scalar variables. The
first one we'll call "logfile" and the second we'll call "mailprog" We
express scalar variables by putting a dollar sign before the name we
assign to them:
$logfile
$mailprog
So, what do we know? We know that the scalar variable (I'm just going
to refer them as variables) $logfile is the variable that will "hold"
our information on our log file and that $mailprog will hold the
information on our e-mail program.
We aren't done there. We must "define" what $logfile and $mailprog
are. We just can't let them sit there. Perl is not a mind reader!! So,
we must tell Perl what they are.
$logfile = "/path/to/where/your/space/mylog/mylog.log";
So, what do you think this says? Basically what this says is that
$logfile is a file called "mylog.log" We have to put the entire path
to mylog.log because we have to tell Perl where it EXACTLY is! You'll
also notice that you'll have to create a directory within your space
called "mylog" I did this just so everything is kept nice and tidy!
Now, we have to define $mailprog. You'll remember that $mailprog is
the variable that tells Perl about our e-mail program. Basically what
that is, is simply where it is.
$mailprog = "/usr/sbin/sendmail";
Just like $logfile, $mailprog tells Perl where something is. In this
case we are telling Perl that our mail program (called sendmail) is in
the directory: /usr/sbin.
side note: as a matter of practice. when ever you're dealing with
files or programs, its best to put the path statements in double
quotes. You'll also notice that each line ends with a semi-colon. This
tells Perl that it is done with this line and to go onto the next.
So lets do a quick review. What do we have so far? Well our program
should look like this (I hope!):
#!/usr/bin/perl
# MyLog CGI program to process form input from mylog.html
# Location of our logfile
$logfile = "/usr/home/upstate/public_html/mylog/mylog.log";
# Location of our sendmail e-mail program
$mailprog = "/usr/sbin/sendmail";
This is what we have so far! Pretty neat huh?
Okay, lets get on with it.
Now that we've defined these two variables there is one more that
needs to be defined. This one is quite important, and directly relates
to our first procedure we outline: parsing our form input.
There is an external Perl program called the: cgi-lib.pl file. It
stands for CGI Library. It is a library in the sense that it has many
resource contained in one place which you may use to accomplish
various tasks. cgi-lb.pl most popular function is gathering,
decoding/parsing input from a form. Lets take a second here and talk
about the mechanics of what happens when you click on that "submit"
button.
First all of the information that you entered in the text boxes, radio
buttons or text areas, is all sent to the server. It is sent to the
server in a format called URI encoded data. What that is, basically,
is that your input is sent to the server in one long string with the
name/value pairs delimited by ampersands (&) The name/value pairs are
from the form itself, that's why its important for you to name them
logically. Because you're going to have to know them in order to write
your program. Okay, not only does URI encoded data come to the server
as one long string, but it also picks up some nasty hexadecimal stuff.
That hex stuff is quite important. See, if you have a forward slash
(/) or a percent sign (%) or any other weird character, they have to
be translated to their hexadecimal counterparts so the server doesn't
get confused. So, now that the server has this one long string, its
quite useless to us. So, this is where cgi-lib steps in. It gather's
that URI encoded data and first splits it into a variable called $name
and one called $value. Then it decodes all of the hexadecimal
material, and translates it back to its ASCII form. Then once it does
that it places the name/value pairs into an Associative array called
"in" (associative arrays are data types that handle complex forms of
data). So, now we have all of our form input (the name/value pairs) in
our associative array called "in" I'll get to how we use that data in
a second.
Okay, so we know we need the cgi-lib.pl to decode our form input. but
how do we do it???? Its rather simple. First we tell Perl where our
cgi-lib.pl file is. I usually just create a variable called: library
$library = "/usr/home/upstate/public_html/cgi-bin";
Now what we must do is tell Perl we are going to use cgi-lib.pl. We do
this using one word: require then a statement saying what do we
require:
require "$library/cgi-lib.pl";
There now cgi-lib.pl has been assumed by our mylog.cgi program! But
that's not it. We have to "call" what functions we need to use from
the cgi-lib.pl file. That is done by "referencing" one of cgi-lib's
functions. Remember I said its like a library. Well, in order to use
the library, you have to know what you're looking for. So, to "call"
the function in the cgi-lib, we just have to add this line:
&ReadParse;
This is the function that does all of what I talked about earlier.
Okay, lets do another quick review. Make sure you're all up to speed!
Here's what we should have by now:
#!/usr/bin/perl
#MyLog CGI program to process form input from mylog.html
# Location of log file
$logfile = "/usr/home/upstate/public_html/mylog/mylog.log";
# Location of e-mail program
$mailprog = '/usr/sbin/sendmail';
# Location of our cgi-lib.pl file
$library = "/usr/home/upstate/public_html/cgi-bin";
# Tell Perl we require cgi-lib.pl
require "$library/cgi-lib.pl";
# Call cgi-lib's function to decode/parse our form input
&ReadParse;
side note: the ampersand (&) is the Perl syntax for calling a sub
routine. A sub routine is a block of code that handles one area of the
program. The nice thing with Perl is, you can call a sub routine any
where in the program, and only right the routine once! So, you can
have a sub routine that checks for a certain phrase in a text file and
you might need to check it a number of times you just need to make a
reference to the sub routine that does the checking.
Allright. Now, we're almost done. So, we've got our form input placed
into our associative array called in. Now we need to use that input!
Lets remember one of the procedure's of myform. It was to return an
html thanking the user for filing out the form. This will be the first
time we use some of that input.
The first thing we must do if we intend to return a page to the user
is tell their browser what we're sending them. This is done simply by
sending them the HTTP header, which simply tells their browser what
the content will be. In our case it is text/html. So, we simply
express this by writing this:
print "Content-type: text/html\n\n";
the "print" command is Perl's standard output syntax. The
"Content-type: text/html\n\n" is the header information. the \n\n is
Perl's way of returning two new lines. This is crucial. When you send
header information to a browser, you must return two new lines before
you actually get into the content.
Now that we have told our user's browser what its getting lets send it
the goods! We do this by a series of "print" statements. We actually
print an HTML page. Which looks like this:
print "Thank you!\n";
print "\n";
print "Thanks $in{'usrname'} for filling out my form! \n";
print "I'll keep in touch!\n";
print "\n";
There, you'll notice we put a \n at the end of each line. Also I
introduced something new, the $in{'usrname'} Do you recognize the
'usrname' part? Well you should, that's from our form! See, we made a
reference to our associative array. The one that holds our form input.
the 'usrname' is called a key. It represents a section in our
associative array. the $in is simply naming the associative array. So,
in simple English $in{'usrname'} equals the value from our form which
is the user's name! If we wanted to tell the user that we know their
e-mail address, we could do that by saying: $in{'email'} We can use
any part of our input from the form just by referencing the
corresponding key from our associative array.
Okay, we've made sent our thank you's. Now lets get on with the
business part.
We want to write all of the user's input from the form into a file so
that we can maintain a list of all those who have filled out our form.
Perl is quite logical. You must do things in logical order for things
to work. So, the first thing we must do if we want to work with a file
is... open it!
So lets do that:
open(FILE, ">$logfile") || die "I can't open $logfile\n";
Allright. First lets take this line apart. The "open" command does
just what it says, opens a file. You must assign a file that Perl is
going to use what is called a filehandle, that is usually typed in all
upper case. I simply called it FILE. Then we must tell Perl what file.
The > tells Perl to append a file, or if it isn't there to just create
the file. You remember that $logfile is the path and name of our log
file. Then we add the: || die "I can't open $logfile\n"; the die is a
simple method of killing the process if Perl can't find your file.
When ever you are going to open a file or a process on your machine.
Always include this, so nothing weird happens if you entered anything
incorrectly!
Okay, our file is open, now we want to write our information. We do
that using the print command again. But... we don't want to print the
output to the standard output (the screen) we want to write it to our
file. So we tell it to print to our filehandle:
print FILE "Someone filled out your form\n";
print FILE "Here is there information:\n";
print FILE "Name: $in{'usrname'}\n";
print FILE "E-mail: $in{'email'}\n";
print FILE "Comments: $in{'comments'}\n";
print FILE "\n";
Now, we close our file:
close(FILE);
There, this fully illustrates how we make our references to our
associative array: in. So, if you wanted more form inputs on your form
say you wanted to add an address field, and you named that field:
address. The associative array reference would be: $in{'address'} Does
that make sense??? That's why I said its important to name your field
names in a logical way! I can't count the number of times I've
forgotten what I named a particular name in a form!
Okay, we're moving now. The next thing we want to do is, send
ourselves some e-mail. You'll see a lot of CGI programs do this. And I
usually build this into many of my programs. This is mainly for
conveyance. I hate to log in, traverse through the file system to look
at my log file. So, I just have it send me an e-mail with the
information in it. Call me lazy!
Okay, remember I said that Perl treats everything has a piece of data,
that includes other programs. Remember we told Perl where and what our
e-mail program was. We treat this just like it was an ordinary file,
in one respect, and we do something slightly different than if it was
just a regular file. We must take our input and send it to another
program where it does its own thing. This process is called "piping"
We "pipe" data to another program via this little thing: |
I'll show you how it works:
open(MAIL "| $mailprog -t") || die "I can't open $mailprog\n";
There, we opened our "file" and assigned it a filehandle. But instead
of treating it as a regular file, we opened a "pipe" to our sendmail
program. Also we added the die statement just incase!
Now, we handle everything as if it was a normal file:
print MAIL "To: Your Name \n";
print MAIL "From: $in{'usrname'} <$in{'email'}>\n";
print MAIL "Subject: My Log report\n";
print MAIL "Someone filled out your form\n";
print MAIL "It was filled out by: $in{'usrname'}\n";
print MAIL "Here is what they said:\n";
print MAIL "$in{'comments'}\n";
close(MAIL)
There, you'll notice the To: From: and Subject: lines. This is so
sendmail can properly format the message. You'll also notice the
absence of the semi-colon after the: close(MAIL) that's because it is
our last line in our program. So we can leave them off.
So, that's it. Here's what the finished product should looks like:
#!/usr/bin/perl
#MyLog CGI program to process form input from mylog.html
# Location of log file
$logfile = "/usr/home/upstate/public_html/mylog/mylog.log";
# Location of e-mail program
$mailprog = "/usr/sbin/sendmail";
# Location of our cgi-lib.pl file
$library = "/usr/home/upstate/public_html/cgi-bin";
# Tell Perl we require cgi-lib.pl
require "$library/cgi-lib.pl";
# Call cgi-lib's function to decode/parse our form input
&ReadParse;
# Print the http header
print "Content-type: text/html\n\n";
# Send the user a thank you
print "Thank you!\n";
print "\n";
print "Thanks $in{'usrname'} for filling out my form! \n";
print "I'll keep in touch!\n";
print "\n";
# Open the log file and write the data
open(FILE, ">$logfile") || die "I can't open $logfile\n";
print FILE "Someone filled out your form\n";
print FILE "Here is there information:\n";
print FILE "Name: $in{'usrname'}\n";
print FILE "E-mail: $in{'email'}\n";
print FILE "Comments: $in{'comments'}\n";
print FILE "\n";
close(FILE);
# Open the sendmail program and pipe the data
open(MAIL "| $mailprog -t") || die "I can't open $mailprog\n";
print MAIL "To: Your Name \n";
print MAIL "From: $in{'usrname'} <$in{'email'}>\n";
print MAIL "Subject: My Log report\n";
print MAIL "Someone filled out your form\n";
print MAIL "It was filled out by: $in{'usrname'}\n";
print MAIL "Here is what they said:\n";
print MAIL "$in{'comments'}\n";
close(MAIL)
There that's it! Some closing thoughts. Make sure to comment your
program heavily. This one didn't really require it. But for each
section in your program, make sure you have a # and comment what that
section does. That way in a month down the road you can easily
remember what everything does!
Okay, now save your text file call it: mylog.cgi and upload it to your
cgi-bin. Chmod it to 755. Create the directory: mylog and chmod that
to 777. This gives permission to write to the directory. Make sure to
upload the mylog.html. Now try it out! Oh make sure you have
cgi-lib.pl in place, and chmod that to 755!
Well, if I left something out, or you need something clarified, just
drop me a line at:
dave@upstatepress.com
This tutorial was written by: Dave Palmer
----------
Building Your Own CGI Program (a relatively complex one!)
Associative Arrays | Error Checking and Working with Output |
Writing to an Existing File | Sub Routines | Closing
thoughts]
_________________________________________________________________
Introduction
So, did you make through Tutorial 1??? I hope so! Also, I'd have to
say you're one dedicated learner! Jeeez, to tolerate my confusing
banter!
Okay, so where are we? We learned how to write a CGI program that does
some simple, yet some rather useful functions. Lets take a second to
review.
We have a program called mylog.cgi and it does (I hope!):
1. Parses input from a form, and uses cgi-lib.pl to decode that
input
2. Sends the user a thank you screen
3. Formats the user's input into a text file mylog.cgi creates
4. Sends us an e-mail notifying us of the new entry to our log file
If you'll remember, the first thing we did, even before we wrote a
single character of code, was to plan. So, lets do that now. Lets do a
quick thumbnail sketch of what we want this program to do.
Our program will be a guestbook. These are very popular, and you see
them all over the place. So, lets write our own! Here's what we want
it to do:
1. Parse our input from a form the user fills out
2. Send the user a confirmation page
3. Format the user's input to a separate HTML file. We'll have a
feature that will allow the user to enter his URL and we'll create
a link to it in his entry. We'll also ask for his e-mail and create
a mailto link in his entry as well.
4. We will check the user's input, and do some error checking
routines. This is important because if they forget to fill out a
field, our program will inform them of this, and ask that they fill
in the missing field. We'll even provide them with a field in which
to do so (so they don't have to go back).
5. We have the program notify us when ever someone adds to our
guestbook, but, only if we want it to!
6. We'll send the user a thank you e-mail (Thanks for signing our
guest book!)
So, you'll see we have our work cut out for us! You'll also notice I'm
going to be introducing some new concepts. But stick with it! If you
went through Tutorial 1, you learned the key concepts. We are just
going to expand on what you know!
_________________________________________________________________
Getting Started
First, launch your favorite text editor, and start with a nice fresh
page.
Lets do it!
Lets start with our first line. If you remember, the first line in a
Perl program (written for Unix machines, which this is) you need your
"pound bang" line. So, go ahead and type that:
#!/usr/bin/perl
Now, before we go any further, lets add our first comment. Telling us
what the hell this thing is!
# My Guestbook CGI program!
Okay, now just like mylog.cgi, the first order of business is we need
to define a few variables. We are going to need several external files
and processes for this program to work. So, we do that by assigning
this information to scalar variables.
The first thing we'll tell Perl is the location of our actual
guestbook page. This is the page where the user's input is placed.
This file will be a regular HTML file.
$guestbook = "/home/your_name/public_html/guestbook/guestbook.html";
You'll notice that in your public_html directory, you'll have to
create a directory called "guestbook" and inside that directory will
be your guestbook.html file. Notice that the path is in double quotes,
and the line ends with the semi-colon.
Okay, now we'll tell Perl what the URL of our guestbook.html file is.
We are doing this because we want this URL to be linked on any of the
return pages our program may return. I'll go into further detail a bit
later on.
$guestbook_url =
"http://www.yourhost.com/~yourname/guestbook/guestbook.html";
Now lets tell Perl the URL of our guestbook.cgi file. We do this
because we are going to have to know this if the user misses a form
field. We'll simply give them another opportunity to fill in the
missing field. So, if we give them that chance, we'll have to tell
Perl where our guestbook.cgi file is for the