Creating the CGI Program

Now that the web form is created, you need a program to handle it. This section describes how to make a simple CGI program to read the form data.

When the user clicks on the Submit button, the browser encodes the data in the form and sends it to web server. The web server then runs the CGI program and sends the data to it.

A lot of details are involved in the encoding and decoding of form data. Fortunately, you don’t have to worry about them because there are Perl modules to do the work for you.

CGI Versus CGI::Thin

Most books on CGI programming describe how to use the CGI module rather than of the CGI::Thin module. The CGI::Thin module is a short, simple module that does everything you want it to.

The CGI module also does everything you want. The problem is that CGI module also contains hundreds of functions that you don’t want. As a result, it’s large and bloated. Finding the correct function in this mess is difficult.

So for both speed and simplicity, this chapter uses the CGI::Thin module.


Before getting started, you’ll need to install two modules:

  • CGI::Thin Decodes CGI data.

  • HTML::Entities Text-to-HTML encoder.

The CGI program begins with

#!/usr/local/bin/perl –T 
use strict; 
use warnings; 
use CGI::Thin; 
use CGI::Carp qw(fatalsToBrowser); 
use HTML::Entities;

Again, the first line is the magic line that tells Linux where to find Perl and to start it with the “Taint” flag set.

Next, specify the modules you are using.

When the CGI program runs, the first thing it does is print the special string that tells the web server that a HTML page follows:

print "Content–type: text/html
"; 
print "
";

CGI programs are notoriously difficult to debug (more on this in the “Debugging a CGI Script” section). First you must call a debug routine that prints out all the data in the form. This will be a big help if anything goes wrong.

The debug routine begins by getting the data out of the form by calling the Parse_CGI function. This function knows all about communicating with the web server and how to decode form data:

my %form_info = Parse_CGI();

The function returns the form data in the form of a hash where the key comes from the NAME attribute of the input directive, and the value comes from what the user entered (in the case of text entry) or the VALUE attribute in the case of check boxes or options.

For example, if the user checked the blank specified by

<INPUT TYPE="checkbox" NAME="intern" VALUE="1"> 
Currently a member of an intern program</INPUT>

the CGI program would see

$form_info{"intern"} = "1";

For debugging, you want to print the hash. You can do so in a small loop:

foreach my $cur_key (sort keys %form_info) {
    # WARNING: SEE BELOW 
    print "$cur_key = $form_info{$cur_key}
"; 
}

But there is a problem with this. What if the user entered data containing HTML code? For example:

This is a <B>Good</B> job.

In this case, when this string is printed it will be intercepted as an HTML string resulting in

This is a Good job.

If you wanted to see exactly what the user typed this would be wrong. In this case, things are not too bad because the user was nice enough to type legal HTML code. But the user could have typed

Will be finished in "< two weeks".

Because of the “<” in this text, the browser will think that this is an HTML directive and try to execute it.

You need to encode the output so that special characters don’t cause funny things to happen. For example, if you want to print the previous comment, it needs to be printed as

Will be finished in "&lt; two weeks".

That’s where the HTML::Entities module comes in. It provides the function encode_entities that turns text into HTML so that it can be printed. So the actual print loop is

foreach my $cur_key (sort keys %form_info) {
    print encode_entities($cur_key), " = ", 
      encode_entities($form_info{$cur_key}), "
"; 
}

Actually, you’re not quite there. Sometimes the system will have multiple values for the same key—for example, when you have a form with a multiple selection list in it. In this case, the Parse_CGI function sets the hash’s value to an array reference.

You need to check for this and handle it properly:

if (ref $form_info{$cur_key}) {
    #.... print array @{$form_info{$cur_key}} 
} else {
    #.... print scalar $form_info{$cur_key} 
}

Note that the ref function returns true if the scalar is a reference and undefined if it’s not.

The server communicates with the application through not only the CGI protocol but also the environment. So after you print all the CGI parameters, you print the environment as well.

Recording the Data

After the debug function comes the body of the program, which records the data. This is simple, straightforward Perl, so the details are not discussed here.

About the only significant thing to notice is that all the output files are named form.<time >, where <time > is the system time in seconds. This guarantees that you have unique names for your output files (assuming that two people don’t submit reports at exactly the same time).

The other thing to notice about the filename is that no user input goes into creating it. In other words, nothing from the form is used in selecting the filename. This is a security measure. Security is discussed in more detail in the section “Security.”

Writing a Response

The last part of the program writes a response to the user to let him know that his data has been submitted:

print <<EOF; 
<H1>Thanks</H1> 
<P> 
Thank you for your time.  Your information has been 
recorded. 
EOF

Putting It All Together

Listing 12.3 shows the full version of the CGI script.

Listing 12.3. record.pl
#!/home/sdo/local/bin/perl –T 
use strict; 
use warnings; 

use CGI::Thin; 
use CGI::Carp qw(fatalsToBrowser); 
use HTML::Entities; 

my $out_dir = "/tmp"; 

######################################################## 
# debug –– Output debugging information for the web form 
# 
#  All form data and the environment is printed. 
######################################################## 
sub debug() 
{
    print "<H1>DEBUG INFORMATION</H1>
"; 
    print "<H2>Form Information</H2>
";   
    # –––––––– print form information ––––– 
    my %form_info = Parse_CGI(); 
    foreach my $cur_key (sort keys %form_info) {
        print "<BR>"; 
        if (ref $form_info{$cur_key}) {
            foreach my $value (@{$form_info{$cur_key}}) {
                print encode_entities($cur_key), " = ", 
                      encode_entities($value), "
"; 
            } 
        } else {
            print encode_entities($cur_key), " = ", 
                  encode_entities($form_info{$cur_key}), "
"; 
        } 
    } 

    # –––––––– print environment –––––– 
    print "<H2>Environment</H2>
"; 
    foreach my $cur_key (sort keys %ENV) {
         print "<BR>"; 
         print encode_entities($cur_key), " = ", 
         encode_entities($ENV{$cur_key}), "
"; 
    } 
} 
sub write_report() 
{
    # The information from the form 
    my %form_info = Parse_CGI(); 

    # The current time in seconds 
    my $time = time(); 

    open OUT_FILE, ">$out_dir/form.$time" or 
          die("Could not open $out_dir/form.$time"); 

    print OUT_FILE "Name: $form_info{name}    Group: $form_info{group}
"; 
    if ($form_info{work}) {
         print OUT_FILE "Full Time Employee
"; 
    } 
    if ($form_info{intern}) {
         print OUT_FILE "Part of the Intern program
"; 
    } 
    if (not defined($form_info{schedule})) {
         print OUT_FILE "*** Did not select a schedule
"; 
    } else {
         print OUT_FILE "Schedule: $form_info{schedule}
"; 
    } 
    print OUT_FILE "Comments:
"; 
    print OUT_FILE "$form_info{comments}
"; 
    close (OUT_FILE); 
} 
print "Content–type: text/html
"; 
print "
"; 
debug(); 
write_report(); 
print <<EOF; 
<H1>Thanks</H1> 
<P> 
Thank you for your time.  Your information has been 
recorded. 
EOF

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset