36.

book home

CGI Programming with Perl


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:

  • Setting the -base argument to a true value tells CGI.pm to include a <BASE HREF="url"> tag in the head of your document that points to the URL of your script.

  • The -meta argument accepts a reference to a hash containing the name and content of meta tags that appear in the head of your document.

  • The -script argument allows you to add JavaScript to the head of your document. You can either provide a string containing the JavaScript code or a reference to a hash containing -language, -src, and -code as possible keys. This allows you to specify the language and source attributes of the <SCRIPT> tag too. CGI.pm automatically provides comment tags around the code to protect it from browsers that do not recognize JavaScript.

  • The -noscript argument allows you to specify HTML display if the browser does not support JavaScript. It is inserted into the head of your document.

  • The -style argument allows you to define a style sheet for the document. Like -script, you may either specify a string or a reference to a hash. The keys that -style accepts in the hash are -code and -src. The value of -code will be inserted into the document as style sheet information. The value of -src will be a URL to a .css file. CGI.pm automatically provides comment tags around the code to protect cascading style sheets from browsers that do not recognize them.

  • The -title argument sets the title of the HTML document.

  • The -xbase argument lets you specify a URL to use in the <BASE HREF="url"> tag. This is different from the -base argument that also generates this tag but sets it to the URL of the current CGI script.

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:

  • CGI.pm recognizes that some elements, like <HR> and <BR>, do not have closing tags. These methods take no arguments and return the single tag:

    print $q->hr;

    This outputs:

    <HR>
  • If you provide one argument, it creates an opening and closing tag to enclose the text of your argument. Tags are capitalized:

    print $q->p( "This is a paragraph." );

    This prints the text:

    <P>This is a paragraph.</P>
  • If you provide multiple arguments, these are simply joined with the tags at the beginning and the end:

    print $q->p( "The server name is:", $q->server_name );

    This prints the text:

    <P>The server name is: localhost</P>

    This usage makes it easy to nest elements:

    print $q->p( "The server name is:", $q->em( $q->server_name ) );

    This prints the text:

    <P>The server name is: <EM>localhost</EM></P>

    Note that a space is automatically added between each list element. It appears after the colon in these examples. If you wish to print multiple items in a list without intervening spaces, then you must set Perl's list separator variable, $", to an empty string:

    {    local $" = "";   print $q->p( "Server=", $q->server_name ); }

    This prints the text:

    <P>Server=Apache/1.3.9</P>

    Note that whenever you change global variables like $", you should localize them by enclosing them in blocks and using Perl's local function.

  • If the first argument is a reference to a hash, then the hash elements are interpreted as attributes for the HTML element:

    print $q->a( { -href => "/downloads" }, "Download Area" );

    This prints the text:

    <A HREF="/downloads" >Download Area</A>

    You can specify as many attributes as you want. The leading hyphen as part of the attribute name is not required, but it is the standard convention.

    Some attributes do not take arguments and simply appear as a word. For these, pass undef as the value of the attribute. Prior to version 2.41 of CGI.pm, passing an empty string would accomplish the same thing, but that was changed so that people could explicitly request an attribute set to an empty string (e.g., <IMG HREF="spacer.gif" ALT="">).

  • If you provide a reference to an array as an argument, the tag is distributed across each item in the array:

    print $q->ol( $q->li( [ "First", "Second", "Third" ] ) );

    This corresponds to:

    <OL>   <LI>First</LI>   <LI>Second</LI>   <LI>Third</LI> </OL>

    This still works fine when the first argument is a reference to a hash arguments. Here is a table:

    print $q->table(                  { -border => 1,                    -width  => "100%" },                  $q->Tr( [                            $q->th( { -bgcolor => "#cccccc" },                                    [ "Name", "Age" ] ),                            $q->td( [ "Mary", 29 ] ),                            $q->td( [ "Bill", 27 ] ),                            $q->td( [ "Sue",  26 ] )                        ] )                );

    This corresponds to:

    <TABLE BORDER="1" WIDTH="100%">   <TR>     <TH BGCOLOR="#cccccc">Name</TH>     <TH BGCOLOR="#cccccc">Age</TH>   </TR>   <TR>     <TD>Mary</TD>     <TD>29</TD>   </TR>   <TR>     <TD>Bill</TD>     <TD>27</TD>   </TR>   <TR>     <TD>Sue</TD>     <TD>26</TD>   </TR> </TABLE>
  • Aside from the spaces we mentioned above that are introduced between array elements, CGI.pm does not insert any whitespace between HTML elements. It creates no indentation and inserts no new lines. Although this makes it harder for a human to read, it also makes the output smaller and downloads faster. If you wish to generate neatly formatted HTML code, you can use the CGI::Pretty module distributed with CGI.pm. It provides all of the features of CGI.pm (because it is an object-oriented module that extends CGI.pm), but the HTML it produces is neatly indented.

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).


5.2. Handling Input with CGI.pm5.4. Alternatives for Generating Output


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



CGI Programming with Perl
CGI Programming with Perl
ISBN: 1565924193
EAN: 2147483647
Year: 1999
Pages: 120

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net