Приглашаем посетить
Грибы (grib.niv.ru)

Building Your Own Basic CGI Program

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.

<html>
<head>
<title>MyLog Entry Form</title>
<body>
Please fill in the below information<br>
<form action="/cgi-bin/mylog.cgi" method=POST> ####this is a comment. erase this. Make sure the "action" statement is pointed to where you keep your executable scripts####

Your Name:<input type=text size="20" name="usrname"><br>
Your e-mail: <input type=text size="20" name="email"><br>
Comments:<br>
<textarea cols="40" rows="3" name="comments"></textarea><br>
<input type=submit name="submit" value="submit"><input type=reset name="reset" value="reset">

</form>
</body>
</html>

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

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
"/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"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";

"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:

# Location of log file
$logfile = "/usr/home/upstate/public_html/mylog/mylog.log";

# Location of e-mail program
$mailprog = '/usr/sbin/sendmail';


$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:
"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 "<html><head><title>Thank you!</title</head>\n";
"<body>\n";
print "Thanks $in{'usrname'} for filling out my form!<br>\n";
print "I'll keep in touch!\n";
print "</body></html>\n";

There, you'll notice we put a \n at the end of each line. Also I introduced something new, the 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.

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";

"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!

it to our file. So we tell it to print to our filehandle:
"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";
"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: 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:
"| $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 <youremail@yourhost.com>\n";
print MAIL "From: $in{'usrname'} <$in{'email'}>\n";
"Subject: My Log report\n";
print MAIL "Someone filled out your form\n";
"It was filled out by: $in{'usrname'}\n";
print MAIL "Here is what they said:\n";
print MAIL "$in{'comments'}\n";

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: 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


$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
"/usr/home/upstate/public_html/cgi-bin";

# Tell Perl we require cgi-lib.pl
require "$library/cgi-lib.pl";


&ReadParse;


print "Content-type: text/html\n\n";

# Send the user a thank you
print "<html><head><title>Thank you!</title</head>\n";
print "<body>\n";
"Thanks $in{'usrname'} for filling out my form!<br>\n";
print "I'll keep in touch!\n";
print "</body></html>\n";

# Open the log file and write the data
open(FILE, ">$logfile") || die "I can't open $logfile\n";
"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";
"\n";
close(FILE);

# Open the sendmail program and pipe the data
open(MAIL "| $mailprog -t") || die "I can't open $mailprog\n";
"To: Your Name <youremail@yourhost.com>\n";
"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";
"$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