CGI.pm: a Perl Module for Web CGI Programming

Lincoln Stein
Capricorn Consulting
(Converted to HTML by Marjorie Roswell)

What you can do with CGI.pm

What CGI.pm Does

CGI is easy; I can do it myself!

First Example

#!/usr/bin/perl

use CGI ':standard'

print
  header,
  start_html('Example 1'),
     h1('Hello World!'),
     "Wow, I'm speaking HTML!",
     hr,
  end_html;

Output from 1st Example

Content-type: text/html

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <HTML><HEAD> <TITLE>Example 1</TITLE> </HEAD> <BODY> <H1>Hello World!</H1> Wow, I'm speaking HTML! <HR> </BODY> </HTML>

What it Looks Like

Hello World!

Wow, I'm speaking HTML!

CGI Script Basics, Part 1

How CGI Scripts are Executed

The HTTP Header

HTTP/1.0 200 OK

Content-type: text/html
Content-language: en
Content-length: 1255
Expires: 05-Jun-1998 08:20:33 GMT

The header() Function

Content-type: text/html\r\n\r\n

Content-type: image/gif\r\n\r\n

Content-type: image/gif\r\n\r\n

Expires: 22-Aug-1997 08:20:33 GMT

Content-type: image/gif\r\n\r\n

The -status Argument

header() Arguments

-type          -content-encoding
-expires       -content-language
-status        -content-transfer-encoding
-location      -date
-server        -auth-type

anything else in current or future specs

print header(-type=>'image/gif',
             -status=>'402 Payment Required',
             -cost=>'$0.02');

HTML Shortcuts

h1( )
h2( )
h3( )
strong( )
li( )
dl( )
tt( )
p( )
a( )
em( )
ol( )
dt( )
b( )
hr( )
pre( )
ul( )
dd( )
i( )
blockquote( )
etcetera

Using HTML Shortcuts

<P>

<P>This is a paragraph.</P>

This is <B>bold</B> face.

<P ALIGN="CENTER">This is centered.</P>

HTML Shortcuts Nest

print ol({-type=>'A'},
		li('FORTRAN'),
		li('C')
		li('Java'),
		li('Perl')
	);

<OL TYPE="A">
	<li>FORTRAN
	<li>C
	<li>Java
	<li>Perl
</OL>

HTML Shortcuts are Distributive

@lang = qw(FORTRAN C Java Perl);
print ol({-type=>'A'},li(\@lang));

<OL TYPE="A">
	<LI>FORTRAN
	<LI>C
	<LI>Java
	<LI>Perl
</OL>

HTML 3.2 Extensions

use CGI qw(:standard :html3);

print table({-border=>''},
   caption('Table 1'),
	   TR([th(['Language','Power']),
          td(['Fortran', 'Low']),
          td(['C',       'Medium']),
          td(['Java',    'Medium']),
          td(['Perl',    'High'])
		  ]
		)
	);

What it Looks Like

Table 1
LanguagePower
Fortran Low
C Medium
JavaMedium
Perl High

Other Importable Sets

Creating New Shortcuts

use CGI qw(:standard marquee object
		  embed);

print 
  marquee({-text=>'Late breaking news...',
		 -fgcolor=>'yellow',
		 -bgcolor=>'black',
		 -speed=>30});

Non-Standard Shortcuts

start_html()

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML><HEAD>
<TITLE>ABC DEF</TITLE>
</HEAD>
<BODY>

</BODY></HTML>

start_html()Arguments

A start_html()Example

#!/usr/bin/perl

use CGI ':standard';
print
   header,
   start_html(-title=>'Secrets of the Pyramids',
            -author=>'fred@capricorn.org',
		-meta=>{'keywords'=>'pharoah secret mummy',
                    'copyright'=>' 1996 King Tut'},
		-text=>'yellow',
            -bgcolor=>'black');

print h1("I've gone all yellow!"),
      "Isn't CGI fun?",
	hr(),
	end_html();

What it Looks Like

I've gone all yellow!

Isn't CGI fun?

CGI Environment

Access to CGI Environment

A Dynamic Page

use CGI ':standard';
$date = localtime();
$host = remote_host();
$referer = referer();
print
   header,
   start_html(-title=>'A Dynamic Page'),
   h1('A Dynamic Page'),
   <<END,end_html();

Hello!  I see that the name of your machine is
<I>$host</I> and that you were just now reading
the page at <I>$referer</I>.
<HR>
Last modified: <$date< 
END

Dynamic Page Output

Interactive Scripts

Creating Fill-Out Forms

start_form() & end_form()

<FORM METHOD=POST>

</FORM>

start_form parameters

Form Element Arguments

textfield()

<INPUT TYPE="textfield" NAME="comments" VALUE="CGI rocks">

<INPUT TYPE="textfield" NAME="comments" SIZE=50 MAXLENGTH=80>

popup_menu()

  • Output:
    <FORM METHOD="POST" ENCTYPE="application/x-www-form-urlencoded"> <SELECT NAME="flavor" SIZE=1>
    <OPTION>vanilla</OPTION>
    <OPTION SELECTED>orange</OPTION>
    <OPTION>lemon</OPTION>
    </SELECT>

    </FORM>
  • popup_menu() output

    scrolling_list()

    print start_form;

    print scrolling_list(-name=>'toppings',
       -values=>['nuts','sprinkles','Oreos'],
       -defaults=>['sprinkles','nuts'],
       -multiple=>1);

    print end_form;

    Output:
    <FORM METHOD="POST" ENCTYPE="application/x-www-form-urlencoded"> <SELECT NAME="toppings" MULTIPLE SIZE=3>
    <OPTION SELECTED>nuts</OPTION>
    <OPTION SELECTED>sprinkles</OPTION>
    <OPTION>Oreos</OPTION>

    </SELECT>

    </form>

    scrolling_list() output

    Changing List Labels

     scrolling_list(-name=>'toppings',
     	-values=>['nuts','sprinkles','Oreos'],
     	-defaults=>['sprinkles','nuts'],
     	-multiple=>1,
     	-labels=>{nuts=>'Mixed Nuts',
     			sprinkles=>'Jimmies',
     			Oreos=>'Cookie Bits'}	
     	);
    
     

    submit(), reset() & defaults()

    Putting it Together

    sub generate_form {
      print hr, start_form,
       strong('Your name: '),
    	textfield(-name=>'customer'),br,
       strong('Flavor: '),
    	popup_menu(-name=>'flavor',
    	  -values=>[qw/chocolate vanilla lemon/]),br,
       strong('Toppings: '),
    	scrolling_list(-name=>'toppings',
    	  -values=>[qw/nuts sprinkles Oreos/]),br,
       strong('Cone: '),
    	radio_group(-name=>'cone',-multiple=>1,
    	  -values=>[qw/sugar waffle/]),br,
       submit(-value=>'Send Order'),
       end_form,hr;
    }
    

    How it Looks

    Order Ice Cream


    Your name:
    Flavor:
    Toppings:
    Cone: sugar waffle

    Retrieving the Field Values

    $customer = param('customer');
    @toppings = param('topping');

    Complete Example

    #!/usr/bin/perl
    use CGI ':standard';
    
    print header,start_html('Order Ice Cream'),
    	h1('Order Ice Cream');
    
    generate_form();
    print_results if param();
    print end_html();
    
    sub print_results {
       my @top = param('toppings');
       print b('Customer name: '),param('customer'),br,
             "You ordered a ",param('flavor'),' ',
             param('cone'),' cone with ';
       print @top ? join(',',@top) : 'no',' toppings';
    }
    
    sub generate_form {
      print hr, start_form,
       strong('Your name: '),
    	textfield(-name=>'customer'),br,
       strong('Flavor: '),
    	popup_menu(-name=>'flavor',
    	  -values=>[qw/chocolate vanilla lemon/]),br,
       strong('Toppings: '),
    	scrolling_list(-name=>'toppings',
    	  -values=>[qw/nuts sprinkles Oreos/]),br,
       strong('Cone: '),
    	radio_group(-name=>'cone',-multiple=>1,
    	  -values=>[qw/sugar waffle/]),br,
       submit(-value=>'Send Order'),
       end_form,hr;
    }
    

    "Sticky" Field Values

    Example Stickiness

    Manually Setting Fields

    Importing CGI Fields

     param(-name=>'customer',
          -value=>'Dr. Smith');
     param(-name=>'toppings',
          -value=>['nuts','Oreos']);
     import_names('Q');
     print "Customer = $Q::customer";
          Customer = Dr. Smith
     print "Toppings = @Q::toppings";
          Toppings = nuts Oreos
     

    Redirection

    $wday = (localtime())[6];
    if ($wday == 0) {
    print redirect('/closed_sunday.html');
    } else {
    print header()...

    Part 2: Advanced Techniques

    Debugging from Command Line

    2 Ways to Run Without Waiting

    Handling Funny Characters

    Object-Oriented Style

    Example OO Style

    #!/usr/bin/perl
    use CGI;
    $q = new CGI;
    print $q->header(),
    	$q->start_html('Object Oriented'),
    	$q->h1('Object Oriented');
    if ($q->param) {
    	print "Your name is ",
             $q->param('name');
    
    

    CGI Object Initialization

    $q = new CGI({'dinosaur'=>'barney',
    'color'=>'purple',
    'friends'=>[qw/Jessica George Ann/]});

    $q=new CGI('dinosaur=barney&color=purple')

    open(INPUT,"foobar.txt");
    $q=new CGI(INPUT);

    Saving & Restoring CGI Objects

    use CGI;
    $q = new CGI;
    open (STATE,">save.txt");
    $q->save(STATE); # save(\*STATE);
    close STATE;
    
    open (IN,"save.txt"):
    $r = new CGI(IN); # new CGI(\*IN)
    close IN;
    

    Format of a Saved CGI Object

    dinosaur=Barney
    color=purple
    friends=Jessica
    friends=George
    friends=Ann
    =
    dinosaur=Godzilla
    color=green
    friends=Tokyo Redevelopment Authority
    =
    

    Reading States from a Database

    use CGI;
    
    open (IN,"state.txt"):
    while (!eof(IN)) {
    	push(@q,new CGI(IN));
    }
    close IN;
    

    Accessing Internal CGI Object

    use CGI ':standard';
    @fields = param();
    $CGI::Q->save(OUT);

    File Upload

    Generating Fill-Out Form

    print start_multipart_form(),
    	"Enter the file to upload: ",
    	filefield(-name=>'uploaded file'),
    	end_form();
    

    Reading the File

    $filehandle = param('uploaded file');
    exit 0 unless $filehandle;

    while (<$filehandle>) { do_something(); }

    while (read($filehandle,$scalar,1024)) {
    do_something($scalar);
    }

    Other Things You Can Do

    $filename = param('uploaded file');

    $filename = param('uploaded file');
    $info = uploadInfo($filename);
    $type = $info->{'Content-Type'};
    die "Text files only"
    unless $type =~ /^text/;

    Accessing Temporary File

    $filename = param('uploaded file');

    $tmpfile = tmpFileName($filename);

    Cookies

    Working with Cookies

    1. Create cookie
    2. Send it in outgoing HTTP header
    3. Recover old cookies from incoming HTTP header

    Creating & Sending Cookies

    use CGI qw/:standard/;
    
    $cookie = cookie(
         -name=>'favorite_color',
         -value=>'puce',
         -expires=>'+3d');
    
    print header(-cookie=>$cookie);
    

    cookie() arguments

    -value flexible

    $c = cookie(-name=>'color',-value=>'puce';

    $c = cookie(-name=>'colors',
       -value=>['puce','mauve','red'];

    Sending Multiple Cookies

    $c1 = cookie(
       -name=>'favorite_color',
       -value=>'puce',
       -expires=>'+3d');
    $c2 = cookie(
       -name=>'favorite_shape',
       -value=>'octagon');
    
    print header(-cookie=>[$c1,$c2]);
    

    Retrieving Cookies

    $color = cookie('favorite_color');
    @color = cookie('colors');
    %preferences = cookie('preferences');

    foreach $c (cookie()) {
    process_cookie(cookie($c));

    }

    Cascading Style Sheets

    Defining a Style Sheet

    Stylesheet example

    $newStyle=<<:END;
    <!-- P.Tip {
            margin-right: 50pt;
            margin-left: 50pt; }
        P.Alert {
           font-size: 30pt;
           font-family: sans-serif;
           color: red; } -->
    END
    print start_html(-style=>$newStyle);
    print p({-class=>Alert},"Watch out!");
    print span({-style=>"Color: magenta"},
        "Here's some magenta text.");
    

    JavaScript

    Attach JavaScript to Page with start_html()

    $jscript=<<END;
    function riddle_me_this() {
       var r = prompt("What walks on four legs, " +
                       "two legs, three legs?");
             response(r);}
    END
    print start_html(-title=>'A Riddle',
                     -script=>$jscript);
    
    print start_html(-title=>'A Riddle',
                     -script=>{-language=>'JavaScript",
                     -src=>'/JS/riddle.js'}
                    );
    

    Creating Event Handlers

    print start_form(-onSubmit=>'check_answer()'),
       button(-name=>'button1',
              -value=>'Ask the riddle',
              -onClick=>'riddle_me_this()'),
       submit(-name=>'submission button',
              -value=>'Check answer'),
       end_form();
    

    Clickable Image Maps

    Using Frames

    print header(-target=>'frame3');

    print start_form(-target=>'results');

    NPH Scripts

    Activating NPH Mode

    mod_perl

    FastCGI

    use CGI::Fast qw/:standard/;
    while (new CGI::Fast) {
       print header,
          start_html('Hi!')...
    }
    

    Server Push

    Better Error Reporting

    Using CGI::Carp

    Send error messages to log file

    use CGI::Carp 'carpout';
    open(LOG,">>/usr/logs/cgi.log");
    carpout(LOG);
    die "Oh dear, something bad happened!\n";
    

    Future Directions for CGI.pm

    URL FOR THIS TALK