Using a flat-file database in Perl

Monday Aug 30th 1999 by Jason Shindler
Share:

Web developers often need ways of speeding up the development process, without spending thousands of dollars for software. Here's how to build an easy to use database in Perl and access it via a Web page.

A Poor Man's Database

Huh? What's that?

You've all heard of a Poor Man's Copyright: when you come up with a great idea and you send it to yourself in the mail to prove it was your idea. Getting a real copyright can be a pain, and sometimes isn't worth the effort. A poor man's copyright doesn't have all of the benefits of a "real" one, but for the small stuff - it usually gets the job done.

When designing a website, the same sort of problem can arise, you have a project that needs a database setup, but you either don't have the money for a database package, or it's such a small database, that using a commercial package isn't worth the trouble.

Here's one such scenario: I was designing a site for two movie theaters in Georgia. They wanted their movie showtimes on their site, with a link to the movie's website, a picture, a rating, etc. I tried doing it the old fashioned HTML way, but I found that I was typing in the same information over and over, (after all, Kate Winslet is always a star of Titanic). They change the showtimes 2 or 3 times a week, so I found myself typing in that information too many times. The approximately 10 movies a week certainly didn't merit a Microsoft SQL or Oracle. So I decided to use a series of small text files as a database instead.

Why Perl?

Perl is an interpreted language that's available on most web server packages. It's not platform or operating system dependent, and it's easy to learn and use.

OK-This is a great idea. What do I need?

The recipe calls for 2 cups of sugar, 2 ounces of chocolate and...

  • 1 web server with FTP access: It must have CGI and Perl capabilities (most modern web servers do). A "small business" account from an ISP will generally work, Geocities, Tripod or Angelfire accounts will not; they don't have CGI access. A note about Windows NT IIS servers -- your server's administrator may need to add the Perl language to the server. A free copy can be downloaded from ActiveState Tool Corp
  • 1 copy of WS-FTP, or another FTP program that supports CHMOD. All scripts will need to be set to "7-5-5" which means you should check all boxes in the owner column, and the read and execute box in the group and other columns.
  • 1 copy of CGI-LIB.PL. This is a Perl library that will make your HTML forms useable in a Perl Script.
  • Knowledge of a programming language: You don't need to know Perl, but this article assumes that you know variables and loops and other common programming concepts.
  • Know where the Perl program is located on your web server. Also know the path to your documents. A quick email to your system operator should get you these pieces of information. Still not sure? There's more information about this later on in this article. A note about Windows NT IIS servers -- on a properly configured NT server, knowing where Perl is located is not necessary

Some quick Perl basics

Perl is a multipurpose language. It has lots of other uses besides what we are doing. So, if you are looking to learn Perl and all of its uses, go here. Likewise, if you know Perl already, you can skip this section and go to "Getting Started - The HTML".

All variables start with a $. Well, that's not true. Perl has other types of variables, we just won't be using them. As a side note, if you are interested in the Perl language itself, visit your favorite computer bookstore and ask for the "Camel book" -- it's published by O'Reilly, has a camel on the front cover, and is the definitive reference on Perl. Variables can be as descriptive as you would like.

Examples:

$Customer 
$Employee1 
$Phone_number

To open a file, use the open command.

Syntax:

open(TAG, "path/to/file") 
     or die "Message to	print when 
             the file can't be opened";

TAG: A short phrase for referring to this file in other parts of the program.

path/to/file: This is where you need to know the path to your douments. In most cases this will just be the file's name (see example). This path varies widely on different systems. If you are not sure, contact your system administrator.

Message to print when the file can't be opened: Self explanatory. Use \n to print a new line. $! Prints the error message.

Example:

open(THEATER, "theater.data") 
   or die "We could not open the Movie 
          Theater Information file.\n 
          Please email the webmaster
          with the following 
          information:\n$!\n";

Note: Our examples are word wrapped for formatting purposes. All Perl lines end in a semicolon, so when using this code in your programs, make sure each line ends in a semicolon.

We'll be reading input from a file. Our file will have text seperated by semicolon. If this bothers you (or more importantly conflicts with some of your data, use a comma or some other character. After each file is opened, change the semicolon in the split statement to that character.

People will use your Perl program just as they do any HTML file - so you'll need to print your output in HTML. To do this:

Print >> EOF;
<PUT HTML HERE, USE AS MANY 
        LINES AS NEEDED>
EOF;

Also note: before the first part of your output, insert this line.

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

Getting Started

The HTML

Before writing anything in Perl - you'll have to have some way of accessing the Perl program from your existing HTML pages. There are two ways to do this.

  • You can use HTML forms. Ask the user to specify which theater and which day they want to search for. They choose from a list using HTML forms.
  • Just specify a URL. This is the simplest and requires less user interaction.

For example:

http://domain.com/cgi-bin/moviewizard.cgi? showdate=07011999&theater=1

Put a link similar to this one in your HTML. This will work in some simple cases, but the first choice is far more flexible.

On to the Perl

To start the project, we must start two header lines. The first tells the system where to find the Perl executable (this may vary on some systems). The second line tells Perl to import the libraries that will translate the HTML form output into Perl.

#!/usr/bin/perl
require "cgi-lib.pl";

Next we have to import in the HTML form output. The first line is the only necessary one. The rest of the lines just save time later. For instance - if you include the optional lines, you could write $printerver later in your script instead of writing $input{'printerver'}.

ReadParse(*input);
$datetosearch = $input{'showdate'};
$showthisdate = substr($input{'showdate'}, 0, 2);
$showthisdate1 = substr($input{'showdate'}, 2, 2);
$showthisdate2 = substr($input{'showdate'}, 4, 4);
$theater = $input{'theater'};
$movienum = $input{'movienum'};
$t = $theater

This is some more "getting started" stuff. This section of code imports the current system time into a series of variables.


($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$thismonth = $mon + 1;       # month in perl is 0-11, must add 1
$thismonth1 = (Jan,Feb,Mar,Apr,May,June,July,Aug,Sept,Oct,Nov,Dec)[$mon];
$year = $year + 1900;        # After year 2000, year comes in form 
                             # 100 = 2000, etc. So this works
if ($thismonth < 10)
   { $thismonth2 = join '', 0, $thismonth; }
else
   { $thismonth2 = $thismonth }

if ($mday < 10)
   { $thisday = join '', 0, $mday; }
else
   { $thisday = $mday; }

$time0 = (join '', $thismonth2, $thisday, $year);

On our HTML pages, the user has the choice of picking a specific day to view or one can choose "today." This part computes what the day is and puts it in the appropriate variables for computations. The $showthisdate = substr($time0, 0, 2) command takes the variable $time0, starts reading at character 0 (the first one) and reads for two characters and returns the information into the variable $showthisdate.

if ($input{'showtoday'} eq "yes")
   { $datetosearch = $time0;
   $showthisdate = substr($time0, 0, 2);
   $showthisdate1 = substr($time0, 2, 2);
   $showthisdate2 = substr($time0, 4, 4);
   }

Now, we must start bringing in the data from our text files, which -- in this case - contain information that is specific to each theater. We'll repeat a similar process for each of our flat-file databases. In our example, they include information about each movie, each showtime and each movie studio. Other applications of this technique might include a list of recipes (with ingredients, instructions, etc.), or a list of contacts (with names, addresses, etc). This piece of code cycles through each line in the file and extracts this information into a series of variables. Everytime it hits a semicolon in the file, it puts the next information from the file in the next variable. Every time it hits a line break, it increments $t and starts the process over again. It ends the loop when there are no more lines.

open(THEATER, "theater.data") 
   or die "Domain.com could not open the Movie Theater Information file.\n
           Please email the webmaster at domain.com with the following 
           information:\n$!\n";

while ($line = <THEATER>)
{
   ($theaterpic[$t], $adultprice[$t], $childprice[$t],
    $seniorprice[$t], $matineeprice[$t], $message[$t],
    $phone[$t])	= split /;/, $line;
   $t++
}

The process is repeated for the movie text file. Note the variable names are different. They indicate the different information that comes from this file.

open(MOVIE, "movie.data") 
   or die "Domain.com could not open the Movie Information file.\n
           Please email webmaster at domain.com with the following 
           information:\n$!\n";
$d=1;
while ($line = <MOVIE>)
{
   ($name[$d], $website[$d], $starring[$d], $runtime[$d],
    $s[$d], $pic[$d], $rated[$d], $plot[$d]) = split /;/, $line;
   $d++
}

The next lines print the HTML output, part 1. In this area, you'll want to put any information that is the same for every page the program prints. A standard menu that runs atop the page is an example of something that might go in here. In this example, this includes HTML headers, theater information (which is reliant on the information gleaned from the text file on the previous page), and the top part of the showtimes table. The information from the text files is used in the HTML simply by typing the variable's name. For instance, to use the $showthisdate variable we created before, simply type "$showthisdate" in your HTML and Perl will insert the right information. For brevity, this part of the example is in a text file.

Note: This ability to use variables inside the HTML has one noticable disadvantage: Anytime you use a character in your HTML that is also used in Perl to represent varaibles, you must add a backslash. For Instance: to write $3.83 in your HTML, you must write \$3.83 instead. This must also be done for @, as "at" is used for other Perl variables.

This next segment imports the studio information from a file, just as we did for the theater information before.

open(STUDIO, "studio.data") 
   or die "Domain.com could not open the Studio 
           Information file.\n
           Please email webmaster at domain.com 
           with the following information:\n$!\n";
$s=1;

while ($line = <STUDIO>)
{
   ($studioname[$s], $studio[$s], $studiourl[$s])
    = split /;/, $line;
   $s++
}

Now the showtimes data file is more complicated. We input the information as before. But, as we cycle through each line of the file, we also set some other variables for later use when writing each line of the table.

open(SHOW, "showtimes.data") 
   or die "Seethemovies.com could not open the main 
           Showtimes file.\nPlease email webmaster 
           at domain.com with the following 
           information:\n$!\n";
$b=1;
while ($line = <SHOW>)
{
   ($bdate[$b], $edate[$b], $m[$b], $digsound[$b],
    $showtimesm8[$b], $showtimesm400[$b]) = split /;/, $line;
   if ($showtimesm8[$b] != "") {
      $movies8[$b] = 1; }
   else {
      $movies8[$b] = 0; }
   if ($showtimesm400[$b] != "") {
      $movies400[$b] = 1; }
   else {
      $movies400[$b] = 0; }
   if ($theater eq 2) {
      $movies[$b] = $movies400[$b];
      $showtimes[$b] = $showtimesm400[$b];
   }
   if ($theater eq 1) {
      $movies[$b] = $movies8[$b];
      $showtimes[$b] = $showtimesm8[$b];
   }
   $b++
}

Next, we cycle through each value in the array of showtimes and check to see if it meets the characteristics we're looking for. In this example, we check if the showtime is for the right theater and is valid for the day we're searching for. It then displays the movie and showtime specifics for that particular showtime, using the same technique used above (recall: to use information from our text files, simply write the variable's name inside the HTML).For instance, a user might ask for January 25. If the date range is between January 1 and January 10, it won't display anything. If it's between January 20 and January 30, it will. The loop in this section of code terminates when $c >= $b; in other words, when each line that was imported into from the text file has been processed. Note: The use of "$pic[$m[$c]]" may look confusing (it is supposed to return the picture that corresponds to the movie specified on the line of showtimes the script is processing -- so it also sounds confusing). But by thinking logically, it is easy to see what's happening. Perl evaluates $m[$c] first, and returns a number (which is the number of the movie), then Perl evaluates the number like this "$pic[<NUMBER>], thus returning the correct picture.

# $c is incremented until the last showtimes.data
# line has been processed
$c=1;
while ($c < $b ) {
   if ($movies[$c] eq "1" && 
      ($bdate[$c] <= $datetosearch) && 
      ($edate[$c] >= $datetosearch) {
      print <<EOF ;
      <TR>
       <TD WIDTH="20%">
        <CENTER>
         <H2>
          <A HREF="http://domain.com/cgi-
bin/moviewizard.cgi?movienum=$m[$c]&showdate=$datetosearch">
$name[$m[$c]]</A><IMG
SRC="http://domain.com/images/ratings/$rated[$m[$c]].gif" 
NOSAVE BORDER=0 HEIGHT=35 WIDTH=47 ALIGN=ABSCENTER></H2>
        </CENTER>
        <CENTER><IMG SRC="
http://domain.com/images/movies/$pic[$m[$c]]">
        </CENTER>
        <CENTER><B><FONT COLOR="#800080">$digsound[$c]</FONT></B></CENTER>
       </TD>
       <TD>
        <CENTER>$runtime[$m[$c]]</CENTER>
       </TD>
       <TD WIDTH="20%">
        <CENTER><FONT SIZE=+1>
          $starring[$m[$c]]</FONT></CENTER>
       </TD>
       <TD WIDTH="20%">
        <CENTER>$showtimes[$c]</CENTER>
       </TD>
       <TD WIDTH="20%">
        <CENTER><a href=$studiourl[$s[$m[$c]]]><IMG SRC="
http://domain.com/images/studios/$studio[$s[$m[$c]]].gif"
NOSAVE HEIGHT=60 WIDTH=115></CENTER></a>
</a>
       </TD>
      </TR>
EOF
   }
   $c++
}

Simple stuff again at the bottom. Insert any HTML footers or menus that run at the bottom. Take note of the \@ used instead of @ when displaying an email address in the HTML. As noted earlier, this avoids confusing between an email address and variables that start with @ in Perl. Note: If you do not do this, you WILL get an "Internal Server Error".

print <<EOF ;
</TABLE>
<p><b><font size=4><center>
$message[$t]</b></p>
<P><BR><B><FONT COLOR="#3333FF"><FONT
SIZE=+1>Copyright 1998&nbsp;</FONT></FONT></B>
<BR><B><FONT COLOR="#3333FF"><FONT
SIZE=+1><A HREF="mailto:norman\@domain.com">MnM
Entertainment</A> &amp;</FONT></FONT></B>
<BR><B><FONT COLOR="#3333FF"><FONT
SIZE=+1><A HREF="mailto:webmaster\@domain.com">Jason
Shindler</A></FONT></FONT></B></CENTER>
</TD><TD COLSPAN="4">
</body>
</html>
EOF

That's it! Your script is finished :)

From here....

You've mastered some basic Perl and hopefully designed a script that meets your needs. We've learned how to read from files, from here it might be useful to write to files as well. To take this example, one could write additions to this script that allow users to write comments about each movie and rate the movie on a scale of one to ten.

This method also has several other applications. Among them, you read from text files to put a similar banner or navigation menu on the top and bottom of every page. Simply ask Perl to read in a file that contains your menu, read in another file that contains the data for a specific document and concatenate them together using the familiar Print statement. The opportunities are endless. Happy coding :)

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved