December 4, 1998
Cross-platform Perl/CGI tips and tricks
by Dave Edis
Let’s talk about writing cross-platform Perl/CGI programs. Cross-platform means that a program will work just as well on a Windows server as it will on a Unix server and vice versa. It also means that if a program is moved from one type of server to another, it can run without any modifications.
Not only does this make your code more portable and easier to set up, it also saves you time when you are developing a program on one server and installing it on another, or when your client decides to switch servers or Web hosting providers.
Figuring out what the cgi directory is
One of the biggest hassles in setting up a new program is figuring out the paths to data files, templates, and other required files. These can vary widely from server to server, and if you only have FTP access to the server on which you’re installing your program, it can be very difficult to determine the full filepath.Even when you know the filepath, you will need to modify it each time your program is installed on a different server. If you are constantly jumping from a development server to a staging server to a live server, this can be a lot of work.
The trick? In Perl the
$0 |
$cgidir |
“$cgidir/../data/database.db” |
The first line finds the cgi directory on a Windows server, which uses back slashes to separate the filepath. The second line finds the cgi directory on a Unix server, which uses forward slashes. Finally, we’ve found that on a very few Unix servers
### Find current directory path
if ($0=~m#^(.*)#){ $cgidir = “$1”; } # win/dos
elsif ($0=~m#^(.*)/# ){ $cgidir = “$1”; } # Unix
else {`pwd` =~ /(.*)/; $cgidir = “$1”; } # Unix
$0 |
By using
$cgidir |
How to “die” with something better than “Server Error 500”
Anyone who develops Web applications is all too familiar with that “Server Error 500” screen, the one that appears every time you have even the slightest error in your code. When something goes wrong in your program and Perl “dies,” it exits the program currently running and makes an entry in the error log telling you what the problem was.In many cases, it can be difficult to locate and view the error log to find out just what went wrong, and on some servers it’s not possible at all (due to file permissions). As it turns out, there’s a quick and easy way to replace that error screen with a helpful error message of your own design. By setting the signal handler for die, we can “catch” that die signal and tell the program to do something else before it dies. The following code should go near the top of our program so it runs before anything else.
$SIG{__DIE__} = &Error_Msg;
sub Error_Msg {
$msg = “@_”;
print “Content-type: text/htmlnn”;
print “The following error occurred : $msgn”;
exit;
}
You can customize your error message even more by specifying the “die” message and using
$! |
[break inserted here by editor to fit page; omit when copying!]
open(FILE,”<$cgidir/myfile.dat") ||
die(“Read Myfile : Can’t open file $cgidir/myfile.dat : $!”);
Now when your programs crash, die will tell you exactly what happened and why.
How to handle end-of-line characters and binary files
Windows and Unix handle end-of-line characters differently. Unix, for example, puts a single nextline character (“n”) at the end of each line in a text file to signify that that line is over and a new one has started. Windows does the same thing but uses two characters, a return and a nextline character (“rn”).This means that anywhere those characters are being read in, your program should recognize them as either “rn” or “n”. This could be while reading in data files, parsing text, reading form input, or so forth. If you’re counting on one and you get the other, your program may not function the way you want it to. An easy way to account for this is to simply replace “rn” with “n” like this:
$string =~ s/rn/n/gs;
Another issue is that Windows treats binary files and text files differently, so if you’re trying to read or write a binary file, you’ll get corrupted data, unless you specify that the file is to be read or written in binary mode.
Unix doesn’t pay attention to “binmode,” so it won’t cause problems by having it in there, it will just make Windows systems recognize the file as binary and read/write it correctly.
### Read Binary file on Windows
open(FILE,”<$cgidir/image.gif");
binmode(FILE); # Specify Binary mode for file
binmode(STDOUT); # Specify Binary mode for output
print "Content-type: image/gifnn";
while (
close(FILE);
Perl replacements for common system commands
I’ve seen many CGI programs that would work beautifully on any server except for one simple thing. Where the programmer needed to copy, rename, or erase a file, instead of doing it in Perl he just used an operating system specific shell command (e.g.,system(“cp $file1 $file2”); |
Here are some 100 percent Perl-based alternatives to common system commands that will work on any operating system.
### ERASE
unlink(“$cgidir/file.dat”);
### RENAME
rename(“$cgidir/oldfile.dat”,”$cgidir/newfile.dat”);
### COPY
open(FILE1,”<$cgidir/file1.dat");
open(FILE2,">$cgidir/file2.dat”);
binmode(FILE1);
binmode(FILE2);
while (
close(FILE1);
close(FILE2);
### CHMOD
chmod(0777,”$cgidir/file.dat”);
### MAKE DIRECTORY
mkdir(“$cgidir/newdir”,0777);
### REMOVE DIRECTORY
rmdir(“$cgidir/newdir”);
### CURRENT DATE/TIME
$date = scalar localtime(time);
print $date;
By using a few simple tricks and tips like these, you’ll not only be saving time but writing better programs too! If you have any tricks and tips of your own you would like to share, drop me a line.
Dave Edis is president of Edis Digital, a new media solutions firm in Vancouver, Canada. Edis Digital develops Web-based publishing tools and applications for companies around the world.