Book HomeCGI Programming with PerlSearch this book

5.3. Generating Output with CGI.pm

CGI.pm provides a very elegant solution for outputting both headers and HTML with Perl. It allows you to embed HTML in your code, but it makes this more natural by turning the HTML into code. Every HTML element can be generated via a corresponding method in CGI.pm. We have already seen some examples of this already, but here's another:

#!/usr/bin/perl -wT

use strict;
use CGI;

my $q = new CGI;
my $timestamp = localtime;

print $q->header( "text/html" ),
      $q->start_html( -title => "The Time", -bgcolor => "#ffffff" ),
      $q->h2( "Current Time" ),
      $q->hr,
      $q->p( "The current time according to this system is: ",
             $q->b( $timestamp ) ),
      $q->end_html;

The resulting output looks like this (the indentation is added to make it easier to read):

Content-type: text/html

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
  <HEAD><TITLE>The Time</TITLE></HEAD>
  <BODY BGCOLOR="#ffffff">
    <H2>Current Time</H2>
    <HR>
    <P>The current time according to this system is:
      <B>Mon May 29 16:48:14 2000</B></P>
  </BODY>
</HTML>

As you can see, the code looks a lot like Perl and a lot less like HTML. It is also shorter than the corresponding HTML because CGI.pm manages some common tags for us. Another benefit is that it is impossible to forget to close a tag because the methods automatically generate closing tags (except for those elements that CGI.pm knows do not need them, like <HR>).

We'll look at all of these output methods in this section, starting with the first method, header.

5.3.1. Controlling HTTP Headers with CGI.pm

CGI.pm has two methods for returning HTTP headers: header and redirect. They correspond to the two ways you can return data from CGI scripts: you can return a document, or you can redirect to another document.

5.3.1.1. Media type

The header method handles multiple HTTP headers for you. If you pass it one argument, it returns the Content-type header with that value. If you do not supply a media type, it defaults to "text/html". Although CGI.pm makes outputting HTML much easier, you can of course print any content type with it. Simply use the header method to specify the media type and then print your content, whether it be text, XML, Adobe PDF, etc.:

print $q->header( "text/plain" );
print "This is just some boring text.\n";

If you want to set other headers, then you need to pass name-value pairs for each header. Use the -type argument to specify the media type (see the example under Section 5.3.1.2, "Status" later in this chapter).

5.3.1.2. Status

You can specify a status other than "200 OK" by using the -status argument:

print $q->header( -type => "text/html", -status => "404 Not Found" );

5.3.1.3. Caching

Browsers can't always tell if content is being dynamically generated by CGI or if it is coming from a static source, and they may try to cache the output of your script. You can disable this or request caching if you want it, by using the -expires argument. You can supply either a full time stamp with this argument or a relative time. Relative times are created by supplying a plus or minus sign for forward or backward, an integer number, and a one letter abbreviation for second, minute, hour, day, month, or year (each of these abbreviations is lowercase except for month, which is an uppercase M). You can also use "now" to indicate that a document should expire immediately. Specifying a negative value also has this effect.

This example tells the browser that this document is good for the next 30 minutes:

print $q->header( -type => "text/html", -expires => "+30m" );

5.3.1.4. Specifying an alternative target

If you are using frames or have multiple windows, you may want links in one document to update another document. You can use the -target argument along with the name of the other document (as set by a <FRAMESET> tag or by JavaScript) to specify that clicking on a link in this document should cause the new resource to load in the other frame (or window):

print $q->header( -type => "text/html", -target => "main_frame" );

This argument is only meaningful for HTML documents.

5.3.1.5. Redirection

If you need to redirect to another URL, you can use the redirect method instead of printing the Location HTTP header:

print $q->redirect( "http://localhost/survey/thanks.html" );

Although the term "redirect" is an action, this method does not perform a redirect for you; it simply returns the corresponding header. So don't forget you still need to print the result!

5.3.1.6. Other headers

If you need to generate other HTTP headers, you can simply pass the name-value pair to header and it will return the header with the appropriate formatting. Underscores are converted to hyphens for you.

Thus, the following statement:

print $q->header( -content_encoding  => "gzip" );

produces the following output:

Content-encoding: gzip

5.3.2. Starting and Ending Documents

Now let's look at the methods that you can use to generate HTML. We'll start by looking at the methods for starting and ending documents.

5.3.2.1. start_html

The start_html method returns the HTML DTD, the <HTML> tag, the <HEAD> section including <TITLE>, and the <BODY> tag. In the previous example, it generates HTML like the following:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML><HEAD><TITLE>The Time</TITLE>
</HEAD><BODY BGCOLOR="#ffffff">

The most common arguments start_html recognizes are as follows:

Any other arguments, like -bgcolor, are passed as attributes to the <BODY> tag.

5.3.2.2. end_html

The end_html method returns the </BODY> and </HTML> tags.

5.3.3. Standard HTML Elements

HTML elements can be generated by using the lowercase name of the element as a method, with the following exceptions: Accept, Delete, Link, Param, Select, Sub, and Tr. These methods have an initial cap to avoid conflicting with built-in Perl functions and other CGI.pm methods.

The following rules apply to basic HTML tags:

5.3.4. Form Elements

The syntax for generating form elements differs from other elements. These methods only take name-value pairs that correspond to the attributes. See Table 5-2.

Table 5-2. CGI.pm Methods for HTML Form Elements

CGI.pm Method

HTML Tag

start_form

<FORM>

end_form

</FORM>

textfield

<INPUT TYPE="TEXT" >

password_field

<INPUT TYPE="PASSWORD" >

filefield

<INPUT TYPE="FILE" >

button

<INPUT TYPE="BUTTON" >

submit

<INPUT TYPE="SUBMIT" >

reset

<INPUT TYPE="RESET" >

checkbox, checkbox_group

<INPUT TYPE="CHECKBOX" >

radio_group

<INPUT TYPE="RADIO" >

popup_menu

<SELECT SIZE="1" >

scrolling_list

<SELECT SIZE="n" > where n > 1

textarea

<TEXTAREA>

hidden

<INPUT TYPE="HIDDEN" >

The start_form and end_form elements generate the opening and closing form tags. start_form takes arguments for each of its attributes:

print $q->start_form( method => "get", action => "/cgi/myscript.cgi" );

Note that unlike a typical form tag, CGI.pm sets the request method to POST instead of GET by default (the reverse of the default for HTML forms). If you want to allow file uploads, use the start_multipart_form method instead of start_form, which sets enctype to "multipart/form-data".

All of the remaining methods create form elements. They all take the -name and -default arguments. The -default value for an element is replaced by the corresponding value from param if that value exists. You can disable this and force the default to override a user's parameters by passing the -override argument with a true value.

The -default option specifies the default value of the element for elements with single values:

print $q->textfield(
        -name    => "username",
        -default => "Anonymous"
      );

This yields:

<INPUT TYPE="text" NAME="username" VALUE="Anonymous">

By supplying an array with the -values argument, the checkbox_group and radio_group methods generate multiple checkboxes that share the same name. Likewise, passing an array reference with the -values argument to the scrolling_list and popup_menu functions generates both the <SELECT> and <OPTION> elements. For these elements, -default indicates the values that are checked or selected; you can pass -default a reference to an array for checkbox_group and scrolling_list for multiple defaults.

Each method accepts a -labels argument that takes a reference to a hash; this hash associates the value of each element to the label the browser displays to the user.

Here is how you can generate a group of radio buttons:

print $q->radio_group(
        -name    => "curtain",
        -values  => [ "A", "B", "C" ],
        -default => "B",
        -labels  => { A => "Curtain A", B => "Curtain B", C => "Curtain C" }
      );

This yields:

<INPUT TYPE="radio" NAME="look_behind" VALUE="A">Curtain A
<INPUT TYPE="radio" NAME="look_behind" VALUE="B" CHECKED>Curtain B
<INPUT TYPE="radio" NAME="look_behind" VALUE="C">Curtain C

For specifying any other attributes for form elements, like SIZE=4, pass them as additional arguments (e.g., size => 4).



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.