.d8888b.    .d8888b.   8888888
                      d88P  Y88b  d88P  Y88b    888
                      888    888  888    888    888
                      888         888           888
                      888         888  88888    888
                      888    888  888    888    888
                      Y88b  d88P  Y88b  d88P    888
                       "Y8888P"    "Y8888P88  8888888

                       PCP => Perl CGI Program (ming)

                                Version 1.0

Shishir Gundavaram <shishir@ora.com>
Tom Christiansen <tchrist@perl.com>

Under Construction

This page needs severe updating. I've a list of things yet to do or fix, but more suggestions are always welcome. See also the Idiot's Guide to Solving Perl CGI Problems.

--tchrist



1.0 - Introduction


Q1.1: Why does my HTML page/form need a script?

There are times when you might want to have some dynamic information (information that's not constant) in your HTML documents. This could include simple information such as the date and time, or a counter that displays "You are visitor number xxx", but it could also include such things as pie charts/graphs based on user input, results from searching a database, or animations. And the only way you can produce results like these is with CGI scripts (though you can also do so with client side applications like Java and JavaScript, but that's a totally different story!)


Q1.2: What does CGI stand for?

Here is an excellent description that my editors Andy Oram and Linda Mui (they're great!) wrote up:

Common          Assures you that CGI can be used by many
		languages and interact with many different
		types of systems.  It doesn't tie you down to
		one way of doing what you want.

Gateway         Suggests that CGI's strength lies not in what
		it does by itself, but in the potential access
		it offers to other systems such as databases
		and graphic generators.

Interface       Simply means that CGI provides a well-defined
		way to call up its features--in other words,
		that you can write programs that use it.

Q1.3: What is a script, anyway? What can I do with a script?

Simply put, a script is a program! OK, OK, there are semantical differences between the two terms. If you really want to know, pick up a book on computer programming (or is that computer scripting :-)

You can create a lot of magic by writing a CGI program/script. You can create graphics on the fly, access databases and return results and connect to other Internet information servers.


Q1.4: What is Perl and why do so many people use it for CGI?

The answer is located in the first three lines of the Perl manpage:

Perl is an interpreted language optimized for scanning arbitrary text files, extracting information from those text files, and printing reports based on that information.
Most CGI applications involve manipulating data in some fashion and accessing external programs and applications. Perl provides easy to use tools that make these tasks a cinch.


Q1.5: Is there a book or on-line docs on CGI and/or Perl programming?

Here is a list of books on CGI and Perl compiled by Cye H. Waldman:

---------------+---------------------------------+--------------+-------+------
Author         | Title                           | Publisher    | Media | Price
---------------+---------------------------------+--------------+-------+------
Christian      | The Webmaster's Handbook:       | Int. Thomson | CD    | $30
Neuss &        | Perl Power for Your Web Server  |              |       |
Johan Vromans  |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
William E.     | CGI Scripting                   | New Riders   | CD    | $45
Weinman        |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
Garbus et al.  | Perl Programming Unleashed      | Sams.net     | CD    |
               | (Available Mar 1996)            |              |       |
---------------+---------------------------------+--------------+-------+------
Steven E.      | Introduction to CGI & Perl:     | MIS Press    |       |
Brenner        | Web Scripts:                    |              |       |
Edwin Aoki     |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
Ed Tittel      | Perl 5 Programming Secrets      | IDG Books    | CD    |
et al.         | (Available Mar 1996)            |              |       |
---------------+---------------------------------+--------------+-------+------
Mitzelfelt     | Special Edition Using Perl      | Que          |       |
---------------+---------------------------------+--------------+-------+------
Shishir        | CGI Programming on the          | O'Reilly     |       | $30
Gundavaram     | World Wide Web                  |              |       |
---------------+---------------------------------+--------------+-------+------
Rob Farrel     | The Official 60 Minute Guide    | IDG Books    |       | $20
               | to CGI Programming with Perl    |              |       |
---------------+---------------------------------+--------------+-------+------
Ed Tittel      | Web Programming Secrets         | IDG Books    | CD    | $40
et al.         |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
John Deep      | Developing CGI Applications     | Wiley        |       | $30
               | with Perl                       |              |       |
---------------+---------------------------------+--------------+-------+------
Jon Orwant     | Perl 5 Interactive              | Waite        |       | $30
---------------+---------------------------------+--------------+-------+------
Reggie David   | Perl 5 How-To                   | Waite        | CD    | $40
               | (Available Spring 1996)         |              |       |
---------------+---------------------------------+--------------+-------+------
Eric Herrmann  | Teach Yourself CGI              | Sams.net     |       | $30
               | Programming with Perl in a      |              |       |
               | Week                            |              |       |
---------------+---------------------------------+--------------+-------+------
Walnut Creek   | Perl (Collected resources,      | Walnut Creek | CD    | $40
CD-ROM         | archives, tutorial, examples,   |              |       |
               | source code,etc.)               |              |       |
---------------+---------------------------------+--------------+-------+------
Carl Dichter & | Software Engineering with       |              |       |
Mark Pease     | Perl                            |              |       |
               | (This is an advanced text for   | Prentice     | Disk  | $30
               | software professionals; it is   | Hall         |       |
               | not a tutorial)                 |              |       |
---------------+---------------------------------+--------------+-------+------
Ellie Quigley  | Perl by Example                 | Prentice     |       | $27
               |                                 | Hall         |       |
---------------+---------------------------------+--------------+-------+------
John December  |  HTML & CGI Unleashed           | Sams.net     | CD    | $50
Mark Ginsburg  |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
David Till     | Teach Yourself Perl in 21       | Sams         |       | $30
               | Days                            |              |       |
---------------+---------------------------------+--------------+-------+------
Larry Wall &   | Programming Perl                | O'Reilly     |       | $30
Randal L.      |                                 |              |       |
Schwartz       |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
Randal L.      | Learning Perl                   | O'Reilly     |       | $25
Schwartz       |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
Ed Tittel      | Foundations of WWW              | IDG Books    | CD    | $40
et al.         | Programming with HTML and CGI   |              |       |
---------------+---------------------------------+--------------+-------+------
Eric Lease     | Teaching a New Dog Old Tricks   |              |       | FREE!
Morgan         | (Mac-based WWW Starter Kit      |              |       |
               | with Server)                    |              |       |
---------------+---------------------------------+--------------+-------+------
Susan Peck  &  | Website: Everything You Need    | O'Reilly     | CD    | $500
Linda Mui      | to Know...                      |              |       |
               | (This is a complete Website     |              |       |
               | kit for Windows NT 3.5)         |              |       |
---------------+---------------------------------+--------------+-------+------
Lincoln D.     | How to Set Up and Maintain a    | Addison      |       | $29
Stein          | World Wide Web Site             | Wesley       |       |
---------------+---------------------------------+--------------+-------+------
Jonathan       | The Web Server Book             | Ventana      | CD    | $50
Magid et al.   |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
net.Genesis &  | Build a Web Site                | Prima        |       | $35
Devra Hall     |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
David          | Running a Perfect Web Site      | Que          | CD    | $40
Chandler       |                                 |              |       |
---------------+---------------------------------+--------------+-------+------
Jon Weiderspan | Planning & Managing a Web       | Addison      | CD    | $40
Chuck Shotton  | Site on the Macintosh           | Wesley       |       |
---------------+---------------------------------+--------------+-------+------

Q1.6: Is there a mailing list or newsgroup for this kind of thing?

There is a very useful newsgroup: comp.infosystems.www.authoring.cgi, that's "monitored" by numerous CGI experts. However, you should not post a question to this group (or any other group, for that matter), until you have read the FAQ.

Various mailing lists for Perl, CGI, and the Web exist. Here are two of the most popular:

cgi-perl-request@webstorm.com [ Hypermail archive ]

This list is for those who are writing/or interested in writing Perl 5 modules for CGI. It is not intended for any type of CGI support.

libwww-perlrequest@ics.uci.edu [ Hypermail Archive ]

libwww-perl is a Perl library that provides a simple programming interface for writing Web clients and servers.

You can access the Perl 4 distribution at:
http://www.ics.uci.edu/pub/websoft/libwww-perl

The Perl 5 libwww modules are located at:
http://www.oslonett.no/home/aas/perl/www

CPAN: Perl modules may also be retrieved from the multiplexed distributed CPAN system. This chooses a "site near you". For example, LWP modules are retrievable as source or just the readme.


Q1.7: Are there archives on the net of mailings or postings about this?

Yes, look at The Usenet Newstand, which has all of the comp.infosystems.www.* newsgroups are archived. In addition, the cgi-perl and libwww mailing lists are archived there as well.


2.0 - Modules


Q2.1: Should I use the Perl CGI modules to code all my CGI scripts? Isn't it easier to do it myself?

It really depends on what you are trying to do. The CGI modules should generally be used for heavy-duty CGI scripts. For simple scripts, its is far easier and quicker to roll your own or use CGI Lite (current version is v1.62). If you really want, you can even use the old Perl 4 cgi-lib.pl library.


Q2.2: How do I figure out how xyz module works?

Most modules have manpages embedded within the module itself. If that's the case, you can use the pod2man script to view the manpage:

% pod2text name_of_module.pm
% pod2man name_of_module.pm | nroff -man | more


Q2.3: What CGI or WWW libraries are available for Perl4?

The most widely used CGI library for Perl 4 is cgi-lib.pl written by Steven Benner.


Q2.4: What CGI modules are available for Perl 5? Which should I use, and why?

CGI.pm
This wonderful module has some of the same functionality as the CGI::* modules. You can use this if you don't want to deal with multiple modules. We will show you an example of how to use CGI.pm to debug your CGI scripts later in this document.

Lincoln has also written an excellent book on the Web and CGI, titled How to Set Up and Maintain a World Wide Web Site.

CGI::* Modules
These modules, most of them originally written by Tim Bunce and now maintained by Lincoln Stein, allow you to create and decode forms, debug your CGI programs and maintain state between forms.

CGI Lite
This lightweight module is an alternative to the CGI::* modules. It is something of a glorified version of the old cgi-lib.pl with some added functionality.

All three of these modules have the ability to decode the multipart form data (i.e file upload).


Q2.5: Why are so many of these CGI perl libraries object-oriented? I don't know any of this OO programming. Aren't there simpler libraries for non-programmers to use? How hard can it be?

Actually, it's not very hard at all. See Tom Christiansen's Easy Intro to Using Perl Objects for a quick primer.

The CGI modules mentioned above are a piece of cake to use! Here is a simple example that uses CGI Lite to print out form data:

#!/usr/local/bin/perl5

use CGI_Lite;

$cgi = new CGI_Lite;
%data = $cgi->parse_form_data;

print "Content-type: text/plain", "\n\n";

foreach $key (keys %data) {
    print $key, " = ", $data{$key}, "\n";
}

exit (0);
Note, if you did not build Perl on your system or do not have access to install these modules with the other Perl library files, you can still use it by placing the module in a convenient place and adding the following to your script:
BEGIN {
    unshift (@INC, "/your/dir/favorite/place");
}
Now, here is an example using the CGI::* modules:
#!/usr/local/bin/perl5

use CGI::Form;

$cgi_form = new CGI::Form;

print <<'End_of_Header';
    <HTML>
    <HEAD><TITLE>Watch This!</TITLE></HEAD>
    <BODY>
    <H1>Watch This!</H1>
End_of_Header

print $form->startform;

## Creates a text field

print "Name: ";
print $form->textfield('name'), "<BR>\n";

## Creates a group of radio buttons

print "<P>Where do you live: <BR>";
print $form->radio_group (-name      => 'where',
                          -values    => ['North America',
                                         'South America',
                                         'Europe',
                                         'Australia',
                                         'Asia',
                                         'Antartica'],
                          -default   => 'North America',
                          -linebreak => 'true');

## Creates a textarea field

print "Comments: ";
print $form->textarea('comments', undef, 5, 40);

print "<P>";
print $form->reset;
print $form->defaults;
print $form->submit ('Send!', 'Submit');
print $form->endform;

print "</BODY></HTML>";

The reset, defaults and submit methods create different type of buttons. The reset button allows you to clear the values in the current form and display values from the previous state (or session). The defaults button clears the form entirely. And the submit method creates a Submit button for you to send the data to the server.

Now, wasn't that simple?


3.0 - CGI and the WWW Server


Q3.1: Where does my PCP have to live to execute? What is the cgi-bin directory for?

The server is generally configured so that it executes CGI scripts that are located in the "cgi-bin" directory. However, the server administrator can set up aliases in the server configuration files, so that scripts with certain extensions (i.e .cgi, .pl) can also be executed.


Q3.2: What are file access permissions? How do I change them?

File permissions allow read, write, and execute access to users based on their user identification (also known as uid), and their membership to certain groups. You can use the command: chmod to change a file's permissions. Here is an example:

% ls -ls form.cgi

  1 -rwx------  1 shishir       974 Oct 31 22:15 form.cgi*
This has a permission of 0700 (octal), which means that no one (besides the owner) can read to, write from, and execute this file. Let's use the chmod command to change the permissions:
% chmod 755 form.cgi
% ls -ls form.cgi

  1 -rwxr-xr-x  1 shishir       974 Oct 31 22:15 form.cgi*
This changes the permissions so that users in the same group as "shishir", as well as all other users have the permission to read from, and execute this file.

See the manpages for the chmod command for a full explanation of the various octal codes.


Q3.3: Where should Perl be installed so I can execute it?

Perl can be installed anywhere on the system! The only thing you have to make sure is that the server is not running in a chroot-ed environment, and that it can access the interpreter. In other words, system administrators can change the root directory, so that "/" does not point to the actual root ("/"), but to another directory.


Q3.4: Why am I getting the "Server: Error 500" message?

You can get a server error for the following reasons:


Q3.5: I try to open a file for writing so I can save my data, but the open () command fails. What's going on?

Generally, the HTTP server will be running as user "nobody", or "www", or some other user id that has mimimal privileges. As a result, the directory (where you intend to create the file) must be writeable by this process id.

To be on the safe side, always check the return status from the open command to see if it was a success:

open (FILE, "/abc/data.txt")
    || error ("Could not open file /abc/data.txt");

	.
	.	
	.

sub error {
    my ($message) = @_;
	
    print <<End_of_Error;
Content-type: text/html
Status: 500 CGI Error

<HTML>
<HEAD><TITLE>CGI Error</TITLE></HEAD>
<BODY>
<H1>Oops! Error</H1>
<HR>
$message
<HR>
</BODY>
</HTML>

End_of_Error
}

4.0 - Specific Programming Questions


Q4.1: I want the user to fill in a form and mail it to me. How can I do this? Are there any examples to show me how?

It is actually a fairly simple process to do this. Your CGI script must be able to perform two tasks:

Let's assume you're using the CGI::* modules. Here is how you would deal with sendmail:

$cgi_form = new CGI::Form;

$from     = $cgi_form->param('from');
$name     = $cgi_form->param('name');
$to       = $cgi_form->param('to');
$subject  = $cgi_form->param('subject');
$message  = $cgi_form->param('message');

open (SENDMAIL, "| /usr/bin/sendmail -t -n");
print SENDMAIL <<End_of_Mail;
From: $from <$name>
To: $to
Reply-To: $from
Subject: $subject

$message
End_of_Mail
One thing you should note is the "Reply-To:" header. Since the server is running as user "nobody", the mail headers might be messed up (especially when people are trying to reply to it). The "Reply-To:" field fixes that.

There are a lot of mail gateways floating around that use mail in the following format:

open (MAIL, "| mail -s 'Subject' $to");

                                   ^
                                   |
                                   +-- Possible security hole!!!!

If you don't check the $to variable for shell metacharacters, you're in for a major headache! For example, if some malicious user entered the following:

; rm -fr / ;

You'll have a major problem on your hands.


Q4.2: The formmail script looks complicated. Why can't I use a mailto: URL so that it just mails me the info the user filled in?

Unfortunately, the mailto: command is not supported by all browsers. If you have this in your document, it is a limiting factor, as people who use browsers that do not support this, will not have the ability to send you mail.


Q4.3: How do I do PCP from non-Unix platforms, like the Mac, MS-DOS, Windows, and NT? Will my PCP port amongst all these environments? Can it be transparent? I have an account on a UNIX server, but work on a Windows/Mac system. How can I test my CGI script on my own system?

Perl has been ported to all the platforms that are mentioned above. As a result, your PCP program should be reasonably portable. If you're are interfacing with various external programs on the UNIX side, then it probably will not be portable, but if you're just manipulating data, opening and reading files, etc., you should have no problem.


Q4.4: What are STDERR and STDIN and STDOUT connected to in a PCP?

In a CGI environment, STDERR points to the server error log file. You can take this to your advantage by outputting debug messages, and then checking the log file later on.

Both STDIN and STDOUT point to the browser. In actuality, STDIN actualls points to the server which interprets the client (or browser's) request and information, and sends that to the script.

In order to catch errors, you can "dupe" STDERR to STDOUT early on in your script (after outputting the valid HTTP headers):

open (STDERR, ">&STDOUT");
This redirects all of the error messages to STDOUT (i.e the browser).


Q4.5: How do I write an access counter script?

Counter scripts tend to be very popular. The idea behind a counter is very simple:

Here is a simple counter script:

#!/usr/local/bin/perl

$counter = "/home/shishir/counter.dat";
print "Content-type: text/plain", "\n\n";

open (FILE, $counter) || die "Cannot read from the counter file.\n";
flock (FILE, 2);
$visitors = <FILE>;
flock (FILE, 8);
close (FILE);

open (FILE, ">" . $counter) || die "Cannot write to counter file.\n";
flock (FILE, 2);
print FILE $visitors;
flock (FILE, 8);
close (FILE);
You can now use SSI (Server Side Includes) to display a counter in your HTML document:

You are visitor number:

<!--#exec cgi="/cgi-bin/counter.pl-->

Q4.6: How can I strip all the html tags from a document with a Perl substitute?

Here is a simple regular expression that will strip HTML tags:

$line =~ s/<(([^ >]|\n)*)>//g;

Or you can "escape" certain characters in a HTML tag so that it can be displayed:

$line =~ s/<(([^>]|\n)*)>/<$1>/g;

For more information, see Tom's striphtml program, which is also included in his tour of perl5 regexps.


Q4.7: How can I tell what user/host/browser called my program?

You can use the environment variable HTTP_USER_AGENT to determine the user's browser.

[ From WWW FAQ ]

Five important environment variables are available to your CGI script to help in identifying the end user.

[ End of info from WWW FAQ ]


Q4.8: Can people read my PCP? If they do, is it a security problem that they know how my code works? How can I hide it?

If you configure your server so that it recognizes that all files in a specific directory (i.e "cgi-bin"), or files with certain extensions (i.e ".pl", ".tcl", ".sh", etc) are CGI programs, then the server will execute these programs. There is no way for users to see the script itself.

On the other hand, if you allow people to look at your script (by placing it, for example, in the document root directory), it is not a security problem, in most cases, providing that there are no security holes in the program. If the program does contain security holes and you allow users to view the program, then they can and will exploit the problem.


Q4.9: Do I have to copy the whole Perl library into my htdocs directory?

No, your CGI scripts can access files outside the server and document root directories, unless the server is running in a chroot-ed environment.


Q4.10: Why shouldn't I have people type in passwords or social security numbers or credit card numbers? Isn't that what TYPE="password" is for?

No! The forms interface allows you to have a "password" field, but it should not be used for anything highly confidential. The main reason for this is that all form data (including "password" fields) gets sent from the browser to the Web server as plain text, and not as encrypted data.

If you want to solicit secure information, you need to use a secure server, such as Netscape's Commerce Server.


Q4.11: How do I generate separate pages for netscape vs. the rest of the world?

You can have your CGI script determine whether your script is being accessed by Netscape by using the environment variable HTTP_USER_AGENT. Here is an example:

$browser = $ENV{'HTTP_USER_AGENT'};

if ($browser =~ /Mozilla/) {
    #
    # Netscape
    #
} else {
    #
    # Non Netscape
    #
}

Q4.12: Why doesn't my system () output come out in the right order?

This has to do with the way the standard output is buffered. In order for the output to display in the correct order, you need to turn buffering off by using the $| variable:

$| = 1;


Q4.13: I hear that Netscape is going to support Java. Does that mean I have to use Java now instead of Perl? Should I?

No, No. The concept of Java is totally different than that of CGI. CGI refers to server-side execution, while Java refers to client-side execution. There are certain things (like animations) which can be improved by using Java. However, you can continue to use Perl to develop server-side applications.

For more information, here are a few documents you can look at:


Q4.14: How can I access my environment variables? Why are they different sometimes?

You can access the environment variables through the %ENV associative array. Here is a simple script that dumps out all of the environment variables (sorted):

#!/usr/local/bin/perl

print "Content-type: text/plain", "\n\n";
	
foreach $key (sort keys %ENV) {
    print $key, " = ", $ENV{$key}, "\n";
}

exit (0);

Unfortunately, not all browsers set the same environment variables. For example, HTTP_REFERER is not set by all browsers.


Q4.15: Why does my output get mangled ( like "if b < a" is messed up.)?

If you send a MIME content type of HTML, you will have to "escape" certain characters, such as "<", "&" and ">", or else the browser will think it is HTML.

You have to escape the characters by using the following construct:

&#ASCII Code;

Here is a simple script that you can run on the command-line that will give you the ASCII code for non alpha-numeric characters:

#!/usr/local/bin/perl

print "Please enter a string: ";

chop ($string = <STDIN>);
$string =~ s/([^\w\s])/sprintf ("&#%d;", ord ($1))/ge;

print "The escaped string is: $string\n";

exit (0);

Q4.16: How come when I run it from the command line, my PCP works, but not from the browser?

This most likely is due to permission problems. Remember, your server is probably running as "nobody", "www", or a process with very minimal privileges. As a result, it will not be able to execute your script unless it has permissions to do so.


Q4.17: How come my PCP runs fine but doesn't manage to write its output files?

Again, this has to do with permissions! The server cannot write to a file in a certain directory if it does not have permissions to do so.

You should make it a point to check for error status from the open command:

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

.
.
.

open (FILE, ">" . "/some/dir/some.file") ||
    print "Cannot write to the data file!";

.
.
.

Q4.18: How do I make a form that maintains state, or has several entry points?

You can use the CGI::MiniSvr module to keep state between multiple entry points.

Or you can create a series of dynamic documents that pass a unique session identification, either as a query, extra path name, or as a hidden field, to each other.


Q4.19: How do I debug my PCP without running it from a web browser?

It's difficult to debug a CGI script. You can emulate a server by setting environment variables manually:

setenv HTTP_USER_AGENT "Mozilla/2.0b6"       (csh)

or

export HTTP_USER_AGENT = "Mozilla/2.0b6"     (ksh, bash)
You can emulate a POST request by placing the data in a file and piping it to your program:
cat data.file | some_program.pl

You can use the CGI.pm (or the CGI::* modules) to debug your script. Say you have a simple script like the following, which prints out all the key/value pairs you pass it.

#!/usr/local/bin/perl5

use CGI;

$cgi = new CGI;

print $cgi->header;
print $cgi->start_html("Simple CGI.pm Program");
print "<H1>Simple CGI.pm Program</H1>\n";
print "<HR >";
print "Here is a list of the values you passed: ";
print $cgi->dump;

exit (0);
The script doesn't care whether you're passing the values as a GET, POST or ISINDEX query, or from the command line, standard input, or text file. For debugging purposes, let's pass some values through the command line:
% simple.cgi first=shishir last=gundavaram document='CGI\ FAQ'

or

% simple.cgi "first=shishir&last=gundavaram&document='CGI\ FAQ'"
In the second example, you have to have quotes around the entire string, or else the shell will get confused when it sees the "&" character. Now, here is how you would debug from standard input:
% simple.cgi
(waiting for standard input)
first=shishir
last=gundavaram
document=CGI\ FAQ
^D
Of course, you can also use a file to store the form data, and then do input redirection, like so:
% simple.cgi < form.data

You can use also use CGI Lint -- will be released shortly -- which will do much of the same. It will also check for potential security problems, errors in open () and invalid HTTP headers.


Q4.20: How can I call a PCP without using a <FORM> tag?

You can call a CGI program by simply opening the URL to it:

http://some.machine/cgi-bin/your_program.pl

You can also have a link in a document, such as:

<A HREF="http://some.machine/cgi-bin/your_program.pl">
Click here to access my CGI program</A>


Q4.21: How do I stop people from calling my form without filling out anything? Why do they keep doing this?

The reason they call a form with nothing filled in is that they save the URL to the form, which they then call again, which is just an empty GET (and not a POST or a filled-out GET).

However, you can check the information from all the fields and return a "no response" if any of them are empty. Here is an example (assume the associative array %form contains your form information):

$error = 0;

foreach $value (values %form) {
     $value =~ s/\s//g;
     $error = 1 unless ($value);
}

if ($error) {
    print "Content-type: text/plain\n";
    print "Status: 204 No Response\n\n";
    print "You should only see this message if your browser does";
    print "not support the status code 204\n";
} else {
    #
    # Process Data Here
    #
}

Q4.22: What are all the server response codes and what do they mean?

A CGI program can send specific response codes to the server, which in turn, it will send to the browser. For example, if you want a "No Response" (meaning that the browser will not load a new page), then you need to send a response code of 204 (see above).


Q4.23: Why doesn't:
print "Location: http://host/page.html\n"
work? Why does it only work the first time and get the redirects wrong later?

A CGI program can only send one Location header. You also cannot send a MIME content type if you want the server to perform redirection. For example, this is not valid, though it may work with some servers:

#!/usr/local/bin/perl

.
.
.
print "Content-type: text/plain\n"
print "Location: http://some.machine/some.doc\n\n"";

Q4.24: How can I automatically include a:

"Last updated: ..."
line at the bottom of all my HTML pages? Or can I only do that for SSI pages? How do I get the date of the CGI script?

If you are dynamically creating documents using CGI, then you can insert a timestamp pretty easily. Here is an example (Perl 5 only).

$last_updated = localtime (time);
print "Last updated: $last_updated\n";
or:
require "ctime.pl";

$last_updated = &ctime (time);
print "Last updated: $last_updated\n";
or even:
chop ($date = `/usr/local/bin/date`);
print "Last updated: $last_updated\n";
You can accomplish this with SSI like this:
<--#echo var="LAST_MODIFIED"-->


Q4.25: When is a PCP too complex for a simple task and shell will do? When is it not powerful enough for a hard one? Isn't C++ much better for this kind of thing? What about C?

Each language has its own advantages and disadvantages. I'm sure you've heard this many times: it depends on what you're trying to do. If you writing a CGI that's going to be accessed thousands of times in an hour, then you should write it in C or C++. If you are looking for a quick solution (as far as implementation), then Perl is the way to go!

You should generally avoid the shell for any type of CGI programming, just because of the potential for security problems.


5.0 - Security


Q5.1: Is a PCP more or less secure than a shell or C one?

The answer to this is: a CGI program is prone to security problems no matter what language it is written in!


Q5.2: What particular security concerns should I be aware of?

Never expose any form data to the shell. All of the following are possible security holes:

However, the second construct can be made safer by passing the arguments as a list, rather than a string -- which the shell will mess with:

system ("/usr/ucb/finger", $form_user);

You should also look at:


Q5.3: Why is everyone saying that
http://bigidiot.abuse-me.com/perl.exe?foo.pl
is dangerous? How bad can it be?

Extremely dangerous! Just imagine what will happen if I do something like this:

http://bigidiot.abuse-me.com/cgi-bin/perl.exe?-e+'format:%20c'
Now, do you agree with me? The way to avoid these potential nightmares is to:

Now, here's an example. Assume your CGI script is called "sample.pl" and your batch script is called "simple.bat":

@echo off
c:\dos_perl\perl.exe c:\netscape\ns-home\docs\cgi-bin\simple.pl
Now, you can can do the following:
<A HREF="/cgi-bin/simple.bat">Click Here</A>


Q5.4:How can I call progam with backticks securely? Is it true that:
@ans = `grep '$user_field' some.file`;
is insecure?

Yes! It's very dangerous! Imagine if $user_field contains something like the following:

; rm -fr / ;

A much safer way to accomplish the above is:

if (open (GREP, "-|")) {
    @ans = <GREP>;
} else {
    exec ("/usr/local/bin/grep", $user_field, "some.file")
        || die "Error exec'ing command", "\n";
}

close (GREP);

Q5.5: Is it true that /$user_variable/ is a security hole in Perl 5?

No! It's not. It's a security hole if you evaluate the expression at runtime using the eval command. Something like can be dangerous:

foreach $regexp (@all_regexps) {
    eval "foreach (\@data) { push (\@matches, \$_) if m|$regexp|o; }";
}

This document, and all its parts, are Copyright (c) 1996, Shishir Gundavaram and Tom Christiansen. All rights reservered. Permisson to distribute this collection, in part or full, via electronic means (emailed, posted or archived) or printed copy are granted providing that no charges are involved, reasonable attempt is made to use the most current version, and all credits and copyright notices are retained. Requests for other distribution rights, including incorporation in commercial products, such as books, magazine articles, or CD-ROMs should be made to either of the authors.

Return to:
Copyright 1996 Tom Christiansen.
All rights reserved.