Files and CGI in Perl


Andrew Cantino





Introduction

Last time we were introduced to Perl and some basic Perl programming. Now lets learn about files and online CGI scripts.

Files

An Example

$filename = "/home/acantino/testfile";
open(FILE, "$filename") || die("Unable to open $filename: $!\n");
$firstLine = <FILE>;
$secondLine = <FILE>;
@theRest = <FILE>;
close(FILE);
chomp($firstLine);
chomp($secondLine);
print "The first line of the file is: $firstLine\n";
print "And the second line is: $secondLine\n";
print "Here is the rest of the file:\n";
foreach $line (@theRest) {
     chomp($line);
     print "$line\n";
}

I put the following in testfile:

some first text
some second text
some more
and more
and the end of the file!
Script Output:
The first line of the file is: some first text
And the second line is: some second text
Here is the rest of the file:
some more
and more
and the end of the file!

File Modes

You can open a file in a few different modes. Here's a demonstration:

$filename = "countfile";
open(INPUT, "$filename") || die("Unable to open $filename for reading: $!\n");
$data = <INPUT>;
close(INPUT);
open(OUTPUT, ">$filename") || die("Unable to open $filename for output: $!\n");
print OUTPUT ($data + 1);
close(OUTPUT);

CGI

#!/usr/bin/perl -T
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
use CGI;
$c = new CGI;
print $c->header();
print "<html><head><title>My first script!</title></head>\n";
print "Hello, this is my first CGI script!<br>\n";
$date = `/bin/date`;
chomp($date);
print "The date is: $date\n";
print "</body></html>";

This script can be found online here. There's a bunch of new stuff here, so lets go through it slowly.

Taint Checking

We've slightly modified the shebang line, including a new -T option. Options included at the end of the shebang line are passed to perl when the script is run. The -T option is taint checking, and is a very important security precaution for CGI scripts. I will discuss Perl/CGI security and taint checking on Thursday.

The $ENV{'PATH'}... line is also part of our taint checking, and will be explained on Thursday. Basically, it updates the PATH environmental variable to make sure that it is secure.

Objects

The use command tells Perl to use an external library of code. We've used the external CGI 4 library, which provides some useful code for writing CGI scripts. CGI is a package, which Perl treats like an object. Perl, like most modern programming languages, is object-oriented, meaning that you can create data structures called objects that encapsulate other data structures and functions. I'm not really going to teach object-oriented programming in this class, but we will be using a small amount of it here. All you need to know is that $c = new CGI; creates a new instance of a CGI object and puts it in $c. Once we have an instance of an object, we can access data and functions contained within it via the -> operator.

CGI Headers

When the web server runs a CGI script, the script's output is returned to your web browser. Therefore, anything we print in our CGI script will end up as part of the page that you see when you go to the script in your web browser. However, for your browser to understand what it is receiving, we need to send it a Content-type HTTP header before we send any data. If we don't do this, the web browser won't know whether it's receiving HTML, text, an image, or something else. We could print the HTTP header like this:

print "Content-type: text/html\n\n";
But the CGI library provides an easier method. $c->header() is a function in the CGI package that returns an HTTP header as a string. Therefore, calling print $c->header() prints out that header. See this site for more header() options.

The body of the script

UNIX Permissions for CGI Scripts

If your CGI script runs fine on the UNIX shell (when run with perl script.cgi), but gives a server error when accessed over the web, then a number of things could be going wrong:

#!/usr/bin/perl
chmod 755 scriptname.cgi

Links.cgi script

Now we're going to develop a CGI application.

HTML Forms

A really useful CGI script probably needs to be able to take information from the user. We've all seen online forms that let one fill in information to search, send e-mail, sign a guestbook, or otherwise interact with a website. We're going to be developing a CGI script to collect links on a webpage. Lets first build the HTML form:

<html><head><title>Our form!</title></head>
<body bgcolor=white text=black>
<center><b>Our form!</b></center>
<form method=post action=http://andrew.absurdlycool.com/class/links/links.cgi>
<input name=mode type=hidden value=1>
Url Name: <input name=name type=text><br>
URL: <input name=url type=text value="http://"><br>
<input type=submit name=submit value="Submit!"></form>
<p>
<a href=links.cgi?mode=2>See the list!</a>
</body></html>
See the form in action.

The Perl script

#!/usr/bin/perl -T
$datafile = "/home/acantino/public_html/links/data";
$errorLog = "/home/acantino/public_html/links/error";
open (STDERR, ">>$errorLog");
use CGI;
$c = new CGI();
print $c->header();
$mode = $c->param('mode');
if ($mode == 1) {
        # Take input
        $name = $c->param('name');
        $url = $c->param('url');
        unless ($url =~ m/^http\:\/\/.+?\..+/i) {
                print "Sorry, that is not a URL!\n";
                exit;
        }
        if ($name eq "") {
                print "Please enter a webpage name!\n";
                exit;
        }
        open(OUT, ">>$datafile") || die("Unable to open $datafile: $!\n");
        print OUT $name . '|' . $url . "\n";
        close(OUT);
        print "<html><head><title>Thanks</title></head>\n";
        print "<body><center>Thanks!</center></body></html>";
        exit;
} elsif ($mode == 2) {
        print "<html><head><title>Our Links!</title></head>\n";
        print "<body><center>Here are some links!</center><p>";
        open(IN, "$datafile") || die("Unable to open $datafile: $!\n");
        while($j = <IN>) {
                chomp($j);
                ($name, $url) = split(/\|/, $j);
                print "<a href=\"$url\">$name</a><br>\n";
        }
        close(IN);
        print "</body></html>";
        exit;
} else {
        print "Unknown mode!\n";
}

Whew! To see this script in action, go to http://andrew.absurdlycool.com/class/links/! There's a lot going on here, so we'll walk through it step by step. First of all, can you see what the script does? It's a place where you can leave links for other people 6. People can submit new links and see what's already there. Give it a try!

@array = ('andrew', 'bob', 'tom', 'ben');
$string = join('|', @array);
print $string;

Resources

Here are some useful links for further reading:

Suggested Assignments

Write a CGI script of your own!

You now know enough to write many kinds of CGI scripts. Try a simple one first! Here are a few suggestions:


Back to Course Index


  [1] - Wow, violent language.
  [2] - As will be discussed in the Perl security lesson, it is sometimes advisable to separate the mode and file path: open(FILE, '>', $path)
  [3] - Print always takes a filehandle, but the default handle is STDIO, which is the screen.
  [4] - http://search.cpan.org/~lds/CGI.pm-3.10/CGI.pm
  [5] - http://www.w3.org/TR/REC-html40/interact/forms.html
  [6] - This is sometimes called a link free-for-all.
  [7] - The web server passes the data to us in an environmental variable.
  [8] - If you're impatient, look at 'man perlre'.

This document was generated using AFT v5.094