///Tips for Convenient CGI Scripting

Tips for Convenient CGI Scripting

Tips for Convenient CGI Scripting

Any CGI programmer benefits from knowing and using ready-made libraries. In this article Eugene Logvinov shows how CGI modules taken from CPAN can not only help you to work effectively and conveniently, but can also provide you with an excellent code and reference library. Consequently, embedding POD (Plain Old Documentation) in the module turns out to be a good choice.

When you’re doing CGI programming you usually have a choice between using the CGI module or scripting manually. Here we’re going to take a look at what you can do with the CGI module and its derived classes, like CGI::Fast. Scripting without using any pre-built modules may be fine when a CGI application only needs a small amount of code, like when you’re parsing $ENV{QUERY_STRING}, or when speed is of the essence, like when you’re compiling a 200 KB module. But more often than not, the CGI module is more suitable.

The CGI module

The first point to be made in espousing the benefits of using the CGI module is that it is irreplaceable for the file upload function, which differs slightly in various browsers and platforms. The CGI module provides all the tools needed to upload files, including those for handling HTTP headers and cookies, running scripts from the command line, and supporting NPH scripts and the file upload function. And, conveniently, the module can be used either in an object-oriented or in a function-oriented style.

The CGI module itself is a complex, even extreme, application that includes numerous features from Perl. Not surprisingly, some experts claim that if you understand the GGI.pm module, you’ll understand Perl! CGI.pm, written by Lincoln Stein, is the module most developers use to build Web applications with Perl. You can retrieve the module from CPAN, and see current documentation at the CGI.pm page.

Unfortunately, complex libraries often contain subtleties that make them more difficult to use. On the other hand, the complications of the CGI module appear only under certain conditions. Take, for example, the implementation of the file upload function in HTML form, where the documentation neglects to tell us about all of the features. In Listing 1 below, the user can upload a file to a Web server. When the form is processed, the script retrieves the contents of the file and displays them in the browser; they are enclosed by <pre> and </pre> tags.

Listing 1. File upload sample code

#!/usr/bin/perl -Tw

use CGI ':standard';
use strict;

my $out.= start_multipart_form.filefield(-name.=> 'upload');
$out .= br.submit('submit','Send').end_form;
my$file.= param('upload'); #the filename returned is also a file handle
if(request_method eq 'POST' &&
defined $file && ref $file && ref $file eq 'Fh')
{
local $/.= undef; #read the whole file
$out .= pre ||''; #takes care not to send uninitialized value
close $file if $CGI::OS ne 'UNIX'; #such as Win32 platforms
}

print header,start_html('Sample upload page'),$out,end_html;

The “$out .= pre &lt;$file>||”;” line is absolutely necessary here. When a user sends an empty file or enters an invalid file name, the diamond operator returns the uninitialized defined value, causing a crash of the pre function.

Moreover, $file needs quite a few verification points, because when the POST method is used for a simple form, $file is no longer the file handle.

And some operating systems require explicit closure of the temporary file. This is true for Win32, but it is not true for UNIX platforms.

These are all subtle features of the CGI module that the documentation does not tell us about, and that make the module a little more complex under these conditions.

Displaying script errors in the browser

Displaying the syntax and runtime errors on the browser screen can be a big help when you’re debugging code. In our case, the scripting cycle will consist of editing script files, saving them, and reloading the browser screen. Let’s take a look at how it works.

Listing 2. The most complete debug printing code implementation

#!/usr/bin/perl -Tw

use strict; #restrict unsafe constructs
use CGI ':standard';
use CGI::Carp qw/carpout fatalsToBrowser set_message/;
use diagnostics -verbose; #print warning diagnostics

BEGIN {
local *LOG;
my $size.= -s "my.log" || 0;
open LOG, ">>my.log" or die "Can't open: $!";
carpout(\*LOG);
my $errors.= 0;
sub handle_errors #will be called with the text of the error
{
$errors.= defined $_[0] && $_[0] || $errors, $size
}
set_message(\&handle_errors);
}

END {
my($errors, $size).= handle_errors;
if($errors)
{
local *LOG;
local $/.= undef;
open LOG, "my.log" or die "Can't open: $!";
seek LOG,$size,0; #skip previous error log
local $_.= <LOG>;
close LOG;
s/&/&/g; #replace special characters
s/"/"/g;
s/>/>/g;
s/</</g;
print "<table><tr><td bgcolo.=linen><pre styl.='color:black'>";
print "<b>$errors</b>
$_</pre></td></tr></table>";
}
}

print header,start_html('Test page'),'test',end_html;

Now you’ve seen an example of the most complete and popular approach (according to the modules used) to code debugging. Although all of the techniques will hardly be used simultaneously in normal circumstances, each one is worth investigating on its own.

While the -w flag and “use strict” are great to use here, the -T flag is absolutely necessary, as it highlights the security holes in the script.

CGI::LogCarp usage and shortcomings

When you use the diagnostics and the CGI::Carp modules together, you come up with a few interesting results. CGI::Carp sets the $::SIG{__WARN__} and $::SIG{__DIE__} signal handlers in an approximate manner, while the diagnostics module expands the installed signal handler. This is why the order that the modules are included in the use statement is important. Moreover, the module does not allow presentation of the whole STDERR on the browser screen, and as a result, only a snippet of the module’s code is used.

Additional error data displayed by the diagnostics module are not always easily readable, because of repetitive (and annoying) error messages. This is especially true with the -verbose flag, which should only be used when you first start out.

Another imperfection in our example is the relatively long compilation time, which can be avoided by copying code fragments to another module. It’s better to use tied file handles to write STDERR directly to a scalar value, and to subsequently display errors in the browser, than to write STDERR to a file. Unfortunately, this is currently impossible due to a Perl bug.

Jan Pazdziora, the author of the Tie::STDERR module, admits that “the Tie::STDERR catches the compile time errors, but it doesn’t get the reason, only the fact that there was an error. I do not know how to fix this.” So the only current solution is to redirect STDERR to the file.

After completing the script design and test stages, it is a good idea to skip the debug stage and upload a snippet of code to the server first. Perl Diver (a simple Perl script) could be used to determine some server features (installed modules, the location of sendmail, environment variables, etc.). You can also take a look at the script’s detailed description.

Standard modules of CGI::* type

In addition to its primary uses, the CGI module also has a few other functions, among them an HTML writing feature which, according to the module’s author, “should be discarded in favor of the CGI::* modules” (HTTP::* and HTML::* should also be added here). Many of the module’s functions are not always convenient, which is why CGI.pm is often used instead, and the HTML writing functions are usually abandoned. CGI::Minimal and CGI_Lite modules work better for this purpose.

Complex CGI scripting sometimes requires Web-related modules. Their implementation often depends on a specific task or usual HTML writing techniques. The list of modules for this can be found on CPAN (see Resources), which is not only the Perl programming archive but also a hub of ideas. I highly suggest you visit CPAN before writing a complex script; it will be worth the effort.

Resources

• Take a look at the most recent version and complete documentation for the CGI module.

• All the source code examples in this article can be found in the Official Guide to Programming with CGI.pm (John Wiley & Sons, 1998).

• Take a look at the comprehensive Web server report (a Perl script).

• Check out CPAN’s modules in alphabetical order by modules contained in the distributions.

• Find useful reference materials at the O’Reilly Open Books Project.

• Read an extensive article on Debugging CGI Scripts from the Perl/PHP Newsletter.

• Also on developerWorks, read:

· Zope for the Perl/CGI programmer

· Server-side scripting languages· Cultured Perl: One-liners 101

· Repurposing CGI applications with SOAP

· Make your software behave: CGI programming made secure

• Download your own IBM Developer Kit for Linux from developerWorks!

2010-05-26T11:35:14+00:00 April 14th, 2005|CGI and Perl|0 Comments

About the Author:

Eugene Logvinov is a Web developer with the softPilot.2000 project (CONSUL Bureau, Sevastopol, Ukraine). The author is a third-year student at Kharkov National University (Ukraine), focused on new ideas in Web development and technical writing. You can contact him at rezonal [at] univer.kharkov.ua.

Leave A Comment