Fozzologs

RSS Feeds

About...

These posts are the creation of Doran L. Barton (AKA Fozziliny Moo). To learn more about Doran, check out his website at fozzilinymoo.org.

Right Side

This space reserved for future use.

Perl Basics: Using CGI.pm

Posted: 18 February 2009 at 07:55:12

Perl is over twenty years old, but it continues to evolve as a programming language. When Perl 6 is released to the world, we're going to see an incredibly modern language that is adaptable to tackle many of the challenges faced by programmers today including internationalization/localization, Internet networking, object orientation, and more.

But this blog post isn't about Perl 6. This is the first in a series of posts designed to help people ease into Perl as a web development language and is influenced largely by tutorials and seminars I've given in person and online about using Perl as a web development tool.

Perl was embraced for web development in the early and mid 1990s because it had already become a powerful language for text-processing and system administration. As such, it was a natural first choice for developing web applications.

Perl programmers at the time adapted public domain algorithms into Perl code to process HTML forms, but the results were not pretty.


my $hashRef = {};
my $buffer = "";

if ($ENV{'REQUEST_METHOD'} eq 'GET') {
    $buffer = $ENV{'QUERY_STRING'};
}
else {
    read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}

foreach (split(/&/, $buffer)) {
    my($key, $value) = split(/=/, $_);
    $key   = decodeURL($key);
    $value = decodeURL($value);
    %{$hashRef}->{$key} = $value;
}

sub decodeURL {
    $_ = shift;
    tr/+/ /;
    s/%(..)/pack('c', hex($1))/eg;
    return($_);
}

No wonder Perl is often labeled as "unreadable!"

Thankfully, Lincoln Stein came along and gave us CGI.pm-- a Perl 5 module that makes several tasks the Perl web developer is commonly faced with, easier:

  • Generating good HTTP headers
  • Parsing form data
  • Generating HTML
  • Handling file uploads
  • Debugging HTML form processes
  • ...and more

Web developers often fail to realize they take on a greater level of responsibility when they leave the realm of static HTML pages, images, MP3 files, etc. served up by a HTTP server like Apache and enter the world of dynamic content generation, interactive web applications, and forms and form processors.

Web developers must write code to generate headers for the client that would otherwise be handled by the web server. This includes, at a minimum, a Content-type header, but may also include Content-length, Content-disposition, or Location. Developers must also provide the client with an HTTP status code (e.g. 200, 404, 302, etc.).

You may use CGI.pm using object-oriented syntax or not. I prefer to use the object-oriented syntax because it means I'm in step with other Perl modules I employ in my code.


use CGI;

my $q = new CGI;
print   $q->header('text/html'),
        $start_html(    -title =>   'React' );

my $answer = $q->param('foo');
if($answer eq 'bar') {
    print $q->p("You answered correctly!");
}
else {
    print $q->p("That is incorrect.");
}

print $q->end_html;

This example generates different content based on the value of a form variable (foo) passed in. If this script were named react.cgi then it might be called with a URL like react.cgi?foo=bar.

Notice the code above uses the header() function to generate a valid HTTP header. There are many options you may pass to this function but if you pass one scalar string as in this example, it will use that data to generate a Content-type header.

The above above demonstrates some of CGI.pm's HTML-generation capabilities (the use of the p() function to generate paragraph tags around content and the use of the start_html() and end_html() functions to properly form the beginning and end of an HTML document and generate the necessary title tags in the header.)

The above example also shows how you may use CGI.pm to access form variables (the param() function).

For a couple years, I used CGI.pm quite heavily in my web development tasks. I grew very attached to its HTML-generation capabilities and the fact that if your HTML is generated from CGI.pm code, it will always be valid, start tags will always have matching end tags, and so forth. For example, here is a snippet of code I wrote circa 1999-2000:


print   $q->start_form(
           -method=> 'POST',
            -action => 'add_event.cgi'),
         $q->hidden({-name=>'r'}),
         $q->table(
            $q->Tr(
                $q->td(
                    _event_form($q)),
                $q->td({
                    -valign=>'top',
                    -align=>'left'}),
                    $q->submit({
                        -name=>'c',
                        -value=>'Save Event Info'}),
                    $q->br,
                        $q->submit({
                            -name=>'c',
                            -value=>'Cancel'}))),
         $q->end_form;

There are definite advantages to writing code this way, but the disadvantages are numerous, especially if you intend for your application to be maintained by someone other than yourself. If you intend to have a web designer who has no Perl competence work on the layout, this type of code will have them running away, screaming, and flailing their arms wildly.

That being said, if you need to throw together a simple, self-encapsulated interactive web page, doing everything with CGI.pm isn't a bad way to go.

In most cases, CGI.pm is already installed on your Linux system. To read all about it, type perldoc CGI at your shell command prompt, or go to http://search.cpan.org/perldoc?CGI with your favorite web browser.

What's next?

Well, what's next partly depends on the type of feedback I get from this post, if any. Generally, I plan to talk about templating, database interaction, and more. But, if people have some specific things they would like to see my spin on, I'd be more than happy to oblige.