File Under: Programming

Perl Tutorial for Beginners

This article will get you started with CGI scripting, the force that makes forms work, your counters count, and all kinds of other things happen.

CGI scripts can be written in a variety of computer languages, but my favorite is Perl, which also just happens to be one of the most used languages for CGI scripting. So before we tackle CGI, today we’ll max out your gray matter on this damn-near-holy language.


Contents

  1. What You’ll Need
  2. The Rules of the Road
  3. Get Down and Boogie!
  4. Scalers, Arrays, and Associative Arrays
  5. Perl Operators – What Number Please?
    1. Assignment Operators
    2. Comparison Operators
    3. Mathematical Operators
  6. With This Loop, I Thee Wed
    1. The For Loop
    2. The While Loop
    3. Foreach Loop
  7. Getting Manipulative
  8. Additional Functions
    1. Splitting
    2. Search and Replace
    3. Quick Search
  9. Lesson 2:Turning Perl into CGI
  10. The CGI Difference
  11. Just Like in the Movies
  12. Tidying Up the Input
  13. Match Making (The Meat of the Matter)
  14. It’s a Wonderful CGI Script!

What You’ll Need

Some people feel that the benefits of learning Perl scripting are few. But at the end of the day, learning how to do it right gives you the satisfaction of a script well done. It’s kind of like being a cop. You don’t change the world, but you do your small part. That’s right. Learning Perl is just like being a cop.

But before embarking on this mystical quest, make sure you have a few things:

  1. A trusty server capable of handling the monster script you will one day write or, shall I say, compose.
  2. A good monitor. This is important since you’ll spend many an hour looking at the thing, and your eyes will bug under the strain of peering at a small or wavy monitor.
  3. A good source of stimulation:Dr. Pepper, Jolt, coffee, whatever. Just make sure you’ve got a lot of it.
  4. A pack of cigarettes. These will calm your nerves, but the fetching scent will rob you of all sex appeal, allowing you to concentrate fully on writing killer Perl scripts.
  5. Basic food rations. Scripting is best done in short bursts of 24- to 36- hour blocks of time. Leaving to get food is not an option.
  6. A copy of O’Reilly & Associates’ Programming Perl and Learning Perl. These are the best references on the market.

Are you ready? You’re not gonna wuss on me now, are you? C’mon, we’re just talking basics here.

The Rules of the Road

What do you need to know? It’s simple. Just follow these basic rules.

Rule #1: Always put this line at the top of your Perl script, no excuses:

 #!/usr/local/bin/perl 

It tells the server running your script that what follows isn’t Russian on acid but Perl. The server likes Perl, it just needs to know what it is. So don’t forget to start with this line. Otherwise you’ll spend hours trying to find what’s wrong with your syntactically correct script only to discover that you left out the most basic thing.

Rule #2: Always put a semicolon at the end of every line. If you don’t, you’ll never, ever, ever get a script to work. So just do it.

Rule #3: Put comments everywhere you can. What are comments? Comments are complete sentences that describe what the script does at a certain point. Any line beginning with a “#” mark is a comment line, with the exception of the line in Rule #1. Look at the example below to see how comments might be useful.


 # In the following code, I'm going to create a variable that contains

 # the info that will go into a log. But I'm going to keep the

 #  formatting really simple so it'll be displayed in

 # an easy-to-read fashion.



 my $in{'logdata'} = <<END;

 $in{'name'}

 $in{'formelement1'}   |   $in{'radiobutton2'}

 $in{'checkbox1'}        |   $in{'checkbox2'}

 END



As the author of this script, you probably know the purpose of that variable, but what if someone else had to work with the script? You wouldn’t want them to spend the rest of their lives deciphering your uncommented code (unless they’re being paid by the hour). So try to make it easy on everyone else.

Rule #4: Clean code is maintainable code. Writing clean code falls under the good citizen laws, as does Rule #3. Just because you could write something like this:


 for ($i=0;$i<=$#blah;$i++){if ($blah[$i]~=/punk boy/g;)



 {print  "I hate this code";}else { print "nappy";}}



… doesn’t mean you should. It may not create any errors, but it’s difficult to read, not to mention just plain ugly. Even with comments, it would take a person days to figure out that this is nothing more than a “for” loop, running through the “blah” array, looking for the phrase “punk boy.” If the phrase exists, it prints “I hate this code”; if it doesn’t, it prints “nappy.” It’s a lot prettier and easier to understand if you do it like this:

 for ($i = 0; $i <= $#blah; $i++) {



 	if ($blah[$i] ~= /punk boy/g;) {



 		print "I hate this code";



 	}else {



 		print "nappy";



 	}



 }

All clear? Don’t worry, Grasshoppper; you’ll get it.


Get Down and Boogie!

If you’ve ever used any other programming language, then you’re probably familiar with if/else statements. If not, here’s a brief explanation. If/else statements test to see if something is true or not:”If” it is, then the script will do one thing. Otherwise, it’ll do something “else.” Pretty keen, huh?

Here’s how an if/else statement is written:

if (statement) {



	task



} elsif (statement) {



	a different task



} else {



	a task if all else fails



}



Once you understand the basic concept of if/else, you’re ready to explore the wonderful world of variables.

Scalers, Arrays, and Associative Arrays

All variables are one of three different types:scalar, array, or associative array. What’s the difference? A scalar variable is the catch all. It can hold numbers, letters, phrases, whatever. It always has a “$” (dollar sign) before it. So if I wanted to assign a value to the variable $stuff, here’s how I’d do it:




A word:$stuff = "rules";



A phrase:$stuff = "Colin Rules!";



Numbers:$stuff = 2;



You can even add and subtract like this:


$stuff = 2 + 2;



$stuff = 4 - 2;



$stuff would then equal 4 and 2, respectively.

Assignments to variables always happen from left to right. 2 + 2 = $stuff; is not only invalid, it’ll get you killed in some neighborhoods. I’m not kidding around.

An array variable is a variable that holds many scalar variables in numbered slots. These slots are added as needed so the variable can grow dynamically. It can shrink, too, but that’s just a waste of time. Array variables usually have the @ (at symbol) in front of them. When declaring slots individually, you use a $.

You can declare as many slots as you want right away by doing this:

 @stuff = ("1","2","ten","Colin Rules","Perl's for winners"); 

To get at each slot, you call it by number. So $stuff[3] is equal to "Colin Rules", and $stuff[1] is equal to "2". Wait! Why isn’t slot 4 "Colin Rules"? That’s easy. Perl, like JavaScript starts indexing at zero. So $stuff[0] equals "1", $stuff[2] equals "ten", and so on. You can find out how many slots the array has by looking at the built-in variable $#stuff. For instance, the value of the @stuff array we defined above would be 4. (Remember, counting starts at 0.)

To declare one slot at a time, do this:

 $stuff[0] = "2000000"; 

Note that $stuff[0], $stuff[30], or $stuff[whatever] have no relation to $stuff from the example above. The only thing they share is the same name, which doesn’t conflict because the two variables are of different types. Generally it’s good form not to give your variables the same name — which is a perfect segue into Rule #5, recently recovered in a dig in Harlem of all places.

Rule #5 All variables must be named intuitively. Sure, $a may be much quicker to write than $apple, but when you have to go back later to dissect everything, you’ll have no idea that $a stands for apple.

Name it for what it does. You can use up to 4 million characters (or something like that) to name your variable, so don’t worry about running out of room. And don’t run it all together, either. You can’t use spaces in variable names, but you can use an underscore to separate the words. For instance, $book_page_i_am_on is a lot easier to understand than $bookpageiamon.

What characters can you use in a variable name? Choose from aAbBcCdD to xXyYzZ. But don’t use !, @, #, $, %, ^, &, *, (, ), ~ or any other character that deviates from the alphabet. If you didn’t sing it in kindergarten, don’t use it now.

All righty! The last type of variable is the associative array. Associative arrays are great for storing related information. They are the easiest of the two arrays (in my mind), because you don’t have to remember what slot you stuck something in. Associatives usually start with a % (percentage sign), but like the other arrays, when you call a slot individually, use the $. To declare an associative array, simply do this:

%stuff = ("sport","basketball","bike","trek","name","Don't remember",



"Age","Not old enough to drink");

Every other value in this example is the key to the one after it. So $stuff{'sport'} is "basketball", and $stuff{'name'} is "don't remember", and so on. To declare one slot at a time, do this:

$stuff{'girlfriend'} = "Looking. Any leads? Call me";

OK, now you’ve got those variables, but what good are they unless you can compare them to something? No good:That’s what! To give those variables a purpose, you need Perl operators.


Perl Operators – What Number Please?

Without operators, there is no point to scripting. Assigning values to variables and stuff would serve no purpose, unless you just wanted to rename the number one $that_number_that_I_can_never_remember – and we all have to admit that’s a little bit stupid, right?

There are three different types of operators:assignment, comparison, and mathematical. Assignment operators give a value to a variable, comparison operators compare two values and give a third value based on what they find, and mathematical operators do the math so you don’t have to. And here they are:

Assignment Operators

= Makes the value of the variable on the left side equal to whatever is on the right.
+= Adds the value of the right side to the left side and makes the variable on the left equal to it.
-= Same as above, only subtracts instead of adds.

Comparison Operators

< Returns a true value if the value on the left is less than that on the right. Otherwise false.
> Same as above, but the other way around.
>= Returns a true value if the value on the left is greater than or equal to that on the right. False if not.
<= Are we seeing a pattern here?
== Returns a true value if the values on both sides are equal; otherwise returns a false.
eq The same as above, but rather than comparing values, it compares strings of text.
 != Returns a true value if the value on the right is not equal to that on the left. False if they are equal.
ne Again, same as above, but for strings of text.

Comparison Operators are perfect for those if/else statements I talked about. They work something like this:

 #I assign the value of 5 to $stuff.



 $stuff = 5;



 # Then I compare it and react to its value.



 if ($stuff < 5) {



 	print "Runt!";



 } elsif ($stuff >= 6) {



 	print "Too big, man!";



 } else {



 	print "I guess that'll do.";



 }

Mathematical Operators

* Multiplies the two values together.
/ Divides two values.
+ Adds two values.
- Subtracts two values.
++ Adds 1 to the value on the left (so if $i were equal to 1, $i++ would equal 2).
Subtracts 1 from the value on the left.

You get the idea. Of course, with the exception of the last two operators, mathematical operators aren’t any good unless you use an assignment operator for storing the value. For these to be of any use, you’d have to do something like this:


 $stuff = 5 * 3;



With This Loop, I Thee Wed

So you know if/else, you know variables, and you know assignments, but I bet you don’t know loops. That’s right, my friend, you’re not there yet. Even the Karate Kid had a few things to learn from Mr. Miagi.

Anyone who has used a computer language should be familiar with the format of loops. If not, don’t worry too much about it, because I’m paid the big bucks to show you how it’s done.

Loops fall under a part of scripting with the apt name “command structure.” Usually loops form the body of the script, which sends out the information and instructions to the rest of the script. Loops repeat again and again and stop only when certain parameters are met. Enter Rule #6.

Rule #6: All loops must end. It sounds simple, and for the most part it is. You just have to keep track of your variables through every step of the loop (revisit Rule #3).

The essential format of a loop looks like this (although they can include if/else statements and even more loops):

command (statement) {



	statements;



}

The basic kinds of loops in Perl are the for loop, the while loop, and the foreach loop.

The For Loop

The for loop is, without a doubt, my favorite loop because it’s elegant and self-contained. I fell in love with it while working with JavaScript and continued the affair through Java. It still burns strong with Perl. Its format is the most complicated of all of the loops, but complexity in computing usually means more power — or that’s what I keep telling myself. Here’s what it looks like:

for ($i = 0; $i <= $#stuff; $i++) {



	print "$stuff[$i]";



}

In the for loop, you define a variable that exists only within the loop. It doesn’t have to be called $i, but it’s a stand-by variable for incremental variables. I defined the variable $i to equal 0. Then I told the loop to keep looping, as $i is less than or equal to the number of slots in the array @stuff. And then I told it to add 1 to $i at the end of each pass through the loop. Next I had the script print the @stuff array slot that $i represented. So on its first pass through the loop, it would print $stuff[0]. On the second pass, it would print $stuff[1]. This pattern would continue until the condition set was no longer valid.

I love these. My vision of the perfect woman is one who can write a killer for loop and will listen to Pixies songs all day long. (Come to think of it, if you’re out there and you can write a for loop to play a Pixies song, send me a note.)

The While Loop

The while loop is just like the for loop, only not as self-contained. A sample for loop would look something like this:

$stuff = <NAMES>;



while ($stuff ne "bob") {



	print "$stuff";



	$stuff = <NAMES>;



}

This code executes the statements inside the loop as long as the variable $stuff doesn’t equal “bob.” This loop runs the greatest risk of never ending, because it doesn’t rely on a value test to stop as the for loop did. Rather, you have to define a variable outside the loop and have the value change somewhere inside. It’s tricky.

Foreach Loop

Foreach loops are kind of cool. They’re like a lazy version of the for loop. Take a look:

foreach $slotnum (@stuff) {



	print "$slotnum";



}

One slot at a time, this loop will take the lowest value and assign it to $slotnum to be used as a wild-card variable later on. So the @stuff array will start with slot number 0 and go all the way to slot 100 (if there is one). Or it’ll stop if it runs out of slots. The foreach loop is really useful for running through associative arrays since their slots aren’t numbered. Check this out:

foreach $slotname (keys (%stuff)) {



	print "$stuff{$slotname}";



}



This code grabs each key value to the %stuff array one value at a time. (Have you already forgot about associative arrays? Go back to Scalers, Arrays, and Associative Arrays, do not pass Go, and do not collect $200.) It does this by using the built-in Perl function keys and then printing out the value of each slot. Don’t worry:We’ll get to printing. In the meantime, wax on, wax off, wax on, wax off.

Righty-o! Now you’re almost ready to Perl, but you still need something to manipulate.

Getting Manipulative

Without something to manipulate, the only thing you’ve done today is waste your time and sanity. So how do you get the stuff to manipulate? Through a magically wonderful thing called input-output. There are two major types of input and output:user input-output and file input-output.

User input is when the user explicitly tells your script to do something. Output is when the script speaks directly to the user. This is all done through means called standard input and standard output. Input is received by reading the file handle. Even though standard input isn’t a file, the two are handled the same way. You’ll see what I mean when we get to file input-output. Standard input is read like so:




$usersaid = <STDIN>;



File handles are always written in uppercase so they can be easily identified. File handles are the script’s representation of an opened file. Standard input and output are always considered open, so you don’t need to open or close them like the regular files I’ll show you in a minute. The statement $stuff = <INPUT>; would read one line of input into the variable $stuff from the file handle INPUT. The above line would present the user with a line to enter input. Then whatever was entered would be saved in the variable $usersaid.

The print command you’ve seen me use in previous examples is the standard method of outputting information. The print command is set by default to print out to the standard output, so you don’t need to specify it like other file handles. To print the user’s input back out onto the screen, you’d use:

print "$usersaid";

So with this in mind, you could put together a nice little guessing game:

#!/usr/local/bin/perl



print "nPlease enter a number:";



$guess = <STDIN>;



while ($guess != 20) {



print "nSorry! You guessed wrong sucka! Guess again!";



$guess = <STDIN>;



}



print "Damn! You got it!";

By using the while loop, we tested for the user input of $guess and kept looping until they got it right. And believe me, this isn’t even the most irritating thing you can do! To make sure this little torture device is nice and easy for your victim to read, drop in some line breaks with n, which is the character that makes new line in Unix.

You can do file input and output with just a few extra steps. You first have to open a file, kinda like the way you have to open a can of good old Dr. Pepper. Like me, you always give each can a name. Then you go looking for it in the proper place in the fridge by calling out its name. So think of a witty yet descriptive file handle, know the path to the file, and use the open command. Here’s how it’s done:

open (NAMES, "/usr/people/ferm/names.txt");

Once the file is open, you can read in one line of the file at a time (the same way you would with user input above) by doing this …

$fileinput = <NAMES>;

… and storing it in a single scalar variable. Or you could read the whole thing into an array, with each slot as a separate line:

@fileinput = <NAMES>;

Are you with me so far? File input has to be opened first. Then read it either one line at a time, or all at once. So once you’ve got the data, be sure you close the file handle in case you want to write back to it some day. And this brings me to Rule #7.

Rule #7: It explicitly states that you cannot read and write to the same file at the same time. Closing is one line that looks something like:


close (NAMES);

There are two different modes for writing to a file:writing and appending. Writing deletes the contents of the entire file and writes over the file. Or if the file doesn’t already exist, it creates a new file in which to dump the info. Appending adds the new information to the bottom of an existing file.

It’s like this:Writing’s like having a dead guy named Jerry. If there’s already a Jerry in the graveyard, then you dig up the old Jerry and dump in the new Jerry. Or you can dig a new hole if one doesn’t already exist. Appending is like throwing both Jerrys into the same hole. Nothing’s sacred here, pal.

Writing:

open (OUTFILE, ">/usr/people/ferm/perllog.txt");

Appending:




open (OUTFILE, ">>/usr/people/ferm/perllog.txt");

Once you decide how you want to write to a file, you have to print out to the file handle. It’s just like printing out to the standard output, except that you specify explicitly where you want to go by putting the file handle between the print and the actual output:

print OUTFILE "Here's a line of output";

And don’t forget to close that file!


Additional Functions

Great, you’ve almost got it. Just look at you! My little Perl Jedi! Of course, even a Jedi needs a few weapons. Here’s a few extra things to help you write the perfect Perl script to master the Force and all that garbage.

Splitting

Splitting is a function that will save you lots of time and money (well, time, at least). It looks for a pattern in a string and splits up the string into an array based on the pattern. Have a look.

 #!/usr/local/bin/perl



 # I have a string.



 $stuff = "Colin is so cool";



 # I decide that I want to split it up by spaces into an array.



 @stuff = split (/ /, $stuff);



 # I then want to print out each slot on a different line.



 for ($i = 0; $i <= $#stuff; $i++) {



 	print "Slot $i:$stuff[$i]n";



 }



 # Find out how many words there were like this.



 print "There were $#stuff words.n";

Play around with this tool a little bit, and you’ll find out just how useful it really is.

Search and Replace

If you always misspell the same words as I do, then you’ll love Search and Replace. Here’s how it works:Place =~ s/searchstring/replacestring/gi; after the string you want to run Search and Replace on, replacing searchstring and replacestring with the items you want searched and replaced, like so:

 $stuff =~ s/bad/bad bad leroy brown/gi;

So if I wanted to fix all my “e”s before “i”s, I might do something like this:

 # I have this string:



 $stuff = "beleive releive greive";



 # I want to fix all the mistakes.



 $stuff =~ s/ei/ie/gi;



 # Then I want to print out the output.



 print "$stuff";

The niftiest part is that you have a couple of different options with this tool. At the end of statement, there are two letters:”g” and “i.” Those are two options:”g” tells the command to search and replace all occurrences of the string, and “i” tells it to ignore case. One other cool option is the “o” option, which only replaces the first occurrence. (It’s the opposite of the “g” option.) You can use one, all, or none of these options with the command.

Quick Search

Last, you can even use it to tell if something is in a string. Say that you wanted to do something only if the string contained the word “cool.” The hard way to do this is to split up the string and run a loop through the array, looking for the word. Thankfully, there’s any easier way:a quick search.

 $stuff =~ /cool/

This statement would return a true value if the string contains the word “cool” and return a false value if it didn’t. You can also do the reverse:


 $stuff != /cool/



… which would return a true if the string doesn’t contain the word “cool” and a false if it does. Then you can use it in an if statement like so:


 if ($stuff =~ /cool/) {



 	statements



 }



All kinds of niftiness!

Now that I’ve given you a taste of Perl, no doubt you’re probably jonesing to actually do something with it. Read on to learn how to turn Perl into CGI.

Lesson 2:Turning Perl into CGI

So now you have the Perl basics down, and you’re no doubt itching to put that know-how to work. Well, being acquainted with Perl’s one thing, but turning Perl into a keen CGI script is a whole ‘nother ball of wax. Hence, Lesson Two of Colin’s wonderful world of scripting.

These days there are all kinds of super wonderful libraries and Perl Modules that can make CGI scripting easier and niftier, but we’re all about basics here today. My daddy once told me that you’ve got to learn to walk before you can river-dance. So today we’re going to stick to super basic, almost prehistoric, though still really nifty Perl to put together today’s little project. Tune in at a not-so-distant-future date when this simian will take a look at the Perl CGI module.

Before we begin, there are a few more things you must know before you tackle phase two.

  1. You need to know how to make a form in HTML. If you can’t to do this yet, learn it and come back. It’s really easy and should only take five minutes to learn (ten if your last name’s Gump).
  2. Scripting requires a certain concentration, which can be brought on by the right music. Personally, I’ve found The Pixies and They Might Be Giants to be proven script enhancers.
  3. CGI is frustrating. Rather than lash out at a co-worker, little brother, or computer, a big heavy punching bag can help ease the strain. (Of course, if things prove too much for you, you can always go back to stealing other people’s scripts.)

And that should do it. With these things under control, you’re ready to jump into today’s lesson. We’ll examine the differences between Perl CGI and Perl scripting, and we’ll build a small script to illustrate just how nifty CGI really is.

The CGI Difference

CGIs process input differently than old Perl scripting does – and this, my friends, is the only difference you’ll find between the two. Once the CGI scripts process the input, it becomes data, which is treated pretty much the same way by both CGI and Perl scripts. CGI input can be retrieved in two different ways:”get” and “post.” If you’re absolutely sure what type of input you’ll be getting, then you only have to use one type of input retrieval. But if it’s the least bit possible that whoever writes the form won’t mark the input type correctly (and really, who knows what they’ll do), then you have to catch all the possible types of answers. This involves a simple two-step process, handled with an if/else statement.

    if ($ENV{'REQUEST_METHOD'} eq "GET") {



    		$in = $ENV{'QUERY_STRING'};



    	} else {



    		$in = <STDIN>;



    	}


This statement asks the server if the request method (the way in which the server gave you the information) is “get.” If so, the script will read the information from the Query String into a variable called $in. Otherwise, it’ll read it in through standard input just like it would a normal Perl script.

Just Like in the Movies

For your CGI-learning enjoyment, I’m going to show you how to write a little movie-review search script. It’s the perfect thing for the web page of a true movie buff. But don’t worry. If movies aren’t your thing, this script will work just peachy with a music collection; your spores, molds, and fungus collection; whatever).

Before we build the CGI, we have to name our input. One of the first things to learn about CGI scripting is that the more complicated you make something, the more likely it is that users won’t understand how to use it. So let’s keep things nice and simple and start with a form that accepts only one kind of input:the title of the movie. Let’s name that form field “title” (see? no surprises). So on our Web page we have:

Please input the title of the movie you want to hear me rant about. It can be all caps, lowercase, whatever, but leave those “The”s right where they are. So if you’re looking for “The 5,000 Fingers of Dr. T,” type in the The before 5,000 Fingers of Dr. T. Or if it’s “They Live” you seek, you can type in THEY LIVE, they live, They Live, and so on. Got it?

You’d do this with the following HTML:

    <form action="/cgi-bin/webmonkey/crazymovie.cgi">



    <input type="text" length="20" name="title"><br>



    <input type="submit" value="Search The Crazy Movie Megabase!">



    </form>

So now we look for the title in my “database.” Again, to keep things nice and simple for this example, we won’t play hardball with an actual database; there is no Oracle or SQL backend to this. We’ll do everything with a “flat-file” database, which is just a collection of plain text files organized so that it’s easy for the script to parse. Flat-files aren’t good for really detailed searches or huge amounts of data, but they won’t set you back several thousand dollars on hardware and software, either.

To pull info from our flat-file database, we have to know what the input from the database is going to look like so we can build the CGI around it. The format for each entry that I’ll use will look exactly like this:

---- movie title ---- [lowercase]<br />

movie title [how I want the user to see it, minus HTML tags]<br />



movie description [no hard line breaks with <tt>n</tt>, but <tt> p¢</tt> tags are OK]

So I’ve declared the formatting rules for my database, and both the data and the script must conform to these rules. They might seem a little anal, and I suppose they are. But believe me, the more rules you set before you input all your data, the easier things will be later. Scripting is a structured activity, and rules help define the structure.

Once I have my database | ready to go, I can make things happen with the user input I get from my form.


Tidying Up the Input

To search for the info that corresponds to the user “title” input, we’ll open the database in the same way we would any other file in Perl. Then we’ll read it into an array variable and, of course, close the file.

open (DATA, "/usr/people/ferm/movies.dat");



    my @data = <DATA>;



    close (DATA);

The script now has the all the info from the database, and it’s ready to scan for the specific info that matches the user input. We gave the user explicit instructions about how to type in the title of the movie, but you’ll be amazed at how varied the input will actually be. To figure out what the hell the user’s talking about, we’ll just use the catchall that I showed you earlier.

Here’s what it looks like:(Note my use of comments. You should use ones just like these; you could even provide a little more detail. They’re extremely helpful.)

 # Always remember to put this line at the top!



 #!/usr/local/bin/perl



 # This opens the movie database and saves it into the @data variable.



 open (DATA, "/usr/people/ferm/movies.dat");



 my @data = <DATA>;



 close (DATA);





 # Have we forgotten already? This gets the input regardless of what



 # method was used and stores it into the $in variable.



 my $in;



 if ($ENV{'REQUEST_METHOD'} eq "GET") {



	 $in = $ENV{'QUERY_STRING'};



 } else {



	 $in = <STDIN>;



 }



Of course, the user’s input often needs a little massaging or tweaking. First off, we want to make sure that we don’t have any funky characters that are sometimes created when input is translated into URI-readable code. (URI is the code that certain nonalphanumeric characters are translated into when the form is submitted, and it’s the browser’s ideal method of passing the info to the CGI.) To vacuum up any junk that may inadvertently be created, do this:

    $in =~ s/%(..)/pack("c",hex($1))/ge;


This is a search-and-replace command that looks to see if any characters start with % and converts them into characters you and I can read. Then it leaves you with sweet-smelling input.

All right:Now we’ve got normal text, but there are still some problems. If the title is more than one word long, the $in variable’s going to have “+” signs where the spaces should be. So:

    $in =~ s/+/ /g;


This is another standard, Perl search-and-replace function that searches out and destroys any “+” signs and replaces them with a space.

Finally, we need to move the data out of the variable $in, and give it a more descriptive name.

    my %movie = split (/=/, $in);


This code splits up the line into the associative array %movie. Since the name of the form field was “title,” the data is stored in the slot $movie{‘title’}. While not strictly necessary, it helps me keep track of what’s going on.

Now that we have the data, it’s time to do something with it.

Match Making (The Meat of the Matter)

Now that you’ve mushed your users’ input around like Play-Doh, it’s about time you give them something in return. Since your database doesn’t have any real formatting of its own, drop the HTML formatting around the text you retrieve. Printing out to a web page is just like printing out to standard output, except you can use HTML tags. The one thing you need to do when you print out to a web page is tell the browser what it’s getting in return. In this case, it’s getting HTML, so you need to add …

    Content-Type:text/htmlnn



… in the first print statement sent out to the user. The user won’t see it, but the browser will, and that’s the important thing. (But make sure you send it out on only the first print, or the user will actually see it. It’d be lame to have Content-Type:text/htmlnn printed a thousand times all over the page. So with that one exception, we’ll print the header of our results page like so:

    print <<END;



    Content-Type:text/htmlnn



    <html>



    <body bgcolor="#000000" text="#ffffff">



    <center>



    <h2>Results</h2>



    </center>



    <p>



    END

Notice that I used HTML within my CGI. It’s just like writing a normal HTML page in fragments, except this is done with print tags. I can make it as complicated as I want to, using every single HTML tag in the book, but we’re learning CGI, not HTML, so I’m just showing you enough to give you the picture.

We still need to display the information the user is looking for. So far we have the user info in one variable and the database stored in an array variable. Now we need to run through the array and try to match the titles. If a title is matched, we’ll print out the info; if it’s not, we’ll print out an error message.

What’s the best way to run through an array? Well, you could use a for or a foreach loop. I get a personal sense of gratification when I use a for loop, so that’s what I’m going to use here, although either is acceptable.

for ($i = 0; $i <= $#data; $i++) {



    }

This runs through the slots in @data until no slots are left. Then it quits. Now we need to check whether the title is stored in an entry.

if ($data[$i] =~ /-- $movie{'title'} --/i) {



    }

If there is indeed a match, we’ll use something like the following code inside the if:

    print <<END;



    <b><font size="+1">$data[$i + 1]</font></b><br>



    $data[$i + 2]<br>



    END



    last;

What we’ve done here is find the correct title by using the line of dashes I placed in the formatting of my database files, and that’s line $i. The actual content we want to display, the title and the review, is found in the two lines after the dashed line. We’ll print out that content by adding 1 or 2 to the $i variable. Once again we’ll surround the output with HTML formatting to make it all pretty.

So if the dashed line was on line 32, $i would be set to 32. To get the title of the movie without the dashed line, you would add 1 to $i because it is on the line below:line 33. To get the review of the movie, which resides in the third line of my database entry, line 34, you’d have to add 2 to $i. However, note that we’re using a mathematical operator, not an assignment operator. So the value of $i would still be equal to 32. Once it prints out the information, it uses the “last” statement to tell the script that it’s got what it needs. Essentially, “last” tells the loop that the pass it’s on is the last pass, so it should break out and quit the loop.

Of course, the above scenario assumes that the information requested is actually found within the little database we’ve constructed. That’s not always the case. What if the user requested some obscure German film from 1928? Chances are you don’t have it in there. You get bonus points if you do; major bonus points. But let’s say you don’t. You need to add another statement to take care of that. This job would best be handled as an “elsif” statement appended on to the if written above. That way, it would be triggered only if the script was on its very last pass and hadn’t found a match yet.

    if ($data[$i] =~ /-- $movie{'title'} --/i) {



    print <<END;



    <b><font size="+1">$data[$i + 1]</font></b><br>



    $data[$i + 2]<br>



    END



    last;



    } elsif ($i == $#data) {



    }


This code says if $i equals the number of slots in @data and the title wasn’t in that slot, then do whatever. But what is whatever? It’s always better to come right out and tell users that you don’t have what they’re looking for than to lie to them about it. Of course, the final decision is really up to you. So, between the brackets is where you explain why their searches aren’t providing any results.

    print "<b><i>Sorry! I haven't reviewed that one yet!</i></b>";



And with that written, you’re done with the bulk of the script. Here’s how the thing looks all together:


for ($i = 0; $i <= $#data; $i++) {



	  if ($data[$i] =~ /-- $movie{'title'} --/i) {



		  print <<END;



  <b><font size="+1">$data[$i + 1]</font></b><br>



  $data[$i + 2]<br>



  END



		  last;



	  } elsif ($i == $#data) {



	    print "<b><i>Sorry! I haven't reviewed that one yet!</i></b>";



	  }



  }


Finish things off with the footer, which you address just like you did the header:

print <<END;



<center><hr size=1 width=50%></center>



</body>



</html>



END

It’s a Wonderful CGI Script!

With your script all written and your database in place, you’re probably chomping to see it all work. But the most important thing to remember with CGI scripts is to make sure they’re stable. Always have a trusty engineer take a look at your scripts to make sure they don’t do anything stupid.

Once you get the go-ahead, put ‘em up and push ‘em live. If you want to see everything all in one place, take a look at the | finished code (cut and paste at will).

So there you have it:Your very own, living, breathing CGI script. As you can see, most of CGI is just standard Perl, with a few changes here and there to give it that bonus CGI flavor you have to pay so much extra for at Starbucks.

So with the power of CGI firmly in your paw, what’re you going to do with it? Well, that’s up to you. The mighty CGI knowledge has been known to drive some mad. I know many scripters, who having learned the art, decided to head into the thickest forests they could find to build shanties and bombs. Knowing how to script CGI is the easy part of the equation. The toughest part is figuring out how to use your power to do something worthy, while maintaining your sanity and the sanity of the sysadmins who oversee the machines that run your scripts.