10Sstevel@tonic-gatepackage CGI; 20Sstevel@tonic-gaterequire 5.004; 30Sstevel@tonic-gateuse Carp 'croak'; 40Sstevel@tonic-gate 50Sstevel@tonic-gate# See the bottom of this file for the POD documentation. Search for the 60Sstevel@tonic-gate# string '=head'. 70Sstevel@tonic-gate 80Sstevel@tonic-gate# You can run this file through either pod2man or pod2html to produce pretty 90Sstevel@tonic-gate# documentation in manual or html file format (these utilities are part of the 100Sstevel@tonic-gate# Perl 5 distribution). 110Sstevel@tonic-gate 120Sstevel@tonic-gate# Copyright 1995-1998 Lincoln D. Stein. All rights reserved. 130Sstevel@tonic-gate# It may be used and modified freely, but I do request that this copyright 140Sstevel@tonic-gate# notice remain attached to the file. You may modify this module as you 150Sstevel@tonic-gate# wish, but if you redistribute a modified version, please attach a note 160Sstevel@tonic-gate# listing the modifications you have made. 170Sstevel@tonic-gate 180Sstevel@tonic-gate# The most recent version and complete docs are available at: 190Sstevel@tonic-gate# http://stein.cshl.org/WWW/software/CGI/ 200Sstevel@tonic-gate 21*6287Sps156622$CGI::revision = '$Id: CGI.pm,v 1.241 2007/12/27 18:37:43 lstein Exp $'; 22*6287Sps156622$CGI::VERSION='3.33'; 230Sstevel@tonic-gate 240Sstevel@tonic-gate# HARD-CODED LOCATION FOR FILE UPLOAD TEMPORARY FILES. 250Sstevel@tonic-gate# UNCOMMENT THIS ONLY IF YOU KNOW WHAT YOU'RE DOING. 260Sstevel@tonic-gate# $CGITempFile::TMPDIRECTORY = '/usr/tmp'; 270Sstevel@tonic-gateuse CGI::Util qw(rearrange make_attributes unescape escape expires ebcdic2ascii ascii2ebcdic); 280Sstevel@tonic-gate 290Sstevel@tonic-gate#use constant XHTML_DTD => ['-//W3C//DTD XHTML Basic 1.0//EN', 300Sstevel@tonic-gate# 'http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd']; 310Sstevel@tonic-gate 320Sstevel@tonic-gateuse constant XHTML_DTD => ['-//W3C//DTD XHTML 1.0 Transitional//EN', 330Sstevel@tonic-gate 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd']; 340Sstevel@tonic-gate 350Sstevel@tonic-gate{ 360Sstevel@tonic-gate local $^W = 0; 370Sstevel@tonic-gate $TAINTED = substr("$0$^X",0,0); 380Sstevel@tonic-gate} 390Sstevel@tonic-gate 400Sstevel@tonic-gate$MOD_PERL = 0; # no mod_perl by default 41667Sps156622@SAVED_SYMBOLS = (); 420Sstevel@tonic-gate 43*6287Sps156622 440Sstevel@tonic-gate# >>>>> Here are some globals that you might want to adjust <<<<<< 450Sstevel@tonic-gatesub initialize_globals { 460Sstevel@tonic-gate # Set this to 1 to enable copious autoloader debugging messages 470Sstevel@tonic-gate $AUTOLOAD_DEBUG = 0; 480Sstevel@tonic-gate 490Sstevel@tonic-gate # Set this to 1 to generate XTML-compatible output 500Sstevel@tonic-gate $XHTML = 1; 510Sstevel@tonic-gate 520Sstevel@tonic-gate # Change this to the preferred DTD to print in start_html() 530Sstevel@tonic-gate # or use default_dtd('text of DTD to use'); 540Sstevel@tonic-gate $DEFAULT_DTD = [ '-//W3C//DTD HTML 4.01 Transitional//EN', 550Sstevel@tonic-gate 'http://www.w3.org/TR/html4/loose.dtd' ] ; 560Sstevel@tonic-gate 570Sstevel@tonic-gate # Set this to 1 to enable NOSTICKY scripts 580Sstevel@tonic-gate # or: 590Sstevel@tonic-gate # 1) use CGI qw(-nosticky) 600Sstevel@tonic-gate # 2) $CGI::nosticky(1) 610Sstevel@tonic-gate $NOSTICKY = 0; 620Sstevel@tonic-gate 630Sstevel@tonic-gate # Set this to 1 to enable NPH scripts 640Sstevel@tonic-gate # or: 650Sstevel@tonic-gate # 1) use CGI qw(-nph) 660Sstevel@tonic-gate # 2) CGI::nph(1) 670Sstevel@tonic-gate # 3) print header(-nph=>1) 680Sstevel@tonic-gate $NPH = 0; 690Sstevel@tonic-gate 700Sstevel@tonic-gate # Set this to 1 to enable debugging from @ARGV 710Sstevel@tonic-gate # Set to 2 to enable debugging from STDIN 720Sstevel@tonic-gate $DEBUG = 1; 730Sstevel@tonic-gate 740Sstevel@tonic-gate # Set this to 1 to make the temporary files created 750Sstevel@tonic-gate # during file uploads safe from prying eyes 760Sstevel@tonic-gate # or do... 770Sstevel@tonic-gate # 1) use CGI qw(:private_tempfiles) 780Sstevel@tonic-gate # 2) CGI::private_tempfiles(1); 790Sstevel@tonic-gate $PRIVATE_TEMPFILES = 0; 800Sstevel@tonic-gate 81*6287Sps156622 # Set this to 1 to generate automatic tab indexes 82*6287Sps156622 $TABINDEX = 0; 83*6287Sps156622 840Sstevel@tonic-gate # Set this to 1 to cause files uploaded in multipart documents 850Sstevel@tonic-gate # to be closed, instead of caching the file handle 860Sstevel@tonic-gate # or: 870Sstevel@tonic-gate # 1) use CGI qw(:close_upload_files) 880Sstevel@tonic-gate # 2) $CGI::close_upload_files(1); 890Sstevel@tonic-gate # Uploads with many files run out of file handles. 900Sstevel@tonic-gate # Also, for performance, since the file is already on disk, 910Sstevel@tonic-gate # it can just be renamed, instead of read and written. 920Sstevel@tonic-gate $CLOSE_UPLOAD_FILES = 0; 930Sstevel@tonic-gate 940Sstevel@tonic-gate # Set this to a positive value to limit the size of a POSTing 950Sstevel@tonic-gate # to a certain number of bytes: 960Sstevel@tonic-gate $POST_MAX = -1; 970Sstevel@tonic-gate 980Sstevel@tonic-gate # Change this to 1 to disable uploads entirely: 990Sstevel@tonic-gate $DISABLE_UPLOADS = 0; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate # Automatically determined -- don't change 1020Sstevel@tonic-gate $EBCDIC = 0; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate # Change this to 1 to suppress redundant HTTP headers 1050Sstevel@tonic-gate $HEADERS_ONCE = 0; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate # separate the name=value pairs by semicolons rather than ampersands 1080Sstevel@tonic-gate $USE_PARAM_SEMICOLONS = 1; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate # Do not include undefined params parsed from query string 1110Sstevel@tonic-gate # use CGI qw(-no_undef_params); 1120Sstevel@tonic-gate $NO_UNDEF_PARAMS = 0; 1130Sstevel@tonic-gate 114*6287Sps156622 # return everything as utf-8 115*6287Sps156622 $PARAM_UTF8 = 0; 116*6287Sps156622 1170Sstevel@tonic-gate # Other globals that you shouldn't worry about. 1180Sstevel@tonic-gate undef $Q; 1190Sstevel@tonic-gate $BEEN_THERE = 0; 120667Sps156622 $DTD_PUBLIC_IDENTIFIER = ""; 1210Sstevel@tonic-gate undef @QUERY_PARAM; 1220Sstevel@tonic-gate undef %EXPORT; 1230Sstevel@tonic-gate undef $QUERY_CHARSET; 1240Sstevel@tonic-gate undef %QUERY_FIELDNAMES; 125*6287Sps156622 undef %QUERY_TMPFILES; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate # prevent complaints by mod_perl 1280Sstevel@tonic-gate 1; 1290Sstevel@tonic-gate} 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate# ------------------ START OF THE LIBRARY ------------ 1320Sstevel@tonic-gate 133667Sps156622*end_form = \&endform; 134667Sps156622 1350Sstevel@tonic-gate# make mod_perlhappy 1360Sstevel@tonic-gateinitialize_globals(); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate# FIGURE OUT THE OS WE'RE RUNNING UNDER 1390Sstevel@tonic-gate# Some systems support the $^O variable. If not 1400Sstevel@tonic-gate# available then require() the Config library 1410Sstevel@tonic-gateunless ($OS) { 1420Sstevel@tonic-gate unless ($OS = $^O) { 1430Sstevel@tonic-gate require Config; 1440Sstevel@tonic-gate $OS = $Config::Config{'osname'}; 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate} 1470Sstevel@tonic-gateif ($OS =~ /^MSWin/i) { 1480Sstevel@tonic-gate $OS = 'WINDOWS'; 1490Sstevel@tonic-gate} elsif ($OS =~ /^VMS/i) { 1500Sstevel@tonic-gate $OS = 'VMS'; 1510Sstevel@tonic-gate} elsif ($OS =~ /^dos/i) { 1520Sstevel@tonic-gate $OS = 'DOS'; 1530Sstevel@tonic-gate} elsif ($OS =~ /^MacOS/i) { 1540Sstevel@tonic-gate $OS = 'MACINTOSH'; 1550Sstevel@tonic-gate} elsif ($OS =~ /^os2/i) { 1560Sstevel@tonic-gate $OS = 'OS2'; 1570Sstevel@tonic-gate} elsif ($OS =~ /^epoc/i) { 1580Sstevel@tonic-gate $OS = 'EPOC'; 1590Sstevel@tonic-gate} elsif ($OS =~ /^cygwin/i) { 1600Sstevel@tonic-gate $OS = 'CYGWIN'; 1610Sstevel@tonic-gate} else { 1620Sstevel@tonic-gate $OS = 'UNIX'; 1630Sstevel@tonic-gate} 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate# Some OS logic. Binary mode enabled on DOS, NT and VMS 1660Sstevel@tonic-gate$needs_binmode = $OS=~/^(WINDOWS|DOS|OS2|MSWin|CYGWIN)/; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate# This is the default class for the CGI object to use when all else fails. 1690Sstevel@tonic-gate$DefaultClass = 'CGI' unless defined $CGI::DefaultClass; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate# This is where to look for autoloaded routines. 1720Sstevel@tonic-gate$AutoloadClass = $DefaultClass unless defined $CGI::AutoloadClass; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate# The path separator is a slash, backslash or semicolon, depending 1750Sstevel@tonic-gate# on the paltform. 1760Sstevel@tonic-gate$SL = { 1770Sstevel@tonic-gate UNIX => '/', OS2 => '\\', EPOC => '/', CYGWIN => '/', 1780Sstevel@tonic-gate WINDOWS => '\\', DOS => '\\', MACINTOSH => ':', VMS => '/' 1790Sstevel@tonic-gate }->{$OS}; 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate# This no longer seems to be necessary 1820Sstevel@tonic-gate# Turn on NPH scripts by default when running under IIS server! 1830Sstevel@tonic-gate# $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/; 1840Sstevel@tonic-gate$IIS++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate# Turn on special checking for Doug MacEachern's modperl 1870Sstevel@tonic-gateif (exists $ENV{MOD_PERL}) { 1880Sstevel@tonic-gate # mod_perl handlers may run system() on scripts using CGI.pm; 1890Sstevel@tonic-gate # Make sure so we don't get fooled by inherited $ENV{MOD_PERL} 190667Sps156622 if (exists $ENV{MOD_PERL_API_VERSION} && $ENV{MOD_PERL_API_VERSION} == 2) { 191667Sps156622 $MOD_PERL = 2; 192667Sps156622 require Apache2::Response; 193667Sps156622 require Apache2::RequestRec; 194667Sps156622 require Apache2::RequestUtil; 195667Sps156622 require Apache2::RequestIO; 196667Sps156622 require APR::Pool; 197667Sps156622 } else { 198667Sps156622 $MOD_PERL = 1; 199667Sps156622 require Apache; 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate} 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate# Turn on special checking for ActiveState's PerlEx 2040Sstevel@tonic-gate$PERLEX++ if defined($ENV{'GATEWAY_INTERFACE'}) && $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-PerlEx/; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate# Define the CRLF sequence. I can't use a simple "\r\n" because the meaning 2070Sstevel@tonic-gate# of "\n" is different on different OS's (sometimes it generates CRLF, sometimes LF 2080Sstevel@tonic-gate# and sometimes CR). The most popular VMS web server 2090Sstevel@tonic-gate# doesn't accept CRLF -- instead it wants a LR. EBCDIC machines don't 2100Sstevel@tonic-gate# use ASCII, so \015\012 means something different. I find this all 2110Sstevel@tonic-gate# really annoying. 2120Sstevel@tonic-gate$EBCDIC = "\t" ne "\011"; 2130Sstevel@tonic-gateif ($OS eq 'VMS') { 2140Sstevel@tonic-gate $CRLF = "\n"; 2150Sstevel@tonic-gate} elsif ($EBCDIC) { 2160Sstevel@tonic-gate $CRLF= "\r\n"; 2170Sstevel@tonic-gate} else { 2180Sstevel@tonic-gate $CRLF = "\015\012"; 2190Sstevel@tonic-gate} 2200Sstevel@tonic-gate 2210Sstevel@tonic-gateif ($needs_binmode) { 2220Sstevel@tonic-gate $CGI::DefaultClass->binmode(\*main::STDOUT); 2230Sstevel@tonic-gate $CGI::DefaultClass->binmode(\*main::STDIN); 2240Sstevel@tonic-gate $CGI::DefaultClass->binmode(\*main::STDERR); 2250Sstevel@tonic-gate} 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate%EXPORT_TAGS = ( 2280Sstevel@tonic-gate ':html2'=>['h1'..'h6',qw/p br hr ol ul li dl dt dd menu code var strong em 2290Sstevel@tonic-gate tt u i b blockquote pre img a address cite samp dfn html head 2300Sstevel@tonic-gate base body Link nextid title meta kbd start_html end_html 2310Sstevel@tonic-gate input Select option comment charset escapeHTML/], 2320Sstevel@tonic-gate ':html3'=>[qw/div table caption th td TR Tr sup Sub strike applet Param 2330Sstevel@tonic-gate embed basefont style span layer ilayer font frameset frame script small big Area Map/], 2340Sstevel@tonic-gate ':html4'=>[qw/abbr acronym bdo col colgroup del fieldset iframe 2350Sstevel@tonic-gate ins label legend noframes noscript object optgroup Q 2360Sstevel@tonic-gate thead tbody tfoot/], 2370Sstevel@tonic-gate ':netscape'=>[qw/blink fontsize center/], 2380Sstevel@tonic-gate ':form'=>[qw/textfield textarea filefield password_field hidden checkbox checkbox_group 2390Sstevel@tonic-gate submit reset defaults radio_group popup_menu button autoEscape 2400Sstevel@tonic-gate scrolling_list image_button start_form end_form startform endform 2410Sstevel@tonic-gate start_multipart_form end_multipart_form isindex tmpFileName uploadInfo URL_ENCODED MULTIPART/], 242667Sps156622 ':cgi'=>[qw/param upload path_info path_translated request_uri url self_url script_name 243667Sps156622 cookie Dump 2440Sstevel@tonic-gate raw_cookie request_method query_string Accept user_agent remote_host content_type 2450Sstevel@tonic-gate remote_addr referer server_name server_software server_port server_protocol virtual_port 2460Sstevel@tonic-gate virtual_host remote_ident auth_type http append 2470Sstevel@tonic-gate save_parameters restore_parameters param_fetch 2480Sstevel@tonic-gate remote_user user_name header redirect import_names put 2490Sstevel@tonic-gate Delete Delete_all url_param cgi_error/], 2500Sstevel@tonic-gate ':ssl' => [qw/https/], 2510Sstevel@tonic-gate ':cgi-lib' => [qw/ReadParse PrintHeader HtmlTop HtmlBot SplitParam Vars/], 2520Sstevel@tonic-gate ':html' => [qw/:html2 :html3 :html4 :netscape/], 2530Sstevel@tonic-gate ':standard' => [qw/:html2 :html3 :html4 :form :cgi/], 2540Sstevel@tonic-gate ':push' => [qw/multipart_init multipart_start multipart_end multipart_final/], 2550Sstevel@tonic-gate ':all' => [qw/:html2 :html3 :netscape :form :cgi :internal :html4/] 2560Sstevel@tonic-gate ); 2570Sstevel@tonic-gate 258667Sps156622# Custom 'can' method for both autoloaded and non-autoloaded subroutines. 259667Sps156622# Author: Cees Hek <cees@sitesuite.com.au> 260667Sps156622 261667Sps156622sub can { 262667Sps156622 my($class, $method) = @_; 263667Sps156622 264667Sps156622 # See if UNIVERSAL::can finds it. 265667Sps156622 266667Sps156622 if (my $func = $class -> SUPER::can($method) ){ 267667Sps156622 return $func; 268667Sps156622 } 269667Sps156622 270667Sps156622 # Try to compile the function. 271667Sps156622 272667Sps156622 eval { 273667Sps156622 # _compile looks at $AUTOLOAD for the function name. 274667Sps156622 275667Sps156622 local $AUTOLOAD = join "::", $class, $method; 276667Sps156622 &_compile; 277667Sps156622 }; 278667Sps156622 279667Sps156622 # Now that the function is loaded (if it exists) 280667Sps156622 # just use UNIVERSAL::can again to do the work. 281667Sps156622 282667Sps156622 return $class -> SUPER::can($method); 283667Sps156622} 284667Sps156622 2850Sstevel@tonic-gate# to import symbols into caller 2860Sstevel@tonic-gatesub import { 2870Sstevel@tonic-gate my $self = shift; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate # This causes modules to clash. 2900Sstevel@tonic-gate undef %EXPORT_OK; 2910Sstevel@tonic-gate undef %EXPORT; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate $self->_setup_symbols(@_); 2940Sstevel@tonic-gate my ($callpack, $callfile, $callline) = caller; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate # To allow overriding, search through the packages 2970Sstevel@tonic-gate # Till we find one in which the correct subroutine is defined. 2980Sstevel@tonic-gate my @packages = ($self,@{"$self\:\:ISA"}); 2990Sstevel@tonic-gate foreach $sym (keys %EXPORT) { 3000Sstevel@tonic-gate my $pck; 3010Sstevel@tonic-gate my $def = ${"$self\:\:AutoloadClass"} || $DefaultClass; 3020Sstevel@tonic-gate foreach $pck (@packages) { 3030Sstevel@tonic-gate if (defined(&{"$pck\:\:$sym"})) { 3040Sstevel@tonic-gate $def = $pck; 3050Sstevel@tonic-gate last; 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate *{"${callpack}::$sym"} = \&{"$def\:\:$sym"}; 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate} 3110Sstevel@tonic-gate 3120Sstevel@tonic-gatesub compile { 3130Sstevel@tonic-gate my $pack = shift; 3140Sstevel@tonic-gate $pack->_setup_symbols('-compile',@_); 3150Sstevel@tonic-gate} 3160Sstevel@tonic-gate 3170Sstevel@tonic-gatesub expand_tags { 3180Sstevel@tonic-gate my($tag) = @_; 3190Sstevel@tonic-gate return ("start_$1","end_$1") if $tag=~/^(?:\*|start_|end_)(.+)/; 3200Sstevel@tonic-gate my(@r); 3210Sstevel@tonic-gate return ($tag) unless $EXPORT_TAGS{$tag}; 3220Sstevel@tonic-gate foreach (@{$EXPORT_TAGS{$tag}}) { 3230Sstevel@tonic-gate push(@r,&expand_tags($_)); 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate return @r; 3260Sstevel@tonic-gate} 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate#### Method: new 3290Sstevel@tonic-gate# The new routine. This will check the current environment 3300Sstevel@tonic-gate# for an existing query string, and initialize itself, if so. 3310Sstevel@tonic-gate#### 3320Sstevel@tonic-gatesub new { 3330Sstevel@tonic-gate my($class,@initializer) = @_; 3340Sstevel@tonic-gate my $self = {}; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate bless $self,ref $class || $class || $DefaultClass; 337*6287Sps156622 338*6287Sps156622 # always use a tempfile 339*6287Sps156622 $self->{'use_tempfile'} = 1; 340*6287Sps156622 3410Sstevel@tonic-gate if (ref($initializer[0]) 3420Sstevel@tonic-gate && (UNIVERSAL::isa($initializer[0],'Apache') 3430Sstevel@tonic-gate || 344667Sps156622 UNIVERSAL::isa($initializer[0],'Apache2::RequestRec') 3450Sstevel@tonic-gate )) { 3460Sstevel@tonic-gate $self->r(shift @initializer); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate if (ref($initializer[0]) 3490Sstevel@tonic-gate && (UNIVERSAL::isa($initializer[0],'CODE'))) { 3500Sstevel@tonic-gate $self->upload_hook(shift @initializer, shift @initializer); 351*6287Sps156622 $self->{'use_tempfile'} = shift @initializer if (@initializer > 0); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate if ($MOD_PERL) { 3540Sstevel@tonic-gate if ($MOD_PERL == 1) { 355667Sps156622 $self->r(Apache->request) unless $self->r; 356667Sps156622 my $r = $self->r; 3570Sstevel@tonic-gate $r->register_cleanup(\&CGI::_reset_globals); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate else { 3600Sstevel@tonic-gate # XXX: once we have the new API 3610Sstevel@tonic-gate # will do a real PerlOptions -SetupEnv check 362667Sps156622 $self->r(Apache2::RequestUtil->request) unless $self->r; 363667Sps156622 my $r = $self->r; 3640Sstevel@tonic-gate $r->subprocess_env unless exists $ENV{REQUEST_METHOD}; 3650Sstevel@tonic-gate $r->pool->cleanup_register(\&CGI::_reset_globals); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate undef $NPH; 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate $self->_reset_globals if $PERLEX; 3700Sstevel@tonic-gate $self->init(@initializer); 3710Sstevel@tonic-gate return $self; 3720Sstevel@tonic-gate} 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate# We provide a DESTROY method so that we can ensure that 3750Sstevel@tonic-gate# temporary files are closed (via Fh->DESTROY) before they 3760Sstevel@tonic-gate# are unlinked (via CGITempFile->DESTROY) because it is not 3770Sstevel@tonic-gate# possible to unlink an open file on Win32. We explicitly 3780Sstevel@tonic-gate# call DESTROY on each, rather than just undefing them and 3790Sstevel@tonic-gate# letting Perl DESTROY them by garbage collection, in case the 3800Sstevel@tonic-gate# user is still holding any reference to them as well. 3810Sstevel@tonic-gatesub DESTROY { 3820Sstevel@tonic-gate my $self = shift; 383*6287Sps156622 if ($OS eq 'WINDOWS') { 384*6287Sps156622 foreach my $href (values %{$self->{'.tmpfiles'}}) { 385*6287Sps156622 $href->{hndl}->DESTROY if defined $href->{hndl}; 386*6287Sps156622 $href->{name}->DESTROY if defined $href->{name}; 387*6287Sps156622 } 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate} 3900Sstevel@tonic-gate 3910Sstevel@tonic-gatesub r { 3920Sstevel@tonic-gate my $self = shift; 3930Sstevel@tonic-gate my $r = $self->{'.r'}; 3940Sstevel@tonic-gate $self->{'.r'} = shift if @_; 3950Sstevel@tonic-gate $r; 3960Sstevel@tonic-gate} 3970Sstevel@tonic-gate 3980Sstevel@tonic-gatesub upload_hook { 399*6287Sps156622 my $self; 400*6287Sps156622 if (ref $_[0] eq 'CODE') { 401*6287Sps156622 $CGI::Q = $self = $CGI::DefaultClass->new(@_); 402*6287Sps156622 } else { 403*6287Sps156622 $self = shift; 404*6287Sps156622 } 405*6287Sps156622 my ($hook,$data,$use_tempfile) = @_; 4060Sstevel@tonic-gate $self->{'.upload_hook'} = $hook; 4070Sstevel@tonic-gate $self->{'.upload_data'} = $data; 408*6287Sps156622 $self->{'use_tempfile'} = $use_tempfile if defined $use_tempfile; 4090Sstevel@tonic-gate} 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate#### Method: param 4120Sstevel@tonic-gate# Returns the value(s)of a named parameter. 4130Sstevel@tonic-gate# If invoked in a list context, returns the 4140Sstevel@tonic-gate# entire list. Otherwise returns the first 4150Sstevel@tonic-gate# member of the list. 4160Sstevel@tonic-gate# If name is not provided, return a list of all 4170Sstevel@tonic-gate# the known parameters names available. 4180Sstevel@tonic-gate# If more than one argument is provided, the 4190Sstevel@tonic-gate# second and subsequent arguments are used to 4200Sstevel@tonic-gate# set the value of the parameter. 4210Sstevel@tonic-gate#### 4220Sstevel@tonic-gatesub param { 4230Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 4240Sstevel@tonic-gate return $self->all_parameters unless @p; 4250Sstevel@tonic-gate my($name,$value,@other); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate # For compatibility between old calling style and use_named_parameters() style, 4280Sstevel@tonic-gate # we have to special case for a single parameter present. 4290Sstevel@tonic-gate if (@p > 1) { 4300Sstevel@tonic-gate ($name,$value,@other) = rearrange([NAME,[DEFAULT,VALUE,VALUES]],@p); 4310Sstevel@tonic-gate my(@values); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate if (substr($p[0],0,1) eq '-') { 4340Sstevel@tonic-gate @values = defined($value) ? (ref($value) && ref($value) eq 'ARRAY' ? @{$value} : $value) : (); 4350Sstevel@tonic-gate } else { 4360Sstevel@tonic-gate foreach ($value,@other) { 4370Sstevel@tonic-gate push(@values,$_) if defined($_); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate # If values is provided, then we set it. 441*6287Sps156622 if (@values or defined $value) { 4420Sstevel@tonic-gate $self->add_parameter($name); 4430Sstevel@tonic-gate $self->{$name}=[@values]; 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate } else { 4460Sstevel@tonic-gate $name = $p[0]; 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate return unless defined($name) && $self->{$name}; 450*6287Sps156622 451*6287Sps156622 my @result = @{$self->{$name}}; 452*6287Sps156622 453*6287Sps156622 if ($PARAM_UTF8) { 454*6287Sps156622 eval "require Encode; 1;" unless Encode->can('decode'); # bring in these functions 455*6287Sps156622 @result = map {ref $_ ? $_ : Encode::decode(utf8=>$_) } @result; 456*6287Sps156622 } 457*6287Sps156622 458*6287Sps156622 return wantarray ? @result : $result[0]; 4590Sstevel@tonic-gate} 4600Sstevel@tonic-gate 4610Sstevel@tonic-gatesub self_or_default { 4620Sstevel@tonic-gate return @_ if defined($_[0]) && (!ref($_[0])) &&($_[0] eq 'CGI'); 4630Sstevel@tonic-gate unless (defined($_[0]) && 4640Sstevel@tonic-gate (ref($_[0]) eq 'CGI' || UNIVERSAL::isa($_[0],'CGI')) # slightly optimized for common case 4650Sstevel@tonic-gate ) { 4660Sstevel@tonic-gate $Q = $CGI::DefaultClass->new unless defined($Q); 4670Sstevel@tonic-gate unshift(@_,$Q); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate return wantarray ? @_ : $Q; 4700Sstevel@tonic-gate} 4710Sstevel@tonic-gate 4720Sstevel@tonic-gatesub self_or_CGI { 4730Sstevel@tonic-gate local $^W=0; # prevent a warning 4740Sstevel@tonic-gate if (defined($_[0]) && 4750Sstevel@tonic-gate (substr(ref($_[0]),0,3) eq 'CGI' 4760Sstevel@tonic-gate || UNIVERSAL::isa($_[0],'CGI'))) { 4770Sstevel@tonic-gate return @_; 4780Sstevel@tonic-gate } else { 4790Sstevel@tonic-gate return ($DefaultClass,@_); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate} 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate######################################## 4840Sstevel@tonic-gate# THESE METHODS ARE MORE OR LESS PRIVATE 4850Sstevel@tonic-gate# GO TO THE __DATA__ SECTION TO SEE MORE 4860Sstevel@tonic-gate# PUBLIC METHODS 4870Sstevel@tonic-gate######################################## 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate# Initialize the query object from the environment. 4900Sstevel@tonic-gate# If a parameter list is found, this object will be set 4910Sstevel@tonic-gate# to an associative array in which parameter names are keys 4920Sstevel@tonic-gate# and the values are stored as lists 4930Sstevel@tonic-gate# If a keyword list is found, this method creates a bogus 4940Sstevel@tonic-gate# parameter list with the single parameter 'keywords'. 4950Sstevel@tonic-gate 4960Sstevel@tonic-gatesub init { 4970Sstevel@tonic-gate my $self = shift; 4980Sstevel@tonic-gate my($query_string,$meth,$content_length,$fh,@lines) = ('','','',''); 4990Sstevel@tonic-gate 500*6287Sps156622 my $is_xforms; 501*6287Sps156622 5020Sstevel@tonic-gate my $initializer = shift; # for backward compatibility 5030Sstevel@tonic-gate local($/) = "\n"; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate # set autoescaping on by default 5060Sstevel@tonic-gate $self->{'escape'} = 1; 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate # if we get called more than once, we want to initialize 5090Sstevel@tonic-gate # ourselves from the original query (which may be gone 5100Sstevel@tonic-gate # if it was read from STDIN originally.) 5110Sstevel@tonic-gate if (defined(@QUERY_PARAM) && !defined($initializer)) { 512*6287Sps156622 for my $name (@QUERY_PARAM) { 513*6287Sps156622 my $val = $QUERY_PARAM{$name}; # always an arrayref; 514*6287Sps156622 $self->param('-name'=>$name,'-value'=> $val); 515*6287Sps156622 if (defined $val and ref $val eq 'ARRAY') { 516*6287Sps156622 for my $fh (grep {defined(fileno($_))} @$val) { 517*6287Sps156622 seek($fh,0,0); # reset the filehandle. 518*6287Sps156622 } 519*6287Sps156622 520*6287Sps156622 } 521*6287Sps156622 } 522*6287Sps156622 $self->charset($QUERY_CHARSET); 523*6287Sps156622 $self->{'.fieldnames'} = {%QUERY_FIELDNAMES}; 524*6287Sps156622 $self->{'.tmpfiles'} = {%QUERY_TMPFILES}; 525*6287Sps156622 return; 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate $meth=$ENV{'REQUEST_METHOD'} if defined($ENV{'REQUEST_METHOD'}); 5290Sstevel@tonic-gate $content_length = defined($ENV{'CONTENT_LENGTH'}) ? $ENV{'CONTENT_LENGTH'} : 0; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate $fh = to_filehandle($initializer) if $initializer; 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate # set charset to the safe ISO-8859-1 5340Sstevel@tonic-gate $self->charset('ISO-8859-1'); 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate METHOD: { 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate # avoid unreasonably large postings 5390Sstevel@tonic-gate if (($POST_MAX > 0) && ($content_length > $POST_MAX)) { 540*6287Sps156622 #discard the post, unread 541*6287Sps156622 $self->cgi_error("413 Request entity too large"); 542*6287Sps156622 last METHOD; 543*6287Sps156622 } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate # Process multipart postings, but only if the initializer is 5460Sstevel@tonic-gate # not defined. 5470Sstevel@tonic-gate if ($meth eq 'POST' 5480Sstevel@tonic-gate && defined($ENV{'CONTENT_TYPE'}) 5490Sstevel@tonic-gate && $ENV{'CONTENT_TYPE'}=~m|^multipart/form-data| 5500Sstevel@tonic-gate && !defined($initializer) 5510Sstevel@tonic-gate ) { 5520Sstevel@tonic-gate my($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\";,]+)\"?/; 5530Sstevel@tonic-gate $self->read_multipart($boundary,$content_length); 5540Sstevel@tonic-gate last METHOD; 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 557*6287Sps156622 # Process XForms postings. We know that we have XForms in the 558*6287Sps156622 # following cases: 559*6287Sps156622 # method eq 'POST' && content-type eq 'application/xml' 560*6287Sps156622 # method eq 'POST' && content-type =~ /multipart\/related.+start=/ 561*6287Sps156622 # There are more cases, actually, but for now, we don't support other 562*6287Sps156622 # methods for XForm posts. 563*6287Sps156622 # In a XForm POST, the QUERY_STRING is parsed normally. 564*6287Sps156622 # If the content-type is 'application/xml', we just set the param 565*6287Sps156622 # XForms:Model (referring to the xml syntax) param containing the 566*6287Sps156622 # unparsed XML data. 567*6287Sps156622 # In the case of multipart/related we set XForms:Model as above, but 568*6287Sps156622 # the other parts are available as uploads with the Content-ID as the 569*6287Sps156622 # the key. 570*6287Sps156622 # See the URL below for XForms specs on this issue. 571*6287Sps156622 # http://www.w3.org/TR/2006/REC-xforms-20060314/slice11.html#submit-options 572*6287Sps156622 if ($meth eq 'POST' && defined($ENV{'CONTENT_TYPE'})) { 573*6287Sps156622 if ($ENV{'CONTENT_TYPE'} eq 'application/xml') { 574*6287Sps156622 my($param) = 'XForms:Model'; 575*6287Sps156622 my($value) = ''; 576*6287Sps156622 $self->add_parameter($param); 577*6287Sps156622 $self->read_from_client(\$value,$content_length,0) 578*6287Sps156622 if $content_length > 0; 579*6287Sps156622 push (@{$self->{$param}},$value); 580*6287Sps156622 $is_xforms = 1; 581*6287Sps156622 } elsif ($ENV{'CONTENT_TYPE'} =~ /multipart\/related.+boundary=\"?([^\";,]+)\"?.+start=\"?\<?([^\"\>]+)\>?\"?/) { 582*6287Sps156622 my($boundary,$start) = ($1,$2); 583*6287Sps156622 my($param) = 'XForms:Model'; 584*6287Sps156622 $self->add_parameter($param); 585*6287Sps156622 my($value) = $self->read_multipart_related($start,$boundary,$content_length,0); 586*6287Sps156622 push (@{$self->{$param}},$value); 587*6287Sps156622 if ($MOD_PERL) { 588*6287Sps156622 $query_string = $self->r->args; 589*6287Sps156622 } else { 590*6287Sps156622 $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'}; 591*6287Sps156622 $query_string ||= $ENV{'REDIRECT_QUERY_STRING'} if defined $ENV{'REDIRECT_QUERY_STRING'}; 592*6287Sps156622 } 593*6287Sps156622 $is_xforms = 1; 594*6287Sps156622 } 595*6287Sps156622 } 596*6287Sps156622 597*6287Sps156622 5980Sstevel@tonic-gate # If initializer is defined, then read parameters 5990Sstevel@tonic-gate # from it. 600*6287Sps156622 if (!$is_xforms && defined($initializer)) { 6010Sstevel@tonic-gate if (UNIVERSAL::isa($initializer,'CGI')) { 6020Sstevel@tonic-gate $query_string = $initializer->query_string; 6030Sstevel@tonic-gate last METHOD; 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate if (ref($initializer) && ref($initializer) eq 'HASH') { 6060Sstevel@tonic-gate foreach (keys %$initializer) { 6070Sstevel@tonic-gate $self->param('-name'=>$_,'-value'=>$initializer->{$_}); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate last METHOD; 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate if (defined($fh) && ($fh ne '')) { 6130Sstevel@tonic-gate while (<$fh>) { 6140Sstevel@tonic-gate chomp; 6150Sstevel@tonic-gate last if /^=/; 6160Sstevel@tonic-gate push(@lines,$_); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate # massage back into standard format 6190Sstevel@tonic-gate if ("@lines" =~ /=/) { 6200Sstevel@tonic-gate $query_string=join("&",@lines); 6210Sstevel@tonic-gate } else { 6220Sstevel@tonic-gate $query_string=join("+",@lines); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate last METHOD; 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate # last chance -- treat it as a string 6280Sstevel@tonic-gate $initializer = $$initializer if ref($initializer) eq 'SCALAR'; 6290Sstevel@tonic-gate $query_string = $initializer; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate last METHOD; 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate # If method is GET or HEAD, fetch the query from 6350Sstevel@tonic-gate # the environment. 636*6287Sps156622 if ($is_xforms || $meth=~/^(GET|HEAD)$/) { 6370Sstevel@tonic-gate if ($MOD_PERL) { 6380Sstevel@tonic-gate $query_string = $self->r->args; 6390Sstevel@tonic-gate } else { 6400Sstevel@tonic-gate $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'}; 6410Sstevel@tonic-gate $query_string ||= $ENV{'REDIRECT_QUERY_STRING'} if defined $ENV{'REDIRECT_QUERY_STRING'}; 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate last METHOD; 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate 646*6287Sps156622 if ($meth eq 'POST' || $meth eq 'PUT') { 6470Sstevel@tonic-gate $self->read_from_client(\$query_string,$content_length,0) 6480Sstevel@tonic-gate if $content_length > 0; 6490Sstevel@tonic-gate # Some people want to have their cake and eat it too! 6500Sstevel@tonic-gate # Uncomment this line to have the contents of the query string 6510Sstevel@tonic-gate # APPENDED to the POST data. 6520Sstevel@tonic-gate # $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'}; 6530Sstevel@tonic-gate last METHOD; 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate # If $meth is not of GET, POST or HEAD, assume we're being debugged offline. 6570Sstevel@tonic-gate # Check the command line and then the standard input for data. 6580Sstevel@tonic-gate # We use the shellwords package in order to behave the way that 6590Sstevel@tonic-gate # UN*X programmers expect. 6600Sstevel@tonic-gate if ($DEBUG) 6610Sstevel@tonic-gate { 6620Sstevel@tonic-gate my $cmdline_ret = read_from_cmdline(); 6630Sstevel@tonic-gate $query_string = $cmdline_ret->{'query_string'}; 6640Sstevel@tonic-gate if (defined($cmdline_ret->{'subpath'})) 6650Sstevel@tonic-gate { 6660Sstevel@tonic-gate $self->path_info($cmdline_ret->{'subpath'}); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate# YL: Begin Change for XML handler 10/19/2001 672*6287Sps156622 if (!$is_xforms && ($meth eq 'POST' || $meth eq 'PUT') 6730Sstevel@tonic-gate && defined($ENV{'CONTENT_TYPE'}) 6740Sstevel@tonic-gate && $ENV{'CONTENT_TYPE'} !~ m|^application/x-www-form-urlencoded| 6750Sstevel@tonic-gate && $ENV{'CONTENT_TYPE'} !~ m|^multipart/form-data| ) { 676*6287Sps156622 my($param) = $meth . 'DATA' ; 6770Sstevel@tonic-gate $self->add_parameter($param) ; 6780Sstevel@tonic-gate push (@{$self->{$param}},$query_string); 6790Sstevel@tonic-gate undef $query_string ; 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate# YL: End Change for XML handler 10/19/2001 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate # We now have the query string in hand. We do slightly 6840Sstevel@tonic-gate # different things for keyword lists and parameter lists. 6850Sstevel@tonic-gate if (defined $query_string && length $query_string) { 6860Sstevel@tonic-gate if ($query_string =~ /[&=;]/) { 6870Sstevel@tonic-gate $self->parse_params($query_string); 6880Sstevel@tonic-gate } else { 6890Sstevel@tonic-gate $self->add_parameter('keywords'); 6900Sstevel@tonic-gate $self->{'keywords'} = [$self->parse_keywordlist($query_string)]; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate # Special case. Erase everything if there is a field named 6950Sstevel@tonic-gate # .defaults. 6960Sstevel@tonic-gate if ($self->param('.defaults')) { 6970Sstevel@tonic-gate $self->delete_all(); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate # Associative array containing our defined fieldnames 7010Sstevel@tonic-gate $self->{'.fieldnames'} = {}; 7020Sstevel@tonic-gate foreach ($self->param('.cgifields')) { 7030Sstevel@tonic-gate $self->{'.fieldnames'}->{$_}++; 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate # Clear out our default submission button flag if present 7070Sstevel@tonic-gate $self->delete('.submit'); 7080Sstevel@tonic-gate $self->delete('.cgifields'); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate $self->save_request unless defined $initializer; 7110Sstevel@tonic-gate} 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate# FUNCTIONS TO OVERRIDE: 7140Sstevel@tonic-gate# Turn a string into a filehandle 7150Sstevel@tonic-gatesub to_filehandle { 7160Sstevel@tonic-gate my $thingy = shift; 7170Sstevel@tonic-gate return undef unless $thingy; 7180Sstevel@tonic-gate return $thingy if UNIVERSAL::isa($thingy,'GLOB'); 7190Sstevel@tonic-gate return $thingy if UNIVERSAL::isa($thingy,'FileHandle'); 7200Sstevel@tonic-gate if (!ref($thingy)) { 7210Sstevel@tonic-gate my $caller = 1; 7220Sstevel@tonic-gate while (my $package = caller($caller++)) { 7230Sstevel@tonic-gate my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy"; 7240Sstevel@tonic-gate return $tmp if defined(fileno($tmp)); 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate return undef; 7280Sstevel@tonic-gate} 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate# send output to the browser 7310Sstevel@tonic-gatesub put { 7320Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 7330Sstevel@tonic-gate $self->print(@p); 7340Sstevel@tonic-gate} 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate# print to standard output (for overriding in mod_perl) 7370Sstevel@tonic-gatesub print { 7380Sstevel@tonic-gate shift; 7390Sstevel@tonic-gate CORE::print(@_); 7400Sstevel@tonic-gate} 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate# get/set last cgi_error 7430Sstevel@tonic-gatesub cgi_error { 7440Sstevel@tonic-gate my ($self,$err) = self_or_default(@_); 7450Sstevel@tonic-gate $self->{'.cgi_error'} = $err if defined $err; 7460Sstevel@tonic-gate return $self->{'.cgi_error'}; 7470Sstevel@tonic-gate} 7480Sstevel@tonic-gate 7490Sstevel@tonic-gatesub save_request { 7500Sstevel@tonic-gate my($self) = @_; 7510Sstevel@tonic-gate # We're going to play with the package globals now so that if we get called 7520Sstevel@tonic-gate # again, we initialize ourselves in exactly the same way. This allows 7530Sstevel@tonic-gate # us to have several of these objects. 7540Sstevel@tonic-gate @QUERY_PARAM = $self->param; # save list of parameters 7550Sstevel@tonic-gate foreach (@QUERY_PARAM) { 7560Sstevel@tonic-gate next unless defined $_; 7570Sstevel@tonic-gate $QUERY_PARAM{$_}=$self->{$_}; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate $QUERY_CHARSET = $self->charset; 7600Sstevel@tonic-gate %QUERY_FIELDNAMES = %{$self->{'.fieldnames'}}; 761*6287Sps156622 %QUERY_TMPFILES = %{ $self->{'.tmpfiles'} || {} }; 7620Sstevel@tonic-gate} 7630Sstevel@tonic-gate 7640Sstevel@tonic-gatesub parse_params { 7650Sstevel@tonic-gate my($self,$tosplit) = @_; 7660Sstevel@tonic-gate my(@pairs) = split(/[&;]/,$tosplit); 7670Sstevel@tonic-gate my($param,$value); 7680Sstevel@tonic-gate foreach (@pairs) { 7690Sstevel@tonic-gate ($param,$value) = split('=',$_,2); 7700Sstevel@tonic-gate next unless defined $param; 7710Sstevel@tonic-gate next if $NO_UNDEF_PARAMS and not defined $value; 7720Sstevel@tonic-gate $value = '' unless defined $value; 7730Sstevel@tonic-gate $param = unescape($param); 7740Sstevel@tonic-gate $value = unescape($value); 7750Sstevel@tonic-gate $self->add_parameter($param); 7760Sstevel@tonic-gate push (@{$self->{$param}},$value); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate} 7790Sstevel@tonic-gate 7800Sstevel@tonic-gatesub add_parameter { 7810Sstevel@tonic-gate my($self,$param)=@_; 7820Sstevel@tonic-gate return unless defined $param; 7830Sstevel@tonic-gate push (@{$self->{'.parameters'}},$param) 7840Sstevel@tonic-gate unless defined($self->{$param}); 7850Sstevel@tonic-gate} 7860Sstevel@tonic-gate 7870Sstevel@tonic-gatesub all_parameters { 7880Sstevel@tonic-gate my $self = shift; 7890Sstevel@tonic-gate return () unless defined($self) && $self->{'.parameters'}; 7900Sstevel@tonic-gate return () unless @{$self->{'.parameters'}}; 7910Sstevel@tonic-gate return @{$self->{'.parameters'}}; 7920Sstevel@tonic-gate} 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate# put a filehandle into binary mode (DOS) 7950Sstevel@tonic-gatesub binmode { 7960Sstevel@tonic-gate return unless defined($_[1]) && defined fileno($_[1]); 7970Sstevel@tonic-gate CORE::binmode($_[1]); 7980Sstevel@tonic-gate} 7990Sstevel@tonic-gate 8000Sstevel@tonic-gatesub _make_tag_func { 8010Sstevel@tonic-gate my ($self,$tagname) = @_; 8020Sstevel@tonic-gate my $func = qq( 8030Sstevel@tonic-gate sub $tagname { 8040Sstevel@tonic-gate my (\$q,\$a,\@rest) = self_or_default(\@_); 8050Sstevel@tonic-gate my(\$attr) = ''; 8060Sstevel@tonic-gate if (ref(\$a) && ref(\$a) eq 'HASH') { 8070Sstevel@tonic-gate my(\@attr) = make_attributes(\$a,\$q->{'escape'}); 8080Sstevel@tonic-gate \$attr = " \@attr" if \@attr; 8090Sstevel@tonic-gate } else { 8100Sstevel@tonic-gate unshift \@rest,\$a if defined \$a; 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate ); 8130Sstevel@tonic-gate if ($tagname=~/start_(\w+)/i) { 8140Sstevel@tonic-gate $func .= qq! return "<\L$1\E\$attr>";} !; 8150Sstevel@tonic-gate } elsif ($tagname=~/end_(\w+)/i) { 8160Sstevel@tonic-gate $func .= qq! return "<\L/$1\E>"; } !; 8170Sstevel@tonic-gate } else { 8180Sstevel@tonic-gate $func .= qq# 8190Sstevel@tonic-gate return \$XHTML ? "\L<$tagname\E\$attr />" : "\L<$tagname\E\$attr>" unless \@rest; 8200Sstevel@tonic-gate my(\$tag,\$untag) = ("\L<$tagname\E\$attr>","\L</$tagname>\E"); 8210Sstevel@tonic-gate my \@result = map { "\$tag\$_\$untag" } 8220Sstevel@tonic-gate (ref(\$rest[0]) eq 'ARRAY') ? \@{\$rest[0]} : "\@rest"; 8230Sstevel@tonic-gate return "\@result"; 8240Sstevel@tonic-gate }#; 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gatereturn $func; 8270Sstevel@tonic-gate} 8280Sstevel@tonic-gate 8290Sstevel@tonic-gatesub AUTOLOAD { 8300Sstevel@tonic-gate print STDERR "CGI::AUTOLOAD for $AUTOLOAD\n" if $CGI::AUTOLOAD_DEBUG; 8310Sstevel@tonic-gate my $func = &_compile; 8320Sstevel@tonic-gate goto &$func; 8330Sstevel@tonic-gate} 8340Sstevel@tonic-gate 8350Sstevel@tonic-gatesub _compile { 8360Sstevel@tonic-gate my($func) = $AUTOLOAD; 8370Sstevel@tonic-gate my($pack,$func_name); 8380Sstevel@tonic-gate { 8390Sstevel@tonic-gate local($1,$2); # this fixes an obscure variable suicide problem. 8400Sstevel@tonic-gate $func=~/(.+)::([^:]+)$/; 8410Sstevel@tonic-gate ($pack,$func_name) = ($1,$2); 8420Sstevel@tonic-gate $pack=~s/::SUPER$//; # fix another obscure problem 8430Sstevel@tonic-gate $pack = ${"$pack\:\:AutoloadClass"} || $CGI::DefaultClass 8440Sstevel@tonic-gate unless defined(${"$pack\:\:AUTOLOADED_ROUTINES"}); 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate my($sub) = \%{"$pack\:\:SUBS"}; 8470Sstevel@tonic-gate unless (%$sub) { 8480Sstevel@tonic-gate my($auto) = \${"$pack\:\:AUTOLOADED_ROUTINES"}; 849667Sps156622 local ($@,$!); 8500Sstevel@tonic-gate eval "package $pack; $$auto"; 8510Sstevel@tonic-gate croak("$AUTOLOAD: $@") if $@; 8520Sstevel@tonic-gate $$auto = ''; # Free the unneeded storage (but don't undef it!!!) 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate my($code) = $sub->{$func_name}; 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate $code = "sub $AUTOLOAD { }" if (!$code and $func_name eq 'DESTROY'); 8570Sstevel@tonic-gate if (!$code) { 8580Sstevel@tonic-gate (my $base = $func_name) =~ s/^(start_|end_)//i; 8590Sstevel@tonic-gate if ($EXPORT{':any'} || 8600Sstevel@tonic-gate $EXPORT{'-any'} || 8610Sstevel@tonic-gate $EXPORT{$base} || 8620Sstevel@tonic-gate (%EXPORT_OK || grep(++$EXPORT_OK{$_},&expand_tags(':html'))) 8630Sstevel@tonic-gate && $EXPORT_OK{$base}) { 8640Sstevel@tonic-gate $code = $CGI::DefaultClass->_make_tag_func($func_name); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate croak("Undefined subroutine $AUTOLOAD\n") unless $code; 868667Sps156622 local ($@,$!); 8690Sstevel@tonic-gate eval "package $pack; $code"; 8700Sstevel@tonic-gate if ($@) { 8710Sstevel@tonic-gate $@ =~ s/ at .*\n//; 8720Sstevel@tonic-gate croak("$AUTOLOAD: $@"); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate CORE::delete($sub->{$func_name}); #free storage 8760Sstevel@tonic-gate return "$pack\:\:$func_name"; 8770Sstevel@tonic-gate} 8780Sstevel@tonic-gate 8790Sstevel@tonic-gatesub _selected { 8800Sstevel@tonic-gate my $self = shift; 8810Sstevel@tonic-gate my $value = shift; 8820Sstevel@tonic-gate return '' unless $value; 883*6287Sps156622 return $XHTML ? qq(selected="selected" ) : qq(selected ); 8840Sstevel@tonic-gate} 8850Sstevel@tonic-gate 8860Sstevel@tonic-gatesub _checked { 8870Sstevel@tonic-gate my $self = shift; 8880Sstevel@tonic-gate my $value = shift; 8890Sstevel@tonic-gate return '' unless $value; 890*6287Sps156622 return $XHTML ? qq(checked="checked" ) : qq(checked ); 8910Sstevel@tonic-gate} 8920Sstevel@tonic-gate 8930Sstevel@tonic-gatesub _reset_globals { initialize_globals(); } 8940Sstevel@tonic-gate 8950Sstevel@tonic-gatesub _setup_symbols { 8960Sstevel@tonic-gate my $self = shift; 8970Sstevel@tonic-gate my $compile = 0; 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate # to avoid reexporting unwanted variables 9000Sstevel@tonic-gate undef %EXPORT; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate foreach (@_) { 9030Sstevel@tonic-gate $HEADERS_ONCE++, next if /^[:-]unique_headers$/; 9040Sstevel@tonic-gate $NPH++, next if /^[:-]nph$/; 9050Sstevel@tonic-gate $NOSTICKY++, next if /^[:-]nosticky$/; 9060Sstevel@tonic-gate $DEBUG=0, next if /^[:-]no_?[Dd]ebug$/; 9070Sstevel@tonic-gate $DEBUG=2, next if /^[:-][Dd]ebug$/; 9080Sstevel@tonic-gate $USE_PARAM_SEMICOLONS++, next if /^[:-]newstyle_urls$/; 909*6287Sps156622 $PARAM_UTF8++, next if /^[:-]utf8$/; 9100Sstevel@tonic-gate $XHTML++, next if /^[:-]xhtml$/; 9110Sstevel@tonic-gate $XHTML=0, next if /^[:-]no_?xhtml$/; 9120Sstevel@tonic-gate $USE_PARAM_SEMICOLONS=0, next if /^[:-]oldstyle_urls$/; 9130Sstevel@tonic-gate $PRIVATE_TEMPFILES++, next if /^[:-]private_tempfiles$/; 914*6287Sps156622 $TABINDEX++, next if /^[:-]tabindex$/; 915667Sps156622 $CLOSE_UPLOAD_FILES++, next if /^[:-]close_upload_files$/; 9160Sstevel@tonic-gate $EXPORT{$_}++, next if /^[:-]any$/; 9170Sstevel@tonic-gate $compile++, next if /^[:-]compile$/; 9180Sstevel@tonic-gate $NO_UNDEF_PARAMS++, next if /^[:-]no_undef_params$/; 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate # This is probably extremely evil code -- to be deleted some day. 9210Sstevel@tonic-gate if (/^[-]autoload$/) { 9220Sstevel@tonic-gate my($pkg) = caller(1); 9230Sstevel@tonic-gate *{"${pkg}::AUTOLOAD"} = sub { 9240Sstevel@tonic-gate my($routine) = $AUTOLOAD; 9250Sstevel@tonic-gate $routine =~ s/^.*::/CGI::/; 9260Sstevel@tonic-gate &$routine; 9270Sstevel@tonic-gate }; 9280Sstevel@tonic-gate next; 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate foreach (&expand_tags($_)) { 9320Sstevel@tonic-gate tr/a-zA-Z0-9_//cd; # don't allow weird function names 9330Sstevel@tonic-gate $EXPORT{$_}++; 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate _compile_all(keys %EXPORT) if $compile; 9370Sstevel@tonic-gate @SAVED_SYMBOLS = @_; 9380Sstevel@tonic-gate} 9390Sstevel@tonic-gate 9400Sstevel@tonic-gatesub charset { 9410Sstevel@tonic-gate my ($self,$charset) = self_or_default(@_); 9420Sstevel@tonic-gate $self->{'.charset'} = $charset if defined $charset; 9430Sstevel@tonic-gate $self->{'.charset'}; 9440Sstevel@tonic-gate} 9450Sstevel@tonic-gate 946667Sps156622sub element_id { 947667Sps156622 my ($self,$new_value) = self_or_default(@_); 948667Sps156622 $self->{'.elid'} = $new_value if defined $new_value; 949667Sps156622 sprintf('%010d',$self->{'.elid'}++); 950667Sps156622} 951667Sps156622 952667Sps156622sub element_tab { 953667Sps156622 my ($self,$new_value) = self_or_default(@_); 954667Sps156622 $self->{'.etab'} ||= 1; 955667Sps156622 $self->{'.etab'} = $new_value if defined $new_value; 956*6287Sps156622 my $tab = $self->{'.etab'}++; 957*6287Sps156622 return '' unless $TABINDEX or defined $new_value; 958*6287Sps156622 return qq(tabindex="$tab" ); 959667Sps156622} 960667Sps156622 9610Sstevel@tonic-gate############################################################################### 9620Sstevel@tonic-gate################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND #################### 9630Sstevel@tonic-gate############################################################################### 9640Sstevel@tonic-gate$AUTOLOADED_ROUTINES = ''; # get rid of -w warning 9650Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate%SUBS = ( 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate'URL_ENCODED'=> <<'END_OF_FUNC', 9700Sstevel@tonic-gatesub URL_ENCODED { 'application/x-www-form-urlencoded'; } 9710Sstevel@tonic-gateEND_OF_FUNC 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate'MULTIPART' => <<'END_OF_FUNC', 9740Sstevel@tonic-gatesub MULTIPART { 'multipart/form-data'; } 9750Sstevel@tonic-gateEND_OF_FUNC 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate'SERVER_PUSH' => <<'END_OF_FUNC', 9780Sstevel@tonic-gatesub SERVER_PUSH { 'multipart/x-mixed-replace;boundary="' . shift() . '"'; } 9790Sstevel@tonic-gateEND_OF_FUNC 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate'new_MultipartBuffer' => <<'END_OF_FUNC', 9820Sstevel@tonic-gate# Create a new multipart buffer 9830Sstevel@tonic-gatesub new_MultipartBuffer { 9840Sstevel@tonic-gate my($self,$boundary,$length) = @_; 9850Sstevel@tonic-gate return MultipartBuffer->new($self,$boundary,$length); 9860Sstevel@tonic-gate} 9870Sstevel@tonic-gateEND_OF_FUNC 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate'read_from_client' => <<'END_OF_FUNC', 9900Sstevel@tonic-gate# Read data from a file handle 9910Sstevel@tonic-gatesub read_from_client { 9920Sstevel@tonic-gate my($self, $buff, $len, $offset) = @_; 9930Sstevel@tonic-gate local $^W=0; # prevent a warning 9940Sstevel@tonic-gate return $MOD_PERL 9950Sstevel@tonic-gate ? $self->r->read($$buff, $len, $offset) 9960Sstevel@tonic-gate : read(\*STDIN, $$buff, $len, $offset); 9970Sstevel@tonic-gate} 9980Sstevel@tonic-gateEND_OF_FUNC 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate'delete' => <<'END_OF_FUNC', 10010Sstevel@tonic-gate#### Method: delete 10020Sstevel@tonic-gate# Deletes the named parameter entirely. 10030Sstevel@tonic-gate#### 10040Sstevel@tonic-gatesub delete { 10050Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 10060Sstevel@tonic-gate my(@names) = rearrange([NAME],@p); 10070Sstevel@tonic-gate my @to_delete = ref($names[0]) eq 'ARRAY' ? @$names[0] : @names; 10080Sstevel@tonic-gate my %to_delete; 10090Sstevel@tonic-gate foreach my $name (@to_delete) 10100Sstevel@tonic-gate { 10110Sstevel@tonic-gate CORE::delete $self->{$name}; 10120Sstevel@tonic-gate CORE::delete $self->{'.fieldnames'}->{$name}; 10130Sstevel@tonic-gate $to_delete{$name}++; 10140Sstevel@tonic-gate } 10150Sstevel@tonic-gate @{$self->{'.parameters'}}=grep { !exists($to_delete{$_}) } $self->param(); 1016667Sps156622 return; 10170Sstevel@tonic-gate} 10180Sstevel@tonic-gateEND_OF_FUNC 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate#### Method: import_names 10210Sstevel@tonic-gate# Import all parameters into the given namespace. 10220Sstevel@tonic-gate# Assumes namespace 'Q' if not specified 10230Sstevel@tonic-gate#### 10240Sstevel@tonic-gate'import_names' => <<'END_OF_FUNC', 10250Sstevel@tonic-gatesub import_names { 10260Sstevel@tonic-gate my($self,$namespace,$delete) = self_or_default(@_); 10270Sstevel@tonic-gate $namespace = 'Q' unless defined($namespace); 10280Sstevel@tonic-gate die "Can't import names into \"main\"\n" if \%{"${namespace}::"} == \%::; 10290Sstevel@tonic-gate if ($delete || $MOD_PERL || exists $ENV{'FCGI_ROLE'}) { 10300Sstevel@tonic-gate # can anyone find an easier way to do this? 10310Sstevel@tonic-gate foreach (keys %{"${namespace}::"}) { 10320Sstevel@tonic-gate local *symbol = "${namespace}::${_}"; 10330Sstevel@tonic-gate undef $symbol; 10340Sstevel@tonic-gate undef @symbol; 10350Sstevel@tonic-gate undef %symbol; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate my($param,@value,$var); 10390Sstevel@tonic-gate foreach $param ($self->param) { 10400Sstevel@tonic-gate # protect against silly names 10410Sstevel@tonic-gate ($var = $param)=~tr/a-zA-Z0-9_/_/c; 10420Sstevel@tonic-gate $var =~ s/^(?=\d)/_/; 10430Sstevel@tonic-gate local *symbol = "${namespace}::$var"; 10440Sstevel@tonic-gate @value = $self->param($param); 10450Sstevel@tonic-gate @symbol = @value; 10460Sstevel@tonic-gate $symbol = $value[0]; 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate} 10490Sstevel@tonic-gateEND_OF_FUNC 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate#### Method: keywords 10520Sstevel@tonic-gate# Keywords acts a bit differently. Calling it in a list context 10530Sstevel@tonic-gate# returns the list of keywords. 10540Sstevel@tonic-gate# Calling it in a scalar context gives you the size of the list. 10550Sstevel@tonic-gate#### 10560Sstevel@tonic-gate'keywords' => <<'END_OF_FUNC', 10570Sstevel@tonic-gatesub keywords { 10580Sstevel@tonic-gate my($self,@values) = self_or_default(@_); 10590Sstevel@tonic-gate # If values is provided, then we set it. 10600Sstevel@tonic-gate $self->{'keywords'}=[@values] if @values; 10610Sstevel@tonic-gate my(@result) = defined($self->{'keywords'}) ? @{$self->{'keywords'}} : (); 10620Sstevel@tonic-gate @result; 10630Sstevel@tonic-gate} 10640Sstevel@tonic-gateEND_OF_FUNC 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate# These are some tie() interfaces for compatibility 10670Sstevel@tonic-gate# with Steve Brenner's cgi-lib.pl routines 10680Sstevel@tonic-gate'Vars' => <<'END_OF_FUNC', 10690Sstevel@tonic-gatesub Vars { 10700Sstevel@tonic-gate my $q = shift; 10710Sstevel@tonic-gate my %in; 10720Sstevel@tonic-gate tie(%in,CGI,$q); 10730Sstevel@tonic-gate return %in if wantarray; 10740Sstevel@tonic-gate return \%in; 10750Sstevel@tonic-gate} 10760Sstevel@tonic-gateEND_OF_FUNC 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate# These are some tie() interfaces for compatibility 10790Sstevel@tonic-gate# with Steve Brenner's cgi-lib.pl routines 10800Sstevel@tonic-gate'ReadParse' => <<'END_OF_FUNC', 10810Sstevel@tonic-gatesub ReadParse { 10820Sstevel@tonic-gate local(*in); 10830Sstevel@tonic-gate if (@_) { 10840Sstevel@tonic-gate *in = $_[0]; 10850Sstevel@tonic-gate } else { 10860Sstevel@tonic-gate my $pkg = caller(); 10870Sstevel@tonic-gate *in=*{"${pkg}::in"}; 10880Sstevel@tonic-gate } 10890Sstevel@tonic-gate tie(%in,CGI); 10900Sstevel@tonic-gate return scalar(keys %in); 10910Sstevel@tonic-gate} 10920Sstevel@tonic-gateEND_OF_FUNC 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate'PrintHeader' => <<'END_OF_FUNC', 10950Sstevel@tonic-gatesub PrintHeader { 10960Sstevel@tonic-gate my($self) = self_or_default(@_); 10970Sstevel@tonic-gate return $self->header(); 10980Sstevel@tonic-gate} 10990Sstevel@tonic-gateEND_OF_FUNC 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate'HtmlTop' => <<'END_OF_FUNC', 11020Sstevel@tonic-gatesub HtmlTop { 11030Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 11040Sstevel@tonic-gate return $self->start_html(@p); 11050Sstevel@tonic-gate} 11060Sstevel@tonic-gateEND_OF_FUNC 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate'HtmlBot' => <<'END_OF_FUNC', 11090Sstevel@tonic-gatesub HtmlBot { 11100Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 11110Sstevel@tonic-gate return $self->end_html(@p); 11120Sstevel@tonic-gate} 11130Sstevel@tonic-gateEND_OF_FUNC 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate'SplitParam' => <<'END_OF_FUNC', 11160Sstevel@tonic-gatesub SplitParam { 11170Sstevel@tonic-gate my ($param) = @_; 11180Sstevel@tonic-gate my (@params) = split ("\0", $param); 11190Sstevel@tonic-gate return (wantarray ? @params : $params[0]); 11200Sstevel@tonic-gate} 11210Sstevel@tonic-gateEND_OF_FUNC 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate'MethGet' => <<'END_OF_FUNC', 11240Sstevel@tonic-gatesub MethGet { 11250Sstevel@tonic-gate return request_method() eq 'GET'; 11260Sstevel@tonic-gate} 11270Sstevel@tonic-gateEND_OF_FUNC 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate'MethPost' => <<'END_OF_FUNC', 11300Sstevel@tonic-gatesub MethPost { 11310Sstevel@tonic-gate return request_method() eq 'POST'; 11320Sstevel@tonic-gate} 11330Sstevel@tonic-gateEND_OF_FUNC 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate'TIEHASH' => <<'END_OF_FUNC', 11360Sstevel@tonic-gatesub TIEHASH { 11370Sstevel@tonic-gate my $class = shift; 11380Sstevel@tonic-gate my $arg = $_[0]; 11390Sstevel@tonic-gate if (ref($arg) && UNIVERSAL::isa($arg,'CGI')) { 11400Sstevel@tonic-gate return $arg; 11410Sstevel@tonic-gate } 11420Sstevel@tonic-gate return $Q ||= $class->new(@_); 11430Sstevel@tonic-gate} 11440Sstevel@tonic-gateEND_OF_FUNC 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate'STORE' => <<'END_OF_FUNC', 11470Sstevel@tonic-gatesub STORE { 11480Sstevel@tonic-gate my $self = shift; 11490Sstevel@tonic-gate my $tag = shift; 11500Sstevel@tonic-gate my $vals = shift; 11510Sstevel@tonic-gate my @vals = index($vals,"\0")!=-1 ? split("\0",$vals) : $vals; 11520Sstevel@tonic-gate $self->param(-name=>$tag,-value=>\@vals); 11530Sstevel@tonic-gate} 11540Sstevel@tonic-gateEND_OF_FUNC 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate'FETCH' => <<'END_OF_FUNC', 11570Sstevel@tonic-gatesub FETCH { 11580Sstevel@tonic-gate return $_[0] if $_[1] eq 'CGI'; 11590Sstevel@tonic-gate return undef unless defined $_[0]->param($_[1]); 11600Sstevel@tonic-gate return join("\0",$_[0]->param($_[1])); 11610Sstevel@tonic-gate} 11620Sstevel@tonic-gateEND_OF_FUNC 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate'FIRSTKEY' => <<'END_OF_FUNC', 11650Sstevel@tonic-gatesub FIRSTKEY { 11660Sstevel@tonic-gate $_[0]->{'.iterator'}=0; 11670Sstevel@tonic-gate $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++]; 11680Sstevel@tonic-gate} 11690Sstevel@tonic-gateEND_OF_FUNC 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate'NEXTKEY' => <<'END_OF_FUNC', 11720Sstevel@tonic-gatesub NEXTKEY { 11730Sstevel@tonic-gate $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++]; 11740Sstevel@tonic-gate} 11750Sstevel@tonic-gateEND_OF_FUNC 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate'EXISTS' => <<'END_OF_FUNC', 11780Sstevel@tonic-gatesub EXISTS { 11790Sstevel@tonic-gate exists $_[0]->{$_[1]}; 11800Sstevel@tonic-gate} 11810Sstevel@tonic-gateEND_OF_FUNC 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate'DELETE' => <<'END_OF_FUNC', 11840Sstevel@tonic-gatesub DELETE { 11850Sstevel@tonic-gate $_[0]->delete($_[1]); 11860Sstevel@tonic-gate} 11870Sstevel@tonic-gateEND_OF_FUNC 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate'CLEAR' => <<'END_OF_FUNC', 11900Sstevel@tonic-gatesub CLEAR { 11910Sstevel@tonic-gate %{$_[0]}=(); 11920Sstevel@tonic-gate} 11930Sstevel@tonic-gate#### 11940Sstevel@tonic-gateEND_OF_FUNC 11950Sstevel@tonic-gate 11960Sstevel@tonic-gate#### 11970Sstevel@tonic-gate# Append a new value to an existing query 11980Sstevel@tonic-gate#### 11990Sstevel@tonic-gate'append' => <<'EOF', 12000Sstevel@tonic-gatesub append { 1201667Sps156622 my($self,@p) = self_or_default(@_); 12020Sstevel@tonic-gate my($name,$value) = rearrange([NAME,[VALUE,VALUES]],@p); 12030Sstevel@tonic-gate my(@values) = defined($value) ? (ref($value) ? @{$value} : $value) : (); 12040Sstevel@tonic-gate if (@values) { 12050Sstevel@tonic-gate $self->add_parameter($name); 12060Sstevel@tonic-gate push(@{$self->{$name}},@values); 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate return $self->param($name); 12090Sstevel@tonic-gate} 12100Sstevel@tonic-gateEOF 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate#### Method: delete_all 12130Sstevel@tonic-gate# Delete all parameters 12140Sstevel@tonic-gate#### 12150Sstevel@tonic-gate'delete_all' => <<'EOF', 12160Sstevel@tonic-gatesub delete_all { 12170Sstevel@tonic-gate my($self) = self_or_default(@_); 12180Sstevel@tonic-gate my @param = $self->param(); 12190Sstevel@tonic-gate $self->delete(@param); 12200Sstevel@tonic-gate} 12210Sstevel@tonic-gateEOF 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate'Delete' => <<'EOF', 12240Sstevel@tonic-gatesub Delete { 12250Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 12260Sstevel@tonic-gate $self->delete(@p); 12270Sstevel@tonic-gate} 12280Sstevel@tonic-gateEOF 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate'Delete_all' => <<'EOF', 12310Sstevel@tonic-gatesub Delete_all { 12320Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 12330Sstevel@tonic-gate $self->delete_all(@p); 12340Sstevel@tonic-gate} 12350Sstevel@tonic-gateEOF 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate#### Method: autoescape 12380Sstevel@tonic-gate# If you want to turn off the autoescaping features, 12390Sstevel@tonic-gate# call this method with undef as the argument 12400Sstevel@tonic-gate'autoEscape' => <<'END_OF_FUNC', 12410Sstevel@tonic-gatesub autoEscape { 12420Sstevel@tonic-gate my($self,$escape) = self_or_default(@_); 12430Sstevel@tonic-gate my $d = $self->{'escape'}; 12440Sstevel@tonic-gate $self->{'escape'} = $escape; 12450Sstevel@tonic-gate $d; 12460Sstevel@tonic-gate} 12470Sstevel@tonic-gateEND_OF_FUNC 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate#### Method: version 12510Sstevel@tonic-gate# Return the current version 12520Sstevel@tonic-gate#### 12530Sstevel@tonic-gate'version' => <<'END_OF_FUNC', 12540Sstevel@tonic-gatesub version { 12550Sstevel@tonic-gate return $VERSION; 12560Sstevel@tonic-gate} 12570Sstevel@tonic-gateEND_OF_FUNC 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate#### Method: url_param 12600Sstevel@tonic-gate# Return a parameter in the QUERY_STRING, regardless of 12610Sstevel@tonic-gate# whether this was a POST or a GET 12620Sstevel@tonic-gate#### 12630Sstevel@tonic-gate'url_param' => <<'END_OF_FUNC', 12640Sstevel@tonic-gatesub url_param { 12650Sstevel@tonic-gate my ($self,@p) = self_or_default(@_); 12660Sstevel@tonic-gate my $name = shift(@p); 12670Sstevel@tonic-gate return undef unless exists($ENV{QUERY_STRING}); 12680Sstevel@tonic-gate unless (exists($self->{'.url_param'})) { 12690Sstevel@tonic-gate $self->{'.url_param'}={}; # empty hash 12700Sstevel@tonic-gate if ($ENV{QUERY_STRING} =~ /=/) { 12710Sstevel@tonic-gate my(@pairs) = split(/[&;]/,$ENV{QUERY_STRING}); 12720Sstevel@tonic-gate my($param,$value); 12730Sstevel@tonic-gate foreach (@pairs) { 12740Sstevel@tonic-gate ($param,$value) = split('=',$_,2); 12750Sstevel@tonic-gate $param = unescape($param); 12760Sstevel@tonic-gate $value = unescape($value); 12770Sstevel@tonic-gate push(@{$self->{'.url_param'}->{$param}},$value); 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate } else { 12800Sstevel@tonic-gate $self->{'.url_param'}->{'keywords'} = [$self->parse_keywordlist($ENV{QUERY_STRING})]; 12810Sstevel@tonic-gate } 12820Sstevel@tonic-gate } 12830Sstevel@tonic-gate return keys %{$self->{'.url_param'}} unless defined($name); 12840Sstevel@tonic-gate return () unless $self->{'.url_param'}->{$name}; 12850Sstevel@tonic-gate return wantarray ? @{$self->{'.url_param'}->{$name}} 12860Sstevel@tonic-gate : $self->{'.url_param'}->{$name}->[0]; 12870Sstevel@tonic-gate} 12880Sstevel@tonic-gateEND_OF_FUNC 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate#### Method: Dump 12910Sstevel@tonic-gate# Returns a string in which all the known parameter/value 12920Sstevel@tonic-gate# pairs are represented as nested lists, mainly for the purposes 12930Sstevel@tonic-gate# of debugging. 12940Sstevel@tonic-gate#### 12950Sstevel@tonic-gate'Dump' => <<'END_OF_FUNC', 12960Sstevel@tonic-gatesub Dump { 12970Sstevel@tonic-gate my($self) = self_or_default(@_); 12980Sstevel@tonic-gate my($param,$value,@result); 12990Sstevel@tonic-gate return '<ul></ul>' unless $self->param; 13000Sstevel@tonic-gate push(@result,"<ul>"); 13010Sstevel@tonic-gate foreach $param ($self->param) { 13020Sstevel@tonic-gate my($name)=$self->escapeHTML($param); 13030Sstevel@tonic-gate push(@result,"<li><strong>$param</strong></li>"); 13040Sstevel@tonic-gate push(@result,"<ul>"); 13050Sstevel@tonic-gate foreach $value ($self->param($param)) { 13060Sstevel@tonic-gate $value = $self->escapeHTML($value); 13070Sstevel@tonic-gate $value =~ s/\n/<br \/>\n/g; 13080Sstevel@tonic-gate push(@result,"<li>$value</li>"); 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate push(@result,"</ul>"); 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate push(@result,"</ul>"); 13130Sstevel@tonic-gate return join("\n",@result); 13140Sstevel@tonic-gate} 13150Sstevel@tonic-gateEND_OF_FUNC 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate#### Method as_string 13180Sstevel@tonic-gate# 13190Sstevel@tonic-gate# synonym for "dump" 13200Sstevel@tonic-gate#### 13210Sstevel@tonic-gate'as_string' => <<'END_OF_FUNC', 13220Sstevel@tonic-gatesub as_string { 13230Sstevel@tonic-gate &Dump(@_); 13240Sstevel@tonic-gate} 13250Sstevel@tonic-gateEND_OF_FUNC 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate#### Method: save 13280Sstevel@tonic-gate# Write values out to a filehandle in such a way that they can 13290Sstevel@tonic-gate# be reinitialized by the filehandle form of the new() method 13300Sstevel@tonic-gate#### 13310Sstevel@tonic-gate'save' => <<'END_OF_FUNC', 13320Sstevel@tonic-gatesub save { 13330Sstevel@tonic-gate my($self,$filehandle) = self_or_default(@_); 13340Sstevel@tonic-gate $filehandle = to_filehandle($filehandle); 13350Sstevel@tonic-gate my($param); 13360Sstevel@tonic-gate local($,) = ''; # set print field separator back to a sane value 13370Sstevel@tonic-gate local($\) = ''; # set output line separator to a sane value 13380Sstevel@tonic-gate foreach $param ($self->param) { 13390Sstevel@tonic-gate my($escaped_param) = escape($param); 13400Sstevel@tonic-gate my($value); 13410Sstevel@tonic-gate foreach $value ($self->param($param)) { 13420Sstevel@tonic-gate print $filehandle "$escaped_param=",escape("$value"),"\n"; 13430Sstevel@tonic-gate } 13440Sstevel@tonic-gate } 13450Sstevel@tonic-gate foreach (keys %{$self->{'.fieldnames'}}) { 13460Sstevel@tonic-gate print $filehandle ".cgifields=",escape("$_"),"\n"; 13470Sstevel@tonic-gate } 13480Sstevel@tonic-gate print $filehandle "=\n"; # end of record 13490Sstevel@tonic-gate} 13500Sstevel@tonic-gateEND_OF_FUNC 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate#### Method: save_parameters 13540Sstevel@tonic-gate# An alias for save() that is a better name for exportation. 13550Sstevel@tonic-gate# Only intended to be used with the function (non-OO) interface. 13560Sstevel@tonic-gate#### 13570Sstevel@tonic-gate'save_parameters' => <<'END_OF_FUNC', 13580Sstevel@tonic-gatesub save_parameters { 13590Sstevel@tonic-gate my $fh = shift; 13600Sstevel@tonic-gate return save(to_filehandle($fh)); 13610Sstevel@tonic-gate} 13620Sstevel@tonic-gateEND_OF_FUNC 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate#### Method: restore_parameters 13650Sstevel@tonic-gate# A way to restore CGI parameters from an initializer. 13660Sstevel@tonic-gate# Only intended to be used with the function (non-OO) interface. 13670Sstevel@tonic-gate#### 13680Sstevel@tonic-gate'restore_parameters' => <<'END_OF_FUNC', 13690Sstevel@tonic-gatesub restore_parameters { 13700Sstevel@tonic-gate $Q = $CGI::DefaultClass->new(@_); 13710Sstevel@tonic-gate} 13720Sstevel@tonic-gateEND_OF_FUNC 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate#### Method: multipart_init 13750Sstevel@tonic-gate# Return a Content-Type: style header for server-push 13760Sstevel@tonic-gate# This has to be NPH on most web servers, and it is advisable to set $| = 1 13770Sstevel@tonic-gate# 13780Sstevel@tonic-gate# Many thanks to Ed Jordan <ed@fidalgo.net> for this 13790Sstevel@tonic-gate# contribution, updated by Andrew Benham (adsb@bigfoot.com) 13800Sstevel@tonic-gate#### 13810Sstevel@tonic-gate'multipart_init' => <<'END_OF_FUNC', 13820Sstevel@tonic-gatesub multipart_init { 13830Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 13840Sstevel@tonic-gate my($boundary,@other) = rearrange([BOUNDARY],@p); 13850Sstevel@tonic-gate $boundary = $boundary || '------- =_aaaaaaaaaa0'; 13860Sstevel@tonic-gate $self->{'separator'} = "$CRLF--$boundary$CRLF"; 13870Sstevel@tonic-gate $self->{'final_separator'} = "$CRLF--$boundary--$CRLF"; 13880Sstevel@tonic-gate $type = SERVER_PUSH($boundary); 13890Sstevel@tonic-gate return $self->header( 1390667Sps156622 -nph => 0, 13910Sstevel@tonic-gate -type => $type, 13920Sstevel@tonic-gate (map { split "=", $_, 2 } @other), 13930Sstevel@tonic-gate ) . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $self->multipart_end; 13940Sstevel@tonic-gate} 13950Sstevel@tonic-gateEND_OF_FUNC 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate#### Method: multipart_start 13990Sstevel@tonic-gate# Return a Content-Type: style header for server-push, start of section 14000Sstevel@tonic-gate# 14010Sstevel@tonic-gate# Many thanks to Ed Jordan <ed@fidalgo.net> for this 14020Sstevel@tonic-gate# contribution, updated by Andrew Benham (adsb@bigfoot.com) 14030Sstevel@tonic-gate#### 14040Sstevel@tonic-gate'multipart_start' => <<'END_OF_FUNC', 14050Sstevel@tonic-gatesub multipart_start { 14060Sstevel@tonic-gate my(@header); 14070Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 14080Sstevel@tonic-gate my($type,@other) = rearrange([TYPE],@p); 14090Sstevel@tonic-gate $type = $type || 'text/html'; 14100Sstevel@tonic-gate push(@header,"Content-Type: $type"); 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate # rearrange() was designed for the HTML portion, so we 14130Sstevel@tonic-gate # need to fix it up a little. 14140Sstevel@tonic-gate foreach (@other) { 14150Sstevel@tonic-gate # Don't use \s because of perl bug 21951 14160Sstevel@tonic-gate next unless my($header,$value) = /([^ \r\n\t=]+)=\"?(.+?)\"?$/; 14170Sstevel@tonic-gate ($_ = $header) =~ s/^(\w)(.*)/$1 . lc ($2) . ': '.$self->unescapeHTML($value)/e; 14180Sstevel@tonic-gate } 14190Sstevel@tonic-gate push(@header,@other); 14200Sstevel@tonic-gate my $header = join($CRLF,@header)."${CRLF}${CRLF}"; 14210Sstevel@tonic-gate return $header; 14220Sstevel@tonic-gate} 14230Sstevel@tonic-gateEND_OF_FUNC 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate#### Method: multipart_end 14270Sstevel@tonic-gate# Return a MIME boundary separator for server-push, end of section 14280Sstevel@tonic-gate# 14290Sstevel@tonic-gate# Many thanks to Ed Jordan <ed@fidalgo.net> for this 14300Sstevel@tonic-gate# contribution 14310Sstevel@tonic-gate#### 14320Sstevel@tonic-gate'multipart_end' => <<'END_OF_FUNC', 14330Sstevel@tonic-gatesub multipart_end { 14340Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 14350Sstevel@tonic-gate return $self->{'separator'}; 14360Sstevel@tonic-gate} 14370Sstevel@tonic-gateEND_OF_FUNC 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate#### Method: multipart_final 14410Sstevel@tonic-gate# Return a MIME boundary separator for server-push, end of all sections 14420Sstevel@tonic-gate# 14430Sstevel@tonic-gate# Contributed by Andrew Benham (adsb@bigfoot.com) 14440Sstevel@tonic-gate#### 14450Sstevel@tonic-gate'multipart_final' => <<'END_OF_FUNC', 14460Sstevel@tonic-gatesub multipart_final { 14470Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 14480Sstevel@tonic-gate return $self->{'final_separator'} . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $CRLF; 14490Sstevel@tonic-gate} 14500Sstevel@tonic-gateEND_OF_FUNC 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate#### Method: header 14540Sstevel@tonic-gate# Return a Content-Type: style header 14550Sstevel@tonic-gate# 14560Sstevel@tonic-gate#### 14570Sstevel@tonic-gate'header' => <<'END_OF_FUNC', 14580Sstevel@tonic-gatesub header { 14590Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 14600Sstevel@tonic-gate my(@header); 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate return "" if $self->{'.header_printed'}++ and $HEADERS_ONCE; 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate my($type,$status,$cookie,$target,$expires,$nph,$charset,$attachment,$p3p,@other) = 14650Sstevel@tonic-gate rearrange([['TYPE','CONTENT_TYPE','CONTENT-TYPE'], 14660Sstevel@tonic-gate 'STATUS',['COOKIE','COOKIES'],'TARGET', 14670Sstevel@tonic-gate 'EXPIRES','NPH','CHARSET', 14680Sstevel@tonic-gate 'ATTACHMENT','P3P'],@p); 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate $nph ||= $NPH; 1471*6287Sps156622 1472*6287Sps156622 $type ||= 'text/html' unless defined($type); 1473*6287Sps156622 14740Sstevel@tonic-gate if (defined $charset) { 14750Sstevel@tonic-gate $self->charset($charset); 14760Sstevel@tonic-gate } else { 1477*6287Sps156622 $charset = $self->charset if $type =~ /^text\//; 14780Sstevel@tonic-gate } 1479*6287Sps156622 $charset ||= ''; 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate # rearrange() was designed for the HTML portion, so we 14820Sstevel@tonic-gate # need to fix it up a little. 14830Sstevel@tonic-gate foreach (@other) { 14840Sstevel@tonic-gate # Don't use \s because of perl bug 21951 14850Sstevel@tonic-gate next unless my($header,$value) = /([^ \r\n\t=]+)=\"?(.+?)\"?$/; 14860Sstevel@tonic-gate ($_ = $header) =~ s/^(\w)(.*)/"\u$1\L$2" . ': '.$self->unescapeHTML($value)/e; 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 1489*6287Sps156622 $type .= "; charset=$charset" 1490*6287Sps156622 if $type ne '' 1491*6287Sps156622 and $type !~ /\bcharset\b/ 1492*6287Sps156622 and defined $charset 1493*6287Sps156622 and $charset ne ''; 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate # Maybe future compatibility. Maybe not. 14960Sstevel@tonic-gate my $protocol = $ENV{SERVER_PROTOCOL} || 'HTTP/1.0'; 14970Sstevel@tonic-gate push(@header,$protocol . ' ' . ($status || '200 OK')) if $nph; 14980Sstevel@tonic-gate push(@header,"Server: " . &server_software()) if $nph; 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate push(@header,"Status: $status") if $status; 15010Sstevel@tonic-gate push(@header,"Window-Target: $target") if $target; 15020Sstevel@tonic-gate if ($p3p) { 15030Sstevel@tonic-gate $p3p = join ' ',@$p3p if ref($p3p) eq 'ARRAY'; 15040Sstevel@tonic-gate push(@header,qq(P3P: policyref="/w3c/p3p.xml", CP="$p3p")); 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate # push all the cookies -- there may be several 15070Sstevel@tonic-gate if ($cookie) { 15080Sstevel@tonic-gate my(@cookie) = ref($cookie) && ref($cookie) eq 'ARRAY' ? @{$cookie} : $cookie; 15090Sstevel@tonic-gate foreach (@cookie) { 15100Sstevel@tonic-gate my $cs = UNIVERSAL::isa($_,'CGI::Cookie') ? $_->as_string : $_; 15110Sstevel@tonic-gate push(@header,"Set-Cookie: $cs") if $cs ne ''; 15120Sstevel@tonic-gate } 15130Sstevel@tonic-gate } 15140Sstevel@tonic-gate # if the user indicates an expiration time, then we need 15150Sstevel@tonic-gate # both an Expires and a Date header (so that the browser is 15160Sstevel@tonic-gate # uses OUR clock) 15170Sstevel@tonic-gate push(@header,"Expires: " . expires($expires,'http')) 15180Sstevel@tonic-gate if $expires; 15190Sstevel@tonic-gate push(@header,"Date: " . expires(0,'http')) if $expires || $cookie || $nph; 15200Sstevel@tonic-gate push(@header,"Pragma: no-cache") if $self->cache(); 15210Sstevel@tonic-gate push(@header,"Content-Disposition: attachment; filename=\"$attachment\"") if $attachment; 15220Sstevel@tonic-gate push(@header,map {ucfirst $_} @other); 15230Sstevel@tonic-gate push(@header,"Content-Type: $type") if $type ne ''; 15240Sstevel@tonic-gate my $header = join($CRLF,@header)."${CRLF}${CRLF}"; 1525*6287Sps156622 if (($MOD_PERL >= 1) && !$nph) { 15260Sstevel@tonic-gate $self->r->send_cgi_header($header); 15270Sstevel@tonic-gate return ''; 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate return $header; 15300Sstevel@tonic-gate} 15310Sstevel@tonic-gateEND_OF_FUNC 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate#### Method: cache 15350Sstevel@tonic-gate# Control whether header() will produce the no-cache 15360Sstevel@tonic-gate# Pragma directive. 15370Sstevel@tonic-gate#### 15380Sstevel@tonic-gate'cache' => <<'END_OF_FUNC', 15390Sstevel@tonic-gatesub cache { 15400Sstevel@tonic-gate my($self,$new_value) = self_or_default(@_); 15410Sstevel@tonic-gate $new_value = '' unless $new_value; 15420Sstevel@tonic-gate if ($new_value ne '') { 15430Sstevel@tonic-gate $self->{'cache'} = $new_value; 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate return $self->{'cache'}; 15460Sstevel@tonic-gate} 15470Sstevel@tonic-gateEND_OF_FUNC 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate#### Method: redirect 15510Sstevel@tonic-gate# Return a Location: style header 15520Sstevel@tonic-gate# 15530Sstevel@tonic-gate#### 15540Sstevel@tonic-gate'redirect' => <<'END_OF_FUNC', 15550Sstevel@tonic-gatesub redirect { 15560Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 1557667Sps156622 my($url,$target,$status,$cookie,$nph,@other) = 1558667Sps156622 rearrange([[LOCATION,URI,URL],TARGET,STATUS,['COOKIE','COOKIES'],NPH],@p); 1559*6287Sps156622 $status = '302 Found' unless defined $status; 15600Sstevel@tonic-gate $url ||= $self->self_url; 15610Sstevel@tonic-gate my(@o); 15620Sstevel@tonic-gate foreach (@other) { tr/\"//d; push(@o,split("=",$_,2)); } 15630Sstevel@tonic-gate unshift(@o, 1564667Sps156622 '-Status' => $status, 15650Sstevel@tonic-gate '-Location'=> $url, 15660Sstevel@tonic-gate '-nph' => $nph); 15670Sstevel@tonic-gate unshift(@o,'-Target'=>$target) if $target; 15680Sstevel@tonic-gate unshift(@o,'-Type'=>''); 15690Sstevel@tonic-gate my @unescaped; 15700Sstevel@tonic-gate unshift(@unescaped,'-Cookie'=>$cookie) if $cookie; 15710Sstevel@tonic-gate return $self->header((map {$self->unescapeHTML($_)} @o),@unescaped); 15720Sstevel@tonic-gate} 15730Sstevel@tonic-gateEND_OF_FUNC 15740Sstevel@tonic-gate 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate#### Method: start_html 15770Sstevel@tonic-gate# Canned HTML header 15780Sstevel@tonic-gate# 15790Sstevel@tonic-gate# Parameters: 15800Sstevel@tonic-gate# $title -> (optional) The title for this HTML document (-title) 15810Sstevel@tonic-gate# $author -> (optional) e-mail address of the author (-author) 15820Sstevel@tonic-gate# $base -> (optional) if set to true, will enter the BASE address of this document 15830Sstevel@tonic-gate# for resolving relative references (-base) 15840Sstevel@tonic-gate# $xbase -> (optional) alternative base at some remote location (-xbase) 15850Sstevel@tonic-gate# $target -> (optional) target window to load all links into (-target) 15860Sstevel@tonic-gate# $script -> (option) Javascript code (-script) 15870Sstevel@tonic-gate# $no_script -> (option) Javascript <noscript> tag (-noscript) 15880Sstevel@tonic-gate# $meta -> (optional) Meta information tags 15890Sstevel@tonic-gate# $head -> (optional) any other elements you'd like to incorporate into the <head> tag 15900Sstevel@tonic-gate# (a scalar or array ref) 15910Sstevel@tonic-gate# $style -> (optional) reference to an external style sheet 15920Sstevel@tonic-gate# @other -> (optional) any other named parameters you'd like to incorporate into 15930Sstevel@tonic-gate# the <body> tag. 15940Sstevel@tonic-gate#### 15950Sstevel@tonic-gate'start_html' => <<'END_OF_FUNC', 15960Sstevel@tonic-gatesub start_html { 15970Sstevel@tonic-gate my($self,@p) = &self_or_default(@_); 15980Sstevel@tonic-gate my($title,$author,$base,$xbase,$script,$noscript, 1599667Sps156622 $target,$meta,$head,$style,$dtd,$lang,$encoding,$declare_xml,@other) = 1600667Sps156622 rearrange([TITLE,AUTHOR,BASE,XBASE,SCRIPT,NOSCRIPT,TARGET, 1601667Sps156622 META,HEAD,STYLE,DTD,LANG,ENCODING,DECLARE_XML],@p); 1602667Sps156622 1603667Sps156622 $self->element_id(0); 1604667Sps156622 $self->element_tab(0); 16050Sstevel@tonic-gate 1606*6287Sps156622 $encoding = lc($self->charset) unless defined $encoding; 16070Sstevel@tonic-gate 1608667Sps156622 # Need to sort out the DTD before it's okay to call escapeHTML(). 16090Sstevel@tonic-gate my(@result,$xml_dtd); 16100Sstevel@tonic-gate if ($dtd) { 16110Sstevel@tonic-gate if (defined(ref($dtd)) and (ref($dtd) eq 'ARRAY')) { 16120Sstevel@tonic-gate $dtd = $DEFAULT_DTD unless $dtd->[0] =~ m|^-//|; 16130Sstevel@tonic-gate } else { 16140Sstevel@tonic-gate $dtd = $DEFAULT_DTD unless $dtd =~ m|^-//|; 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate } else { 16170Sstevel@tonic-gate $dtd = $XHTML ? XHTML_DTD : $DEFAULT_DTD; 16180Sstevel@tonic-gate } 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate $xml_dtd++ if ref($dtd) eq 'ARRAY' && $dtd->[0] =~ /\bXHTML\b/i; 16210Sstevel@tonic-gate $xml_dtd++ if ref($dtd) eq '' && $dtd =~ /\bXHTML\b/i; 1622667Sps156622 push @result,qq(<?xml version="1.0" encoding="$encoding"?>) if $xml_dtd && $declare_xml; 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate if (ref($dtd) && ref($dtd) eq 'ARRAY') { 16250Sstevel@tonic-gate push(@result,qq(<!DOCTYPE html\n\tPUBLIC "$dtd->[0]"\n\t "$dtd->[1]">)); 1626667Sps156622 $DTD_PUBLIC_IDENTIFIER = $dtd->[0]; 16270Sstevel@tonic-gate } else { 16280Sstevel@tonic-gate push(@result,qq(<!DOCTYPE html\n\tPUBLIC "$dtd">)); 1629667Sps156622 $DTD_PUBLIC_IDENTIFIER = $dtd; 16300Sstevel@tonic-gate } 1631667Sps156622 1632667Sps156622 # Now that we know whether we're using the HTML 3.2 DTD or not, it's okay to 1633667Sps156622 # call escapeHTML(). Strangely enough, the title needs to be escaped as 1634667Sps156622 # HTML while the author needs to be escaped as a URL. 1635667Sps156622 $title = $self->escapeHTML($title || 'Untitled Document'); 1636667Sps156622 $author = $self->escape($author); 1637667Sps156622 1638667Sps156622 if ($DTD_PUBLIC_IDENTIFIER =~ /[^X]HTML (2\.0|3\.2)/i) { 1639667Sps156622 $lang = "" unless defined $lang; 1640667Sps156622 $XHTML = 0; 1641667Sps156622 } 1642667Sps156622 else { 1643667Sps156622 $lang = 'en-US' unless defined $lang; 1644667Sps156622 } 1645667Sps156622 1646667Sps156622 my $lang_bits = $lang ne '' ? qq( lang="$lang" xml:lang="$lang") : ''; 1647667Sps156622 my $meta_bits = qq(<meta http-equiv="Content-Type" content="text/html; charset=$encoding" />) 1648667Sps156622 if $XHTML && $encoding && !$declare_xml; 1649667Sps156622 1650667Sps156622 push(@result,$XHTML ? qq(<html xmlns="http://www.w3.org/1999/xhtml"$lang_bits>\n<head>\n<title>$title</title>) 1651667Sps156622 : ($lang ? qq(<html lang="$lang">) : "<html>") 16520Sstevel@tonic-gate . "<head><title>$title</title>"); 16530Sstevel@tonic-gate if (defined $author) { 16540Sstevel@tonic-gate push(@result,$XHTML ? "<link rev=\"made\" href=\"mailto:$author\" />" 1655667Sps156622 : "<link rev=\"made\" href=\"mailto:$author\">"); 16560Sstevel@tonic-gate } 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate if ($base || $xbase || $target) { 16590Sstevel@tonic-gate my $href = $xbase || $self->url('-path'=>1); 16600Sstevel@tonic-gate my $t = $target ? qq/ target="$target"/ : ''; 16610Sstevel@tonic-gate push(@result,$XHTML ? qq(<base href="$href"$t />) : qq(<base href="$href"$t>)); 16620Sstevel@tonic-gate } 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate if ($meta && ref($meta) && (ref($meta) eq 'HASH')) { 16650Sstevel@tonic-gate foreach (keys %$meta) { push(@result,$XHTML ? qq(<meta name="$_" content="$meta->{$_}" />) 16660Sstevel@tonic-gate : qq(<meta name="$_" content="$meta->{$_}">)); } 16670Sstevel@tonic-gate } 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate push(@result,ref($head) ? @$head : $head) if $head; 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate # handle the infrequently-used -style and -script parameters 1672667Sps156622 push(@result,$self->_style($style)) if defined $style; 16730Sstevel@tonic-gate push(@result,$self->_script($script)) if defined $script; 1674667Sps156622 push(@result,$meta_bits) if defined $meta_bits; 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate # handle -noscript parameter 16770Sstevel@tonic-gate push(@result,<<END) if $noscript; 16780Sstevel@tonic-gate<noscript> 16790Sstevel@tonic-gate$noscript 16800Sstevel@tonic-gate</noscript> 16810Sstevel@tonic-gateEND 16820Sstevel@tonic-gate ; 16830Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 1684667Sps156622 push(@result,"</head>\n<body$other>\n"); 16850Sstevel@tonic-gate return join("\n",@result); 16860Sstevel@tonic-gate} 16870Sstevel@tonic-gateEND_OF_FUNC 16880Sstevel@tonic-gate 16890Sstevel@tonic-gate### Method: _style 16900Sstevel@tonic-gate# internal method for generating a CSS style section 16910Sstevel@tonic-gate#### 16920Sstevel@tonic-gate'_style' => <<'END_OF_FUNC', 16930Sstevel@tonic-gatesub _style { 16940Sstevel@tonic-gate my ($self,$style) = @_; 16950Sstevel@tonic-gate my (@result); 1696*6287Sps156622 16970Sstevel@tonic-gate my $type = 'text/css'; 1698*6287Sps156622 my $rel = 'stylesheet'; 1699*6287Sps156622 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate my $cdata_start = $XHTML ? "\n<!--/* <![CDATA[ */" : "\n<!-- "; 17020Sstevel@tonic-gate my $cdata_end = $XHTML ? "\n/* ]]> */-->\n" : " -->\n"; 17030Sstevel@tonic-gate 1704667Sps156622 my @s = ref($style) eq 'ARRAY' ? @$style : $style; 1705*6287Sps156622 my $other = ''; 1706667Sps156622 1707667Sps156622 for my $s (@s) { 1708667Sps156622 if (ref($s)) { 1709*6287Sps156622 my($src,$code,$verbatim,$stype,$alternate,$foo,@other) = 1710*6287Sps156622 rearrange([qw(SRC CODE VERBATIM TYPE ALTERNATE FOO)], 1711667Sps156622 ('-foo'=>'bar', 1712667Sps156622 ref($s) eq 'ARRAY' ? @$s : %$s)); 1713*6287Sps156622 my $type = defined $stype ? $stype : 'text/css'; 1714*6287Sps156622 my $rel = $alternate ? 'alternate stylesheet' : 'stylesheet'; 1715*6287Sps156622 $other = "@other" if @other; 1716667Sps156622 1717667Sps156622 if (ref($src) eq "ARRAY") # Check to see if the $src variable is an array reference 1718667Sps156622 { # If it is, push a LINK tag for each one 1719667Sps156622 foreach $src (@$src) 1720667Sps156622 { 1721*6287Sps156622 push(@result,$XHTML ? qq(<link rel="$rel" type="$type" href="$src" $other/>) 1722*6287Sps156622 : qq(<link rel="$rel" type="$type" href="$src"$other>)) if $src; 1723667Sps156622 } 17240Sstevel@tonic-gate } 1725667Sps156622 else 1726667Sps156622 { # Otherwise, push the single -src, if it exists. 1727*6287Sps156622 push(@result,$XHTML ? qq(<link rel="$rel" type="$type" href="$src" $other/>) 1728*6287Sps156622 : qq(<link rel="$rel" type="$type" href="$src"$other>) 1729667Sps156622 ) if $src; 1730667Sps156622 } 1731667Sps156622 if ($verbatim) { 1732667Sps156622 my @v = ref($verbatim) eq 'ARRAY' ? @$verbatim : $verbatim; 1733667Sps156622 push(@result, "<style type=\"text/css\">\n$_\n</style>") foreach @v; 17340Sstevel@tonic-gate } 1735667Sps156622 my @c = ref($code) eq 'ARRAY' ? @$code : $code if $code; 1736667Sps156622 push(@result,style({'type'=>$type},"$cdata_start\n$_\n$cdata_end")) foreach @c; 1737667Sps156622 1738667Sps156622 } else { 1739667Sps156622 my $src = $s; 1740*6287Sps156622 push(@result,$XHTML ? qq(<link rel="$rel" type="$type" href="$src" $other/>) 1741*6287Sps156622 : qq(<link rel="$rel" type="$type" href="$src"$other>)); 1742667Sps156622 } 17430Sstevel@tonic-gate } 17440Sstevel@tonic-gate @result; 17450Sstevel@tonic-gate} 17460Sstevel@tonic-gateEND_OF_FUNC 17470Sstevel@tonic-gate 17480Sstevel@tonic-gate'_script' => <<'END_OF_FUNC', 17490Sstevel@tonic-gatesub _script { 17500Sstevel@tonic-gate my ($self,$script) = @_; 17510Sstevel@tonic-gate my (@result); 17520Sstevel@tonic-gate 17530Sstevel@tonic-gate my (@scripts) = ref($script) eq 'ARRAY' ? @$script : ($script); 17540Sstevel@tonic-gate foreach $script (@scripts) { 17550Sstevel@tonic-gate my($src,$code,$language); 17560Sstevel@tonic-gate if (ref($script)) { # script is a hash 1757*6287Sps156622 ($src,$code,$type) = 1758*6287Sps156622 rearrange(['SRC','CODE',['LANGUAGE','TYPE']], 17590Sstevel@tonic-gate '-foo'=>'bar', # a trick to allow the '-' to be omitted 17600Sstevel@tonic-gate ref($script) eq 'ARRAY' ? @$script : %$script); 1761*6287Sps156622 $type ||= 'text/javascript'; 1762*6287Sps156622 unless ($type =~ m!\w+/\w+!) { 1763*6287Sps156622 $type =~ s/[\d.]+$//; 1764*6287Sps156622 $type = "text/$type"; 17650Sstevel@tonic-gate } 17660Sstevel@tonic-gate } else { 1767*6287Sps156622 ($src,$code,$type) = ('',$script, 'text/javascript'); 17680Sstevel@tonic-gate } 17690Sstevel@tonic-gate 17700Sstevel@tonic-gate my $comment = '//'; # javascript by default 17710Sstevel@tonic-gate $comment = '#' if $type=~/perl|tcl/i; 17720Sstevel@tonic-gate $comment = "'" if $type=~/vbscript/i; 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate my ($cdata_start,$cdata_end); 17750Sstevel@tonic-gate if ($XHTML) { 17760Sstevel@tonic-gate $cdata_start = "$comment<![CDATA[\n"; 17770Sstevel@tonic-gate $cdata_end .= "\n$comment]]>"; 17780Sstevel@tonic-gate } else { 17790Sstevel@tonic-gate $cdata_start = "\n<!-- Hide script\n"; 17800Sstevel@tonic-gate $cdata_end = $comment; 17810Sstevel@tonic-gate $cdata_end .= " End script hiding -->\n"; 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate my(@satts); 17840Sstevel@tonic-gate push(@satts,'src'=>$src) if $src; 17850Sstevel@tonic-gate push(@satts,'type'=>$type); 1786667Sps156622 $code = $cdata_start . $code . $cdata_end if defined $code; 1787667Sps156622 push(@result,$self->script({@satts},$code || '')); 17880Sstevel@tonic-gate } 17890Sstevel@tonic-gate @result; 17900Sstevel@tonic-gate} 17910Sstevel@tonic-gateEND_OF_FUNC 17920Sstevel@tonic-gate 17930Sstevel@tonic-gate#### Method: end_html 17940Sstevel@tonic-gate# End an HTML document. 17950Sstevel@tonic-gate# Trivial method for completeness. Just returns "</body>" 17960Sstevel@tonic-gate#### 17970Sstevel@tonic-gate'end_html' => <<'END_OF_FUNC', 17980Sstevel@tonic-gatesub end_html { 1799667Sps156622 return "\n</body>\n</html>"; 18000Sstevel@tonic-gate} 18010Sstevel@tonic-gateEND_OF_FUNC 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate################################ 18050Sstevel@tonic-gate# METHODS USED IN BUILDING FORMS 18060Sstevel@tonic-gate################################ 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate#### Method: isindex 18090Sstevel@tonic-gate# Just prints out the isindex tag. 18100Sstevel@tonic-gate# Parameters: 18110Sstevel@tonic-gate# $action -> optional URL of script to run 18120Sstevel@tonic-gate# Returns: 18130Sstevel@tonic-gate# A string containing a <isindex> tag 18140Sstevel@tonic-gate'isindex' => <<'END_OF_FUNC', 18150Sstevel@tonic-gatesub isindex { 18160Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 18170Sstevel@tonic-gate my($action,@other) = rearrange([ACTION],@p); 18180Sstevel@tonic-gate $action = qq/ action="$action"/ if $action; 18190Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 18200Sstevel@tonic-gate return $XHTML ? "<isindex$action$other />" : "<isindex$action$other>"; 18210Sstevel@tonic-gate} 18220Sstevel@tonic-gateEND_OF_FUNC 18230Sstevel@tonic-gate 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate#### Method: startform 18260Sstevel@tonic-gate# Start a form 18270Sstevel@tonic-gate# Parameters: 18280Sstevel@tonic-gate# $method -> optional submission method to use (GET or POST) 18290Sstevel@tonic-gate# $action -> optional URL of script to run 18300Sstevel@tonic-gate# $enctype ->encoding to use (URL_ENCODED or MULTIPART) 18310Sstevel@tonic-gate'startform' => <<'END_OF_FUNC', 18320Sstevel@tonic-gatesub startform { 18330Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate my($method,$action,$enctype,@other) = 18360Sstevel@tonic-gate rearrange([METHOD,ACTION,ENCTYPE],@p); 18370Sstevel@tonic-gate 1838667Sps156622 $method = $self->escapeHTML(lc($method) || 'post'); 1839667Sps156622 $enctype = $self->escapeHTML($enctype || &URL_ENCODED); 1840667Sps156622 if (defined $action) { 1841667Sps156622 $action = $self->escapeHTML($action); 1842667Sps156622 } 1843667Sps156622 else { 1844*6287Sps156622 $action = $self->escapeHTML($self->request_uri || $self->self_url); 18450Sstevel@tonic-gate } 18460Sstevel@tonic-gate $action = qq(action="$action"); 18470Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 18480Sstevel@tonic-gate $self->{'.parametersToAdd'}={}; 18490Sstevel@tonic-gate return qq/<form method="$method" $action enctype="$enctype"$other>\n/; 18500Sstevel@tonic-gate} 18510Sstevel@tonic-gateEND_OF_FUNC 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate 18540Sstevel@tonic-gate#### Method: start_form 18550Sstevel@tonic-gate# synonym for startform 18560Sstevel@tonic-gate'start_form' => <<'END_OF_FUNC', 18570Sstevel@tonic-gatesub start_form { 1858667Sps156622 $XHTML ? &start_multipart_form : &startform; 18590Sstevel@tonic-gate} 18600Sstevel@tonic-gateEND_OF_FUNC 18610Sstevel@tonic-gate 18620Sstevel@tonic-gate'end_multipart_form' => <<'END_OF_FUNC', 18630Sstevel@tonic-gatesub end_multipart_form { 18640Sstevel@tonic-gate &endform; 18650Sstevel@tonic-gate} 18660Sstevel@tonic-gateEND_OF_FUNC 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate#### Method: start_multipart_form 18690Sstevel@tonic-gate# synonym for startform 18700Sstevel@tonic-gate'start_multipart_form' => <<'END_OF_FUNC', 18710Sstevel@tonic-gatesub start_multipart_form { 18720Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 1873*6287Sps156622 if (defined($p[0]) && substr($p[0],0,1) eq '-') { 1874*6287Sps156622 return $self->startform(-enctype=>&MULTIPART,@p); 18750Sstevel@tonic-gate } else { 18760Sstevel@tonic-gate my($method,$action,@other) = 18770Sstevel@tonic-gate rearrange([METHOD,ACTION],@p); 18780Sstevel@tonic-gate return $self->startform($method,$action,&MULTIPART,@other); 18790Sstevel@tonic-gate } 18800Sstevel@tonic-gate} 18810Sstevel@tonic-gateEND_OF_FUNC 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate 18840Sstevel@tonic-gate#### Method: endform 18850Sstevel@tonic-gate# End a form 18860Sstevel@tonic-gate'endform' => <<'END_OF_FUNC', 18870Sstevel@tonic-gatesub endform { 1888*6287Sps156622 my($self,@p) = self_or_default(@_); 18890Sstevel@tonic-gate if ( $NOSTICKY ) { 18900Sstevel@tonic-gate return wantarray ? ("</form>") : "\n</form>"; 18910Sstevel@tonic-gate } else { 1892*6287Sps156622 if (my @fields = $self->get_fields) { 1893*6287Sps156622 return wantarray ? ("<div>",@fields,"</div>","</form>") 1894*6287Sps156622 : "<div>".(join '',@fields)."</div>\n</form>"; 1895*6287Sps156622 } else { 1896*6287Sps156622 return "</form>"; 1897*6287Sps156622 } 18980Sstevel@tonic-gate } 18990Sstevel@tonic-gate} 19000Sstevel@tonic-gateEND_OF_FUNC 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate'_textfield' => <<'END_OF_FUNC', 19040Sstevel@tonic-gatesub _textfield { 19050Sstevel@tonic-gate my($self,$tag,@p) = self_or_default(@_); 1906667Sps156622 my($name,$default,$size,$maxlength,$override,$tabindex,@other) = 1907667Sps156622 rearrange([NAME,[DEFAULT,VALUE,VALUES],SIZE,MAXLENGTH,[OVERRIDE,FORCE],TABINDEX],@p); 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate my $current = $override ? $default : 19100Sstevel@tonic-gate (defined($self->param($name)) ? $self->param($name) : $default); 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate $current = defined($current) ? $self->escapeHTML($current,1) : ''; 19130Sstevel@tonic-gate $name = defined($name) ? $self->escapeHTML($name) : ''; 19140Sstevel@tonic-gate my($s) = defined($size) ? qq/ size="$size"/ : ''; 19150Sstevel@tonic-gate my($m) = defined($maxlength) ? qq/ maxlength="$maxlength"/ : ''; 19160Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 19170Sstevel@tonic-gate # this entered at cristy's request to fix problems with file upload fields 19180Sstevel@tonic-gate # and WebTV -- not sure it won't break stuff 19190Sstevel@tonic-gate my($value) = $current ne '' ? qq(value="$current") : ''; 1920667Sps156622 $tabindex = $self->element_tab($tabindex); 1921*6287Sps156622 return $XHTML ? qq(<input type="$tag" name="$name" $tabindex$value$s$m$other />) 19220Sstevel@tonic-gate : qq(<input type="$tag" name="$name" $value$s$m$other>); 19230Sstevel@tonic-gate} 19240Sstevel@tonic-gateEND_OF_FUNC 19250Sstevel@tonic-gate 19260Sstevel@tonic-gate#### Method: textfield 19270Sstevel@tonic-gate# Parameters: 19280Sstevel@tonic-gate# $name -> Name of the text field 19290Sstevel@tonic-gate# $default -> Optional default value of the field if not 19300Sstevel@tonic-gate# already defined. 19310Sstevel@tonic-gate# $size -> Optional width of field in characaters. 19320Sstevel@tonic-gate# $maxlength -> Optional maximum number of characters. 19330Sstevel@tonic-gate# Returns: 19340Sstevel@tonic-gate# A string containing a <input type="text"> field 19350Sstevel@tonic-gate# 19360Sstevel@tonic-gate'textfield' => <<'END_OF_FUNC', 19370Sstevel@tonic-gatesub textfield { 19380Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 19390Sstevel@tonic-gate $self->_textfield('text',@p); 19400Sstevel@tonic-gate} 19410Sstevel@tonic-gateEND_OF_FUNC 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate 19440Sstevel@tonic-gate#### Method: filefield 19450Sstevel@tonic-gate# Parameters: 19460Sstevel@tonic-gate# $name -> Name of the file upload field 19470Sstevel@tonic-gate# $size -> Optional width of field in characaters. 19480Sstevel@tonic-gate# $maxlength -> Optional maximum number of characters. 19490Sstevel@tonic-gate# Returns: 19500Sstevel@tonic-gate# A string containing a <input type="file"> field 19510Sstevel@tonic-gate# 19520Sstevel@tonic-gate'filefield' => <<'END_OF_FUNC', 19530Sstevel@tonic-gatesub filefield { 19540Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 19550Sstevel@tonic-gate $self->_textfield('file',@p); 19560Sstevel@tonic-gate} 19570Sstevel@tonic-gateEND_OF_FUNC 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate 19600Sstevel@tonic-gate#### Method: password 19610Sstevel@tonic-gate# Create a "secret password" entry field 19620Sstevel@tonic-gate# Parameters: 19630Sstevel@tonic-gate# $name -> Name of the field 19640Sstevel@tonic-gate# $default -> Optional default value of the field if not 19650Sstevel@tonic-gate# already defined. 19660Sstevel@tonic-gate# $size -> Optional width of field in characters. 19670Sstevel@tonic-gate# $maxlength -> Optional maximum characters that can be entered. 19680Sstevel@tonic-gate# Returns: 19690Sstevel@tonic-gate# A string containing a <input type="password"> field 19700Sstevel@tonic-gate# 19710Sstevel@tonic-gate'password_field' => <<'END_OF_FUNC', 19720Sstevel@tonic-gatesub password_field { 19730Sstevel@tonic-gate my ($self,@p) = self_or_default(@_); 19740Sstevel@tonic-gate $self->_textfield('password',@p); 19750Sstevel@tonic-gate} 19760Sstevel@tonic-gateEND_OF_FUNC 19770Sstevel@tonic-gate 19780Sstevel@tonic-gate#### Method: textarea 19790Sstevel@tonic-gate# Parameters: 19800Sstevel@tonic-gate# $name -> Name of the text field 19810Sstevel@tonic-gate# $default -> Optional default value of the field if not 19820Sstevel@tonic-gate# already defined. 19830Sstevel@tonic-gate# $rows -> Optional number of rows in text area 19840Sstevel@tonic-gate# $columns -> Optional number of columns in text area 19850Sstevel@tonic-gate# Returns: 19860Sstevel@tonic-gate# A string containing a <textarea></textarea> tag 19870Sstevel@tonic-gate# 19880Sstevel@tonic-gate'textarea' => <<'END_OF_FUNC', 19890Sstevel@tonic-gatesub textarea { 19900Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 1991667Sps156622 my($name,$default,$rows,$cols,$override,$tabindex,@other) = 1992667Sps156622 rearrange([NAME,[DEFAULT,VALUE],ROWS,[COLS,COLUMNS],[OVERRIDE,FORCE],TABINDEX],@p); 19930Sstevel@tonic-gate 19940Sstevel@tonic-gate my($current)= $override ? $default : 19950Sstevel@tonic-gate (defined($self->param($name)) ? $self->param($name) : $default); 19960Sstevel@tonic-gate 19970Sstevel@tonic-gate $name = defined($name) ? $self->escapeHTML($name) : ''; 19980Sstevel@tonic-gate $current = defined($current) ? $self->escapeHTML($current) : ''; 19990Sstevel@tonic-gate my($r) = $rows ? qq/ rows="$rows"/ : ''; 20000Sstevel@tonic-gate my($c) = $cols ? qq/ cols="$cols"/ : ''; 20010Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 2002667Sps156622 $tabindex = $self->element_tab($tabindex); 2003*6287Sps156622 return qq{<textarea name="$name" $tabindex$r$c$other>$current</textarea>}; 20040Sstevel@tonic-gate} 20050Sstevel@tonic-gateEND_OF_FUNC 20060Sstevel@tonic-gate 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate#### Method: button 20090Sstevel@tonic-gate# Create a javascript button. 20100Sstevel@tonic-gate# Parameters: 20110Sstevel@tonic-gate# $name -> (optional) Name for the button. (-name) 20120Sstevel@tonic-gate# $value -> (optional) Value of the button when selected (and visible name) (-value) 20130Sstevel@tonic-gate# $onclick -> (optional) Text of the JavaScript to run when the button is 20140Sstevel@tonic-gate# clicked. 20150Sstevel@tonic-gate# Returns: 20160Sstevel@tonic-gate# A string containing a <input type="button"> tag 20170Sstevel@tonic-gate#### 20180Sstevel@tonic-gate'button' => <<'END_OF_FUNC', 20190Sstevel@tonic-gatesub button { 20200Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 20210Sstevel@tonic-gate 2022667Sps156622 my($label,$value,$script,$tabindex,@other) = rearrange([NAME,[VALUE,LABEL], 2023667Sps156622 [ONCLICK,SCRIPT],TABINDEX],@p); 20240Sstevel@tonic-gate 20250Sstevel@tonic-gate $label=$self->escapeHTML($label); 20260Sstevel@tonic-gate $value=$self->escapeHTML($value,1); 20270Sstevel@tonic-gate $script=$self->escapeHTML($script); 20280Sstevel@tonic-gate 20290Sstevel@tonic-gate my($name) = ''; 20300Sstevel@tonic-gate $name = qq/ name="$label"/ if $label; 20310Sstevel@tonic-gate $value = $value || $label; 20320Sstevel@tonic-gate my($val) = ''; 20330Sstevel@tonic-gate $val = qq/ value="$value"/ if $value; 20340Sstevel@tonic-gate $script = qq/ onclick="$script"/ if $script; 20350Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 2036667Sps156622 $tabindex = $self->element_tab($tabindex); 2037*6287Sps156622 return $XHTML ? qq(<input type="button" $tabindex$name$val$script$other />) 20380Sstevel@tonic-gate : qq(<input type="button"$name$val$script$other>); 20390Sstevel@tonic-gate} 20400Sstevel@tonic-gateEND_OF_FUNC 20410Sstevel@tonic-gate 20420Sstevel@tonic-gate 20430Sstevel@tonic-gate#### Method: submit 20440Sstevel@tonic-gate# Create a "submit query" button. 20450Sstevel@tonic-gate# Parameters: 20460Sstevel@tonic-gate# $name -> (optional) Name for the button. 20470Sstevel@tonic-gate# $value -> (optional) Value of the button when selected (also doubles as label). 20480Sstevel@tonic-gate# $label -> (optional) Label printed on the button(also doubles as the value). 20490Sstevel@tonic-gate# Returns: 20500Sstevel@tonic-gate# A string containing a <input type="submit"> tag 20510Sstevel@tonic-gate#### 20520Sstevel@tonic-gate'submit' => <<'END_OF_FUNC', 20530Sstevel@tonic-gatesub submit { 20540Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 20550Sstevel@tonic-gate 2056667Sps156622 my($label,$value,$tabindex,@other) = rearrange([NAME,[VALUE,LABEL],TABINDEX],@p); 20570Sstevel@tonic-gate 20580Sstevel@tonic-gate $label=$self->escapeHTML($label); 20590Sstevel@tonic-gate $value=$self->escapeHTML($value,1); 20600Sstevel@tonic-gate 2061*6287Sps156622 my $name = $NOSTICKY ? '' : 'name=".submit" '; 2062*6287Sps156622 $name = qq/name="$label" / if defined($label); 20630Sstevel@tonic-gate $value = defined($value) ? $value : $label; 20640Sstevel@tonic-gate my $val = ''; 2065*6287Sps156622 $val = qq/value="$value" / if defined($value); 2066667Sps156622 $tabindex = $self->element_tab($tabindex); 2067*6287Sps156622 my($other) = @other ? "@other " : ''; 2068*6287Sps156622 return $XHTML ? qq(<input type="submit" $tabindex$name$val$other/>) 2069*6287Sps156622 : qq(<input type="submit" $name$val$other>); 20700Sstevel@tonic-gate} 20710Sstevel@tonic-gateEND_OF_FUNC 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate 20740Sstevel@tonic-gate#### Method: reset 20750Sstevel@tonic-gate# Create a "reset" button. 20760Sstevel@tonic-gate# Parameters: 20770Sstevel@tonic-gate# $name -> (optional) Name for the button. 20780Sstevel@tonic-gate# Returns: 20790Sstevel@tonic-gate# A string containing a <input type="reset"> tag 20800Sstevel@tonic-gate#### 20810Sstevel@tonic-gate'reset' => <<'END_OF_FUNC', 20820Sstevel@tonic-gatesub reset { 20830Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 2084667Sps156622 my($label,$value,$tabindex,@other) = rearrange(['NAME',['VALUE','LABEL'],TABINDEX],@p); 20850Sstevel@tonic-gate $label=$self->escapeHTML($label); 20860Sstevel@tonic-gate $value=$self->escapeHTML($value,1); 20870Sstevel@tonic-gate my ($name) = ' name=".reset"'; 20880Sstevel@tonic-gate $name = qq/ name="$label"/ if defined($label); 20890Sstevel@tonic-gate $value = defined($value) ? $value : $label; 20900Sstevel@tonic-gate my($val) = ''; 20910Sstevel@tonic-gate $val = qq/ value="$value"/ if defined($value); 20920Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 2093667Sps156622 $tabindex = $self->element_tab($tabindex); 2094*6287Sps156622 return $XHTML ? qq(<input type="reset" $tabindex$name$val$other />) 20950Sstevel@tonic-gate : qq(<input type="reset"$name$val$other>); 20960Sstevel@tonic-gate} 20970Sstevel@tonic-gateEND_OF_FUNC 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate 21000Sstevel@tonic-gate#### Method: defaults 21010Sstevel@tonic-gate# Create a "defaults" button. 21020Sstevel@tonic-gate# Parameters: 21030Sstevel@tonic-gate# $name -> (optional) Name for the button. 21040Sstevel@tonic-gate# Returns: 21050Sstevel@tonic-gate# A string containing a <input type="submit" name=".defaults"> tag 21060Sstevel@tonic-gate# 21070Sstevel@tonic-gate# Note: this button has a special meaning to the initialization script, 21080Sstevel@tonic-gate# and tells it to ERASE the current query string so that your defaults 21090Sstevel@tonic-gate# are used again! 21100Sstevel@tonic-gate#### 21110Sstevel@tonic-gate'defaults' => <<'END_OF_FUNC', 21120Sstevel@tonic-gatesub defaults { 21130Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 21140Sstevel@tonic-gate 2115667Sps156622 my($label,$tabindex,@other) = rearrange([[NAME,VALUE],TABINDEX],@p); 21160Sstevel@tonic-gate 21170Sstevel@tonic-gate $label=$self->escapeHTML($label,1); 21180Sstevel@tonic-gate $label = $label || "Defaults"; 21190Sstevel@tonic-gate my($value) = qq/ value="$label"/; 21200Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 2121667Sps156622 $tabindex = $self->element_tab($tabindex); 2122*6287Sps156622 return $XHTML ? qq(<input type="submit" name=".defaults" $tabindex$value$other />) 21230Sstevel@tonic-gate : qq/<input type="submit" NAME=".defaults"$value$other>/; 21240Sstevel@tonic-gate} 21250Sstevel@tonic-gateEND_OF_FUNC 21260Sstevel@tonic-gate 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate#### Method: comment 21290Sstevel@tonic-gate# Create an HTML <!-- comment --> 21300Sstevel@tonic-gate# Parameters: a string 21310Sstevel@tonic-gate'comment' => <<'END_OF_FUNC', 21320Sstevel@tonic-gatesub comment { 21330Sstevel@tonic-gate my($self,@p) = self_or_CGI(@_); 21340Sstevel@tonic-gate return "<!-- @p -->"; 21350Sstevel@tonic-gate} 21360Sstevel@tonic-gateEND_OF_FUNC 21370Sstevel@tonic-gate 21380Sstevel@tonic-gate#### Method: checkbox 21390Sstevel@tonic-gate# Create a checkbox that is not logically linked to any others. 21400Sstevel@tonic-gate# The field value is "on" when the button is checked. 21410Sstevel@tonic-gate# Parameters: 21420Sstevel@tonic-gate# $name -> Name of the checkbox 21430Sstevel@tonic-gate# $checked -> (optional) turned on by default if true 21440Sstevel@tonic-gate# $value -> (optional) value of the checkbox, 'on' by default 21450Sstevel@tonic-gate# $label -> (optional) a user-readable label printed next to the box. 21460Sstevel@tonic-gate# Otherwise the checkbox name is used. 21470Sstevel@tonic-gate# Returns: 21480Sstevel@tonic-gate# A string containing a <input type="checkbox"> field 21490Sstevel@tonic-gate#### 21500Sstevel@tonic-gate'checkbox' => <<'END_OF_FUNC', 21510Sstevel@tonic-gatesub checkbox { 21520Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 21530Sstevel@tonic-gate 2154*6287Sps156622 my($name,$checked,$value,$label,$labelattributes,$override,$tabindex,@other) = 2155*6287Sps156622 rearrange([NAME,[CHECKED,SELECTED,ON],VALUE,LABEL,LABELATTRIBUTES, 2156*6287Sps156622 [OVERRIDE,FORCE],TABINDEX],@p); 2157667Sps156622 21580Sstevel@tonic-gate $value = defined $value ? $value : 'on'; 21590Sstevel@tonic-gate 21600Sstevel@tonic-gate if (!$override && ($self->{'.fieldnames'}->{$name} || 21610Sstevel@tonic-gate defined $self->param($name))) { 21620Sstevel@tonic-gate $checked = grep($_ eq $value,$self->param($name)) ? $self->_checked(1) : ''; 21630Sstevel@tonic-gate } else { 21640Sstevel@tonic-gate $checked = $self->_checked($checked); 21650Sstevel@tonic-gate } 21660Sstevel@tonic-gate my($the_label) = defined $label ? $label : $name; 21670Sstevel@tonic-gate $name = $self->escapeHTML($name); 21680Sstevel@tonic-gate $value = $self->escapeHTML($value,1); 21690Sstevel@tonic-gate $the_label = $self->escapeHTML($the_label); 2170*6287Sps156622 my($other) = @other ? "@other " : ''; 2171667Sps156622 $tabindex = $self->element_tab($tabindex); 21720Sstevel@tonic-gate $self->register_parameter($name); 2173*6287Sps156622 return $XHTML ? CGI::label($labelattributes, 2174*6287Sps156622 qq{<input type="checkbox" name="$name" value="$value" $tabindex$checked$other/>$the_label}) 21750Sstevel@tonic-gate : qq{<input type="checkbox" name="$name" value="$value"$checked$other>$the_label}; 21760Sstevel@tonic-gate} 21770Sstevel@tonic-gateEND_OF_FUNC 21780Sstevel@tonic-gate 21790Sstevel@tonic-gate 21800Sstevel@tonic-gate 21810Sstevel@tonic-gate# Escape HTML -- used internally 21820Sstevel@tonic-gate'escapeHTML' => <<'END_OF_FUNC', 21830Sstevel@tonic-gatesub escapeHTML { 21840Sstevel@tonic-gate # hack to work around earlier hacks 21850Sstevel@tonic-gate push @_,$_[0] if @_==1 && $_[0] eq 'CGI'; 21860Sstevel@tonic-gate my ($self,$toencode,$newlinestoo) = CGI::self_or_default(@_); 21870Sstevel@tonic-gate return undef unless defined($toencode); 21880Sstevel@tonic-gate return $toencode if ref($self) && !$self->{'escape'}; 21890Sstevel@tonic-gate $toencode =~ s{&}{&}gso; 21900Sstevel@tonic-gate $toencode =~ s{<}{<}gso; 21910Sstevel@tonic-gate $toencode =~ s{>}{>}gso; 2192667Sps156622 if ($DTD_PUBLIC_IDENTIFIER =~ /[^X]HTML 3\.2/i) { 2193667Sps156622 # $quot; was accidentally omitted from the HTML 3.2 DTD -- see 2194667Sps156622 # <http://validator.w3.org/docs/errors.html#bad-entity> / 2195667Sps156622 # <http://lists.w3.org/Archives/Public/www-html/1997Mar/0003.html>. 2196667Sps156622 $toencode =~ s{"}{"}gso; 2197667Sps156622 } 2198667Sps156622 else { 2199667Sps156622 $toencode =~ s{"}{"}gso; 2200667Sps156622 } 22010Sstevel@tonic-gate my $latin = uc $self->{'.charset'} eq 'ISO-8859-1' || 22020Sstevel@tonic-gate uc $self->{'.charset'} eq 'WINDOWS-1252'; 22030Sstevel@tonic-gate if ($latin) { # bug in some browsers 22040Sstevel@tonic-gate $toencode =~ s{'}{'}gso; 22050Sstevel@tonic-gate $toencode =~ s{\x8b}{‹}gso; 22060Sstevel@tonic-gate $toencode =~ s{\x9b}{›}gso; 22070Sstevel@tonic-gate if (defined $newlinestoo && $newlinestoo) { 22080Sstevel@tonic-gate $toencode =~ s{\012}{ }gso; 22090Sstevel@tonic-gate $toencode =~ s{\015}{ }gso; 22100Sstevel@tonic-gate } 22110Sstevel@tonic-gate } 22120Sstevel@tonic-gate return $toencode; 22130Sstevel@tonic-gate} 22140Sstevel@tonic-gateEND_OF_FUNC 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate# unescape HTML -- used internally 22170Sstevel@tonic-gate'unescapeHTML' => <<'END_OF_FUNC', 22180Sstevel@tonic-gatesub unescapeHTML { 22190Sstevel@tonic-gate # hack to work around earlier hacks 22200Sstevel@tonic-gate push @_,$_[0] if @_==1 && $_[0] eq 'CGI'; 22210Sstevel@tonic-gate my ($self,$string) = CGI::self_or_default(@_); 22220Sstevel@tonic-gate return undef unless defined($string); 22230Sstevel@tonic-gate my $latin = defined $self->{'.charset'} ? $self->{'.charset'} =~ /^(ISO-8859-1|WINDOWS-1252)$/i 22240Sstevel@tonic-gate : 1; 22250Sstevel@tonic-gate # thanks to Randal Schwartz for the correct solution to this one 22260Sstevel@tonic-gate $string=~ s[&(.*?);]{ 22270Sstevel@tonic-gate local $_ = $1; 22280Sstevel@tonic-gate /^amp$/i ? "&" : 22290Sstevel@tonic-gate /^quot$/i ? '"' : 22300Sstevel@tonic-gate /^gt$/i ? ">" : 22310Sstevel@tonic-gate /^lt$/i ? "<" : 22320Sstevel@tonic-gate /^#(\d+)$/ && $latin ? chr($1) : 22330Sstevel@tonic-gate /^#x([0-9a-f]+)$/i && $latin ? chr(hex($1)) : 22340Sstevel@tonic-gate $_ 22350Sstevel@tonic-gate }gex; 22360Sstevel@tonic-gate return $string; 22370Sstevel@tonic-gate} 22380Sstevel@tonic-gateEND_OF_FUNC 22390Sstevel@tonic-gate 22400Sstevel@tonic-gate# Internal procedure - don't use 22410Sstevel@tonic-gate'_tableize' => <<'END_OF_FUNC', 22420Sstevel@tonic-gatesub _tableize { 22430Sstevel@tonic-gate my($rows,$columns,$rowheaders,$colheaders,@elements) = @_; 2244667Sps156622 my @rowheaders = $rowheaders ? @$rowheaders : (); 2245667Sps156622 my @colheaders = $colheaders ? @$colheaders : (); 22460Sstevel@tonic-gate my($result); 22470Sstevel@tonic-gate 22480Sstevel@tonic-gate if (defined($columns)) { 22490Sstevel@tonic-gate $rows = int(0.99 + @elements/$columns) unless defined($rows); 22500Sstevel@tonic-gate } 22510Sstevel@tonic-gate if (defined($rows)) { 22520Sstevel@tonic-gate $columns = int(0.99 + @elements/$rows) unless defined($columns); 22530Sstevel@tonic-gate } 2254667Sps156622 22550Sstevel@tonic-gate # rearrange into a pretty table 22560Sstevel@tonic-gate $result = "<table>"; 22570Sstevel@tonic-gate my($row,$column); 2258667Sps156622 unshift(@colheaders,'') if @colheaders && @rowheaders; 2259667Sps156622 $result .= "<tr>" if @colheaders; 2260667Sps156622 foreach (@colheaders) { 22610Sstevel@tonic-gate $result .= "<th>$_</th>"; 22620Sstevel@tonic-gate } 22630Sstevel@tonic-gate for ($row=0;$row<$rows;$row++) { 22640Sstevel@tonic-gate $result .= "<tr>"; 2265667Sps156622 $result .= "<th>$rowheaders[$row]</th>" if @rowheaders; 22660Sstevel@tonic-gate for ($column=0;$column<$columns;$column++) { 22670Sstevel@tonic-gate $result .= "<td>" . $elements[$column*$rows + $row] . "</td>" 22680Sstevel@tonic-gate if defined($elements[$column*$rows + $row]); 22690Sstevel@tonic-gate } 22700Sstevel@tonic-gate $result .= "</tr>"; 22710Sstevel@tonic-gate } 22720Sstevel@tonic-gate $result .= "</table>"; 22730Sstevel@tonic-gate return $result; 22740Sstevel@tonic-gate} 22750Sstevel@tonic-gateEND_OF_FUNC 22760Sstevel@tonic-gate 22770Sstevel@tonic-gate 22780Sstevel@tonic-gate#### Method: radio_group 22790Sstevel@tonic-gate# Create a list of logically-linked radio buttons. 22800Sstevel@tonic-gate# Parameters: 22810Sstevel@tonic-gate# $name -> Common name for all the buttons. 22820Sstevel@tonic-gate# $values -> A pointer to a regular array containing the 22830Sstevel@tonic-gate# values for each button in the group. 22840Sstevel@tonic-gate# $default -> (optional) Value of the button to turn on by default. Pass '-' 22850Sstevel@tonic-gate# to turn _nothing_ on. 22860Sstevel@tonic-gate# $linebreak -> (optional) Set to true to place linebreaks 22870Sstevel@tonic-gate# between the buttons. 22880Sstevel@tonic-gate# $labels -> (optional) 22890Sstevel@tonic-gate# A pointer to an associative array of labels to print next to each checkbox 22900Sstevel@tonic-gate# in the form $label{'value'}="Long explanatory label". 22910Sstevel@tonic-gate# Otherwise the provided values are used as the labels. 22920Sstevel@tonic-gate# Returns: 22930Sstevel@tonic-gate# An ARRAY containing a series of <input type="radio"> fields 22940Sstevel@tonic-gate#### 22950Sstevel@tonic-gate'radio_group' => <<'END_OF_FUNC', 22960Sstevel@tonic-gatesub radio_group { 22970Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 2298667Sps156622 $self->_box_group('radio',@p); 2299667Sps156622} 2300667Sps156622END_OF_FUNC 2301667Sps156622 2302667Sps156622#### Method: checkbox_group 2303667Sps156622# Create a list of logically-linked checkboxes. 2304667Sps156622# Parameters: 2305667Sps156622# $name -> Common name for all the check boxes 2306667Sps156622# $values -> A pointer to a regular array containing the 2307667Sps156622# values for each checkbox in the group. 2308667Sps156622# $defaults -> (optional) 2309667Sps156622# 1. If a pointer to a regular array of checkbox values, 2310667Sps156622# then this will be used to decide which 2311667Sps156622# checkboxes to turn on by default. 2312667Sps156622# 2. If a scalar, will be assumed to hold the 2313667Sps156622# value of a single checkbox in the group to turn on. 2314667Sps156622# $linebreak -> (optional) Set to true to place linebreaks 2315667Sps156622# between the buttons. 2316667Sps156622# $labels -> (optional) 2317667Sps156622# A pointer to an associative array of labels to print next to each checkbox 2318667Sps156622# in the form $label{'value'}="Long explanatory label". 2319667Sps156622# Otherwise the provided values are used as the labels. 2320667Sps156622# Returns: 2321667Sps156622# An ARRAY containing a series of <input type="checkbox"> fields 2322667Sps156622#### 2323667Sps156622 2324667Sps156622'checkbox_group' => <<'END_OF_FUNC', 2325667Sps156622sub checkbox_group { 2326667Sps156622 my($self,@p) = self_or_default(@_); 2327667Sps156622 $self->_box_group('checkbox',@p); 2328667Sps156622} 2329667Sps156622END_OF_FUNC 2330667Sps156622 2331667Sps156622'_box_group' => <<'END_OF_FUNC', 2332667Sps156622sub _box_group { 2333667Sps156622 my $self = shift; 2334667Sps156622 my $box_type = shift; 2335667Sps156622 2336*6287Sps156622 my($name,$values,$defaults,$linebreak,$labels,$labelattributes, 2337*6287Sps156622 $attributes,$rows,$columns,$rowheaders,$colheaders, 2338*6287Sps156622 $override,$nolabels,$tabindex,$disabled,@other) = 2339*6287Sps156622 rearrange([NAME,[VALUES,VALUE],[DEFAULT,DEFAULTS],LINEBREAK,LABELS,LABELATTRIBUTES, 2340*6287Sps156622 ATTRIBUTES,ROWS,[COLUMNS,COLS],[ROWHEADERS,ROWHEADER],[COLHEADERS,COLHEADER], 2341*6287Sps156622 [OVERRIDE,FORCE],NOLABELS,TABINDEX,DISABLED 2342*6287Sps156622 ],@_); 2343*6287Sps156622 2344*6287Sps156622 2345*6287Sps156622 my($result,$checked,@elements,@values); 2346*6287Sps156622 23470Sstevel@tonic-gate @values = $self->_set_values_and_labels($values,\$labels,$name); 2348667Sps156622 my %checked = $self->previous_or_default($name,$defaults,$override); 23490Sstevel@tonic-gate 23500Sstevel@tonic-gate # If no check array is specified, check the first by default 2351667Sps156622 $checked{$values[0]}++ if $box_type eq 'radio' && !%checked; 2352667Sps156622 23530Sstevel@tonic-gate $name=$self->escapeHTML($name); 23540Sstevel@tonic-gate 2355667Sps156622 my %tabs = (); 2356*6287Sps156622 if ($TABINDEX && $tabindex) { 2357667Sps156622 if (!ref $tabindex) { 2358667Sps156622 $self->element_tab($tabindex); 2359667Sps156622 } elsif (ref $tabindex eq 'ARRAY') { 2360667Sps156622 %tabs = map {$_=>$self->element_tab} @$tabindex; 2361667Sps156622 } elsif (ref $tabindex eq 'HASH') { 2362667Sps156622 %tabs = %$tabindex; 2363667Sps156622 } 2364667Sps156622 } 2365667Sps156622 %tabs = map {$_=>$self->element_tab} @values unless %tabs; 2366*6287Sps156622 my $other = @other ? "@other " : ''; 2367667Sps156622 my $radio_checked; 2368*6287Sps156622 2369*6287Sps156622 # for disabling groups of radio/checkbox buttons 2370*6287Sps156622 my %disabled; 2371*6287Sps156622 foreach (@{$disabled}) { 2372*6287Sps156622 $disabled{$_}=1; 2373*6287Sps156622 } 2374*6287Sps156622 23750Sstevel@tonic-gate foreach (@values) { 2376*6287Sps156622 my $disable=""; 2377*6287Sps156622 if ($disabled{$_}) { 2378*6287Sps156622 $disable="disabled='1'"; 2379*6287Sps156622 } 2380*6287Sps156622 2381667Sps156622 my $checkit = $self->_checked($box_type eq 'radio' ? ($checked{$_} && !$radio_checked++) 2382667Sps156622 : $checked{$_}); 23830Sstevel@tonic-gate my($break); 23840Sstevel@tonic-gate if ($linebreak) { 23850Sstevel@tonic-gate $break = $XHTML ? "<br />" : "<br>"; 23860Sstevel@tonic-gate } 23870Sstevel@tonic-gate else { 23880Sstevel@tonic-gate $break = ''; 23890Sstevel@tonic-gate } 23900Sstevel@tonic-gate my($label)=''; 23910Sstevel@tonic-gate unless (defined($nolabels) && $nolabels) { 23920Sstevel@tonic-gate $label = $_; 23930Sstevel@tonic-gate $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); 23940Sstevel@tonic-gate $label = $self->escapeHTML($label,1); 2395*6287Sps156622 $label = "<span style=\"color:gray\">$label</span>" if $disabled{$_}; 23960Sstevel@tonic-gate } 2397667Sps156622 my $attribs = $self->_set_attributes($_, $attributes); 2398*6287Sps156622 my $tab = $tabs{$_}; 23990Sstevel@tonic-gate $_=$self->escapeHTML($_); 2400*6287Sps156622 2401667Sps156622 if ($XHTML) { 2402667Sps156622 push @elements, 2403*6287Sps156622 CGI::label($labelattributes, 2404*6287Sps156622 qq(<input type="$box_type" name="$name" value="$_" $checkit$other$tab$attribs$disable/>$label)).${break}; 2405667Sps156622 } else { 2406*6287Sps156622 push(@elements,qq/<input type="$box_type" name="$name" value="$_"$checkit$other$tab$attribs$disable>${label}${break}/); 2407667Sps156622 } 24080Sstevel@tonic-gate } 24090Sstevel@tonic-gate $self->register_parameter($name); 2410667Sps156622 return wantarray ? @elements : "@elements" 24110Sstevel@tonic-gate unless defined($columns) || defined($rows); 24120Sstevel@tonic-gate return _tableize($rows,$columns,$rowheaders,$colheaders,@elements); 24130Sstevel@tonic-gate} 24140Sstevel@tonic-gateEND_OF_FUNC 24150Sstevel@tonic-gate 24160Sstevel@tonic-gate 24170Sstevel@tonic-gate#### Method: popup_menu 24180Sstevel@tonic-gate# Create a popup menu. 24190Sstevel@tonic-gate# Parameters: 24200Sstevel@tonic-gate# $name -> Name for all the menu 24210Sstevel@tonic-gate# $values -> A pointer to a regular array containing the 24220Sstevel@tonic-gate# text of each menu item. 24230Sstevel@tonic-gate# $default -> (optional) Default item to display 24240Sstevel@tonic-gate# $labels -> (optional) 24250Sstevel@tonic-gate# A pointer to an associative array of labels to print next to each checkbox 24260Sstevel@tonic-gate# in the form $label{'value'}="Long explanatory label". 24270Sstevel@tonic-gate# Otherwise the provided values are used as the labels. 24280Sstevel@tonic-gate# Returns: 24290Sstevel@tonic-gate# A string containing the definition of a popup menu. 24300Sstevel@tonic-gate#### 24310Sstevel@tonic-gate'popup_menu' => <<'END_OF_FUNC', 24320Sstevel@tonic-gatesub popup_menu { 24330Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 24340Sstevel@tonic-gate 2435667Sps156622 my($name,$values,$default,$labels,$attributes,$override,$tabindex,@other) = 24360Sstevel@tonic-gate rearrange([NAME,[VALUES,VALUE],[DEFAULT,DEFAULTS],LABELS, 2437667Sps156622 ATTRIBUTES,[OVERRIDE,FORCE],TABINDEX],@p); 24380Sstevel@tonic-gate my($result,$selected); 24390Sstevel@tonic-gate 24400Sstevel@tonic-gate if (!$override && defined($self->param($name))) { 24410Sstevel@tonic-gate $selected = $self->param($name); 24420Sstevel@tonic-gate } else { 24430Sstevel@tonic-gate $selected = $default; 24440Sstevel@tonic-gate } 24450Sstevel@tonic-gate $name=$self->escapeHTML($name); 24460Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 24470Sstevel@tonic-gate 24480Sstevel@tonic-gate my(@values); 24490Sstevel@tonic-gate @values = $self->_set_values_and_labels($values,\$labels,$name); 2450667Sps156622 $tabindex = $self->element_tab($tabindex); 2451*6287Sps156622 $result = qq/<select name="$name" $tabindex$other>\n/; 24520Sstevel@tonic-gate foreach (@values) { 24530Sstevel@tonic-gate if (/<optgroup/) { 24540Sstevel@tonic-gate foreach (split(/\n/)) { 24550Sstevel@tonic-gate my $selectit = $XHTML ? 'selected="selected"' : 'selected'; 24560Sstevel@tonic-gate s/(value="$selected")/$selectit $1/ if defined $selected; 24570Sstevel@tonic-gate $result .= "$_\n"; 24580Sstevel@tonic-gate } 24590Sstevel@tonic-gate } 24600Sstevel@tonic-gate else { 2461*6287Sps156622 my $attribs = $self->_set_attributes($_, $attributes); 2462*6287Sps156622 my($selectit) = defined($selected) ? $self->_selected($selected eq $_) : ''; 2463*6287Sps156622 my($label) = $_; 2464*6287Sps156622 $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); 2465*6287Sps156622 my($value) = $self->escapeHTML($_); 2466*6287Sps156622 $label=$self->escapeHTML($label,1); 2467*6287Sps156622 $result .= "<option${attribs} ${selectit}value=\"$value\">$label</option>\n"; 24680Sstevel@tonic-gate } 24690Sstevel@tonic-gate } 24700Sstevel@tonic-gate 24710Sstevel@tonic-gate $result .= "</select>"; 24720Sstevel@tonic-gate return $result; 24730Sstevel@tonic-gate} 24740Sstevel@tonic-gateEND_OF_FUNC 24750Sstevel@tonic-gate 24760Sstevel@tonic-gate 24770Sstevel@tonic-gate#### Method: optgroup 24780Sstevel@tonic-gate# Create a optgroup. 24790Sstevel@tonic-gate# Parameters: 24800Sstevel@tonic-gate# $name -> Label for the group 24810Sstevel@tonic-gate# $values -> A pointer to a regular array containing the 24820Sstevel@tonic-gate# values for each option line in the group. 24830Sstevel@tonic-gate# $labels -> (optional) 24840Sstevel@tonic-gate# A pointer to an associative array of labels to print next to each item 24850Sstevel@tonic-gate# in the form $label{'value'}="Long explanatory label". 24860Sstevel@tonic-gate# Otherwise the provided values are used as the labels. 24870Sstevel@tonic-gate# $labeled -> (optional) 24880Sstevel@tonic-gate# A true value indicates the value should be used as the label attribute 24890Sstevel@tonic-gate# in the option elements. 24900Sstevel@tonic-gate# The label attribute specifies the option label presented to the user. 24910Sstevel@tonic-gate# This defaults to the content of the <option> element, but the label 24920Sstevel@tonic-gate# attribute allows authors to more easily use optgroup without sacrificing 24930Sstevel@tonic-gate# compatibility with browsers that do not support option groups. 24940Sstevel@tonic-gate# $novals -> (optional) 24950Sstevel@tonic-gate# A true value indicates to suppress the val attribute in the option elements 24960Sstevel@tonic-gate# Returns: 24970Sstevel@tonic-gate# A string containing the definition of an option group. 24980Sstevel@tonic-gate#### 24990Sstevel@tonic-gate'optgroup' => <<'END_OF_FUNC', 25000Sstevel@tonic-gatesub optgroup { 25010Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 25020Sstevel@tonic-gate my($name,$values,$attributes,$labeled,$noval,$labels,@other) 25030Sstevel@tonic-gate = rearrange([NAME,[VALUES,VALUE],ATTRIBUTES,LABELED,NOVALS,LABELS],@p); 25040Sstevel@tonic-gate 25050Sstevel@tonic-gate my($result,@values); 25060Sstevel@tonic-gate @values = $self->_set_values_and_labels($values,\$labels,$name,$labeled,$novals); 25070Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 25080Sstevel@tonic-gate 25090Sstevel@tonic-gate $name=$self->escapeHTML($name); 25100Sstevel@tonic-gate $result = qq/<optgroup label="$name"$other>\n/; 25110Sstevel@tonic-gate foreach (@values) { 25120Sstevel@tonic-gate if (/<optgroup/) { 25130Sstevel@tonic-gate foreach (split(/\n/)) { 25140Sstevel@tonic-gate my $selectit = $XHTML ? 'selected="selected"' : 'selected'; 25150Sstevel@tonic-gate s/(value="$selected")/$selectit $1/ if defined $selected; 25160Sstevel@tonic-gate $result .= "$_\n"; 25170Sstevel@tonic-gate } 25180Sstevel@tonic-gate } 25190Sstevel@tonic-gate else { 25200Sstevel@tonic-gate my $attribs = $self->_set_attributes($_, $attributes); 25210Sstevel@tonic-gate my($label) = $_; 25220Sstevel@tonic-gate $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); 25230Sstevel@tonic-gate $label=$self->escapeHTML($label); 25240Sstevel@tonic-gate my($value)=$self->escapeHTML($_,1); 25250Sstevel@tonic-gate $result .= $labeled ? $novals ? "<option$attribs label=\"$value\">$label</option>\n" 25260Sstevel@tonic-gate : "<option$attribs label=\"$value\" value=\"$value\">$label</option>\n" 25270Sstevel@tonic-gate : $novals ? "<option$attribs>$label</option>\n" 25280Sstevel@tonic-gate : "<option$attribs value=\"$value\">$label</option>\n"; 25290Sstevel@tonic-gate } 25300Sstevel@tonic-gate } 25310Sstevel@tonic-gate $result .= "</optgroup>"; 25320Sstevel@tonic-gate return $result; 25330Sstevel@tonic-gate} 25340Sstevel@tonic-gateEND_OF_FUNC 25350Sstevel@tonic-gate 25360Sstevel@tonic-gate 25370Sstevel@tonic-gate#### Method: scrolling_list 25380Sstevel@tonic-gate# Create a scrolling list. 25390Sstevel@tonic-gate# Parameters: 25400Sstevel@tonic-gate# $name -> name for the list 25410Sstevel@tonic-gate# $values -> A pointer to a regular array containing the 25420Sstevel@tonic-gate# values for each option line in the list. 25430Sstevel@tonic-gate# $defaults -> (optional) 25440Sstevel@tonic-gate# 1. If a pointer to a regular array of options, 25450Sstevel@tonic-gate# then this will be used to decide which 25460Sstevel@tonic-gate# lines to turn on by default. 25470Sstevel@tonic-gate# 2. Otherwise holds the value of the single line to turn on. 25480Sstevel@tonic-gate# $size -> (optional) Size of the list. 25490Sstevel@tonic-gate# $multiple -> (optional) If set, allow multiple selections. 25500Sstevel@tonic-gate# $labels -> (optional) 25510Sstevel@tonic-gate# A pointer to an associative array of labels to print next to each checkbox 25520Sstevel@tonic-gate# in the form $label{'value'}="Long explanatory label". 25530Sstevel@tonic-gate# Otherwise the provided values are used as the labels. 25540Sstevel@tonic-gate# Returns: 25550Sstevel@tonic-gate# A string containing the definition of a scrolling list. 25560Sstevel@tonic-gate#### 25570Sstevel@tonic-gate'scrolling_list' => <<'END_OF_FUNC', 25580Sstevel@tonic-gatesub scrolling_list { 25590Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 2560667Sps156622 my($name,$values,$defaults,$size,$multiple,$labels,$attributes,$override,$tabindex,@other) 25610Sstevel@tonic-gate = rearrange([NAME,[VALUES,VALUE],[DEFAULTS,DEFAULT], 2562667Sps156622 SIZE,MULTIPLE,LABELS,ATTRIBUTES,[OVERRIDE,FORCE],TABINDEX],@p); 25630Sstevel@tonic-gate 25640Sstevel@tonic-gate my($result,@values); 25650Sstevel@tonic-gate @values = $self->_set_values_and_labels($values,\$labels,$name); 25660Sstevel@tonic-gate 25670Sstevel@tonic-gate $size = $size || scalar(@values); 25680Sstevel@tonic-gate 25690Sstevel@tonic-gate my(%selected) = $self->previous_or_default($name,$defaults,$override); 25700Sstevel@tonic-gate my($is_multiple) = $multiple ? qq/ multiple="multiple"/ : ''; 25710Sstevel@tonic-gate my($has_size) = $size ? qq/ size="$size"/: ''; 25720Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 25730Sstevel@tonic-gate 25740Sstevel@tonic-gate $name=$self->escapeHTML($name); 2575667Sps156622 $tabindex = $self->element_tab($tabindex); 2576*6287Sps156622 $result = qq/<select name="$name" $tabindex$has_size$is_multiple$other>\n/; 25770Sstevel@tonic-gate foreach (@values) { 25780Sstevel@tonic-gate my($selectit) = $self->_selected($selected{$_}); 25790Sstevel@tonic-gate my($label) = $_; 25800Sstevel@tonic-gate $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); 25810Sstevel@tonic-gate $label=$self->escapeHTML($label); 25820Sstevel@tonic-gate my($value)=$self->escapeHTML($_,1); 25830Sstevel@tonic-gate my $attribs = $self->_set_attributes($_, $attributes); 2584*6287Sps156622 $result .= "<option ${selectit}${attribs}value=\"$value\">$label</option>\n"; 25850Sstevel@tonic-gate } 25860Sstevel@tonic-gate $result .= "</select>"; 25870Sstevel@tonic-gate $self->register_parameter($name); 25880Sstevel@tonic-gate return $result; 25890Sstevel@tonic-gate} 25900Sstevel@tonic-gateEND_OF_FUNC 25910Sstevel@tonic-gate 25920Sstevel@tonic-gate 25930Sstevel@tonic-gate#### Method: hidden 25940Sstevel@tonic-gate# Parameters: 25950Sstevel@tonic-gate# $name -> Name of the hidden field 25960Sstevel@tonic-gate# @default -> (optional) Initial values of field (may be an array) 25970Sstevel@tonic-gate# or 25980Sstevel@tonic-gate# $default->[initial values of field] 25990Sstevel@tonic-gate# Returns: 26000Sstevel@tonic-gate# A string containing a <input type="hidden" name="name" value="value"> 26010Sstevel@tonic-gate#### 26020Sstevel@tonic-gate'hidden' => <<'END_OF_FUNC', 26030Sstevel@tonic-gatesub hidden { 26040Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 26050Sstevel@tonic-gate 26060Sstevel@tonic-gate # this is the one place where we departed from our standard 26070Sstevel@tonic-gate # calling scheme, so we have to special-case (darn) 26080Sstevel@tonic-gate my(@result,@value); 26090Sstevel@tonic-gate my($name,$default,$override,@other) = 26100Sstevel@tonic-gate rearrange([NAME,[DEFAULT,VALUE,VALUES],[OVERRIDE,FORCE]],@p); 26110Sstevel@tonic-gate 26120Sstevel@tonic-gate my $do_override = 0; 26130Sstevel@tonic-gate if ( ref($p[0]) || substr($p[0],0,1) eq '-') { 26140Sstevel@tonic-gate @value = ref($default) ? @{$default} : $default; 26150Sstevel@tonic-gate $do_override = $override; 26160Sstevel@tonic-gate } else { 26170Sstevel@tonic-gate foreach ($default,$override,@other) { 26180Sstevel@tonic-gate push(@value,$_) if defined($_); 26190Sstevel@tonic-gate } 26200Sstevel@tonic-gate } 26210Sstevel@tonic-gate 26220Sstevel@tonic-gate # use previous values if override is not set 26230Sstevel@tonic-gate my @prev = $self->param($name); 26240Sstevel@tonic-gate @value = @prev if !$do_override && @prev; 26250Sstevel@tonic-gate 26260Sstevel@tonic-gate $name=$self->escapeHTML($name); 26270Sstevel@tonic-gate foreach (@value) { 26280Sstevel@tonic-gate $_ = defined($_) ? $self->escapeHTML($_,1) : ''; 2629667Sps156622 push @result,$XHTML ? qq(<input type="hidden" name="$name" value="$_" @other />) 2630667Sps156622 : qq(<input type="hidden" name="$name" value="$_" @other>); 26310Sstevel@tonic-gate } 26320Sstevel@tonic-gate return wantarray ? @result : join('',@result); 26330Sstevel@tonic-gate} 26340Sstevel@tonic-gateEND_OF_FUNC 26350Sstevel@tonic-gate 26360Sstevel@tonic-gate 26370Sstevel@tonic-gate#### Method: image_button 26380Sstevel@tonic-gate# Parameters: 26390Sstevel@tonic-gate# $name -> Name of the button 26400Sstevel@tonic-gate# $src -> URL of the image source 26410Sstevel@tonic-gate# $align -> Alignment style (TOP, BOTTOM or MIDDLE) 26420Sstevel@tonic-gate# Returns: 26430Sstevel@tonic-gate# A string containing a <input type="image" name="name" src="url" align="alignment"> 26440Sstevel@tonic-gate#### 26450Sstevel@tonic-gate'image_button' => <<'END_OF_FUNC', 26460Sstevel@tonic-gatesub image_button { 26470Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 26480Sstevel@tonic-gate 26490Sstevel@tonic-gate my($name,$src,$alignment,@other) = 26500Sstevel@tonic-gate rearrange([NAME,SRC,ALIGN],@p); 26510Sstevel@tonic-gate 2652*6287Sps156622 my($align) = $alignment ? " align=\L\"$alignment\"" : ''; 26530Sstevel@tonic-gate my($other) = @other ? " @other" : ''; 26540Sstevel@tonic-gate $name=$self->escapeHTML($name); 26550Sstevel@tonic-gate return $XHTML ? qq(<input type="image" name="$name" src="$src"$align$other />) 26560Sstevel@tonic-gate : qq/<input type="image" name="$name" src="$src"$align$other>/; 26570Sstevel@tonic-gate} 26580Sstevel@tonic-gateEND_OF_FUNC 26590Sstevel@tonic-gate 26600Sstevel@tonic-gate 26610Sstevel@tonic-gate#### Method: self_url 26620Sstevel@tonic-gate# Returns a URL containing the current script and all its 26630Sstevel@tonic-gate# param/value pairs arranged as a query. You can use this 26640Sstevel@tonic-gate# to create a link that, when selected, will reinvoke the 26650Sstevel@tonic-gate# script with all its state information preserved. 26660Sstevel@tonic-gate#### 26670Sstevel@tonic-gate'self_url' => <<'END_OF_FUNC', 26680Sstevel@tonic-gatesub self_url { 26690Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 26700Sstevel@tonic-gate return $self->url('-path_info'=>1,'-query'=>1,'-full'=>1,@p); 26710Sstevel@tonic-gate} 26720Sstevel@tonic-gateEND_OF_FUNC 26730Sstevel@tonic-gate 26740Sstevel@tonic-gate 26750Sstevel@tonic-gate# This is provided as a synonym to self_url() for people unfortunate 26760Sstevel@tonic-gate# enough to have incorporated it into their programs already! 26770Sstevel@tonic-gate'state' => <<'END_OF_FUNC', 26780Sstevel@tonic-gatesub state { 26790Sstevel@tonic-gate &self_url; 26800Sstevel@tonic-gate} 26810Sstevel@tonic-gateEND_OF_FUNC 26820Sstevel@tonic-gate 26830Sstevel@tonic-gate 26840Sstevel@tonic-gate#### Method: url 26850Sstevel@tonic-gate# Like self_url, but doesn't return the query string part of 26860Sstevel@tonic-gate# the URL. 26870Sstevel@tonic-gate#### 26880Sstevel@tonic-gate'url' => <<'END_OF_FUNC', 26890Sstevel@tonic-gatesub url { 26900Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 2691*6287Sps156622 my ($relative,$absolute,$full,$path_info,$query,$base,$rewrite) = 2692*6287Sps156622 rearrange(['RELATIVE','ABSOLUTE','FULL',['PATH','PATH_INFO'],['QUERY','QUERY_STRING'],'BASE','REWRITE'],@p); 2693*6287Sps156622 my $url = ''; 26940Sstevel@tonic-gate $full++ if $base || !($relative || $absolute); 2695*6287Sps156622 $rewrite++ unless defined $rewrite; 2696*6287Sps156622 2697*6287Sps156622 my $path = $self->path_info; 2698*6287Sps156622 my $script_name = $self->script_name; 2699*6287Sps156622 my $request_uri = unescape($self->request_uri) || ''; 2700*6287Sps156622 my $query_str = $self->query_string; 2701*6287Sps156622 2702*6287Sps156622 my $rewrite_in_use = $request_uri && $request_uri !~ /^$script_name/; 2703*6287Sps156622 undef $path if $rewrite_in_use && $rewrite; # path not valid when rewriting active 2704*6287Sps156622 2705*6287Sps156622 my $uri = $rewrite && $request_uri ? $request_uri : $script_name; 2706*6287Sps156622 $uri =~ s/\?.*$//; # remove query string 2707*6287Sps156622 $uri =~ s/\Q$path\E$// if defined $path; # remove path 27080Sstevel@tonic-gate 27090Sstevel@tonic-gate if ($full) { 27100Sstevel@tonic-gate my $protocol = $self->protocol(); 27110Sstevel@tonic-gate $url = "$protocol://"; 2712*6287Sps156622 my $vh = http('x_forwarded_host') || http('host') || ''; 2713*6287Sps156622 $vh =~ s/\:\d+$//; # some clients add the port number (incorrectly). Get rid of it. 27140Sstevel@tonic-gate if ($vh) { 27150Sstevel@tonic-gate $url .= $vh; 27160Sstevel@tonic-gate } else { 27170Sstevel@tonic-gate $url .= server_name(); 27180Sstevel@tonic-gate } 2719*6287Sps156622 my $port = $self->server_port; 2720*6287Sps156622 $url .= ":" . $port 2721*6287Sps156622 unless (lc($protocol) eq 'http' && $port == 80) 2722*6287Sps156622 || (lc($protocol) eq 'https' && $port == 443); 27230Sstevel@tonic-gate return $url if $base; 2724*6287Sps156622 $url .= $uri; 27250Sstevel@tonic-gate } elsif ($relative) { 2726*6287Sps156622 ($url) = $uri =~ m!([^/]+)$!; 27270Sstevel@tonic-gate } elsif ($absolute) { 2728*6287Sps156622 $url = $uri; 27290Sstevel@tonic-gate } 27300Sstevel@tonic-gate 2731*6287Sps156622 $url .= $path if $path_info and defined $path; 2732*6287Sps156622 $url .= "?$query_str" if $query and $query_str ne ''; 2733*6287Sps156622 $url ||= ''; 27340Sstevel@tonic-gate $url =~ s/([^a-zA-Z0-9_.%;&?\/\\:+=~-])/sprintf("%%%02X",ord($1))/eg; 27350Sstevel@tonic-gate return $url; 27360Sstevel@tonic-gate} 27370Sstevel@tonic-gate 27380Sstevel@tonic-gateEND_OF_FUNC 27390Sstevel@tonic-gate 27400Sstevel@tonic-gate#### Method: cookie 27410Sstevel@tonic-gate# Set or read a cookie from the specified name. 27420Sstevel@tonic-gate# Cookie can then be passed to header(). 27430Sstevel@tonic-gate# Usual rules apply to the stickiness of -value. 27440Sstevel@tonic-gate# Parameters: 27450Sstevel@tonic-gate# -name -> name for this cookie (optional) 27460Sstevel@tonic-gate# -value -> value of this cookie (scalar, array or hash) 27470Sstevel@tonic-gate# -path -> paths for which this cookie is valid (optional) 27480Sstevel@tonic-gate# -domain -> internet domain in which this cookie is valid (optional) 27490Sstevel@tonic-gate# -secure -> if true, cookie only passed through secure channel (optional) 27500Sstevel@tonic-gate# -expires -> expiry date in format Wdy, DD-Mon-YYYY HH:MM:SS GMT (optional) 27510Sstevel@tonic-gate#### 27520Sstevel@tonic-gate'cookie' => <<'END_OF_FUNC', 27530Sstevel@tonic-gatesub cookie { 27540Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 2755*6287Sps156622 my($name,$value,$path,$domain,$secure,$expires,$httponly) = 2756*6287Sps156622 rearrange([NAME,[VALUE,VALUES],PATH,DOMAIN,SECURE,EXPIRES,HTTPONLY],@p); 27570Sstevel@tonic-gate 27580Sstevel@tonic-gate require CGI::Cookie; 27590Sstevel@tonic-gate 27600Sstevel@tonic-gate # if no value is supplied, then we retrieve the 27610Sstevel@tonic-gate # value of the cookie, if any. For efficiency, we cache the parsed 27620Sstevel@tonic-gate # cookies in our state variables. 27630Sstevel@tonic-gate unless ( defined($value) ) { 27640Sstevel@tonic-gate $self->{'.cookies'} = CGI::Cookie->fetch 27650Sstevel@tonic-gate unless $self->{'.cookies'}; 27660Sstevel@tonic-gate 27670Sstevel@tonic-gate # If no name is supplied, then retrieve the names of all our cookies. 27680Sstevel@tonic-gate return () unless $self->{'.cookies'}; 27690Sstevel@tonic-gate return keys %{$self->{'.cookies'}} unless $name; 27700Sstevel@tonic-gate return () unless $self->{'.cookies'}->{$name}; 27710Sstevel@tonic-gate return $self->{'.cookies'}->{$name}->value if defined($name) && $name ne ''; 27720Sstevel@tonic-gate } 27730Sstevel@tonic-gate 27740Sstevel@tonic-gate # If we get here, we're creating a new cookie 27750Sstevel@tonic-gate return undef unless defined($name) && $name ne ''; # this is an error 27760Sstevel@tonic-gate 27770Sstevel@tonic-gate my @param; 27780Sstevel@tonic-gate push(@param,'-name'=>$name); 27790Sstevel@tonic-gate push(@param,'-value'=>$value); 27800Sstevel@tonic-gate push(@param,'-domain'=>$domain) if $domain; 27810Sstevel@tonic-gate push(@param,'-path'=>$path) if $path; 27820Sstevel@tonic-gate push(@param,'-expires'=>$expires) if $expires; 27830Sstevel@tonic-gate push(@param,'-secure'=>$secure) if $secure; 2784*6287Sps156622 push(@param,'-httponly'=>$httponly) if $httponly; 27850Sstevel@tonic-gate 27860Sstevel@tonic-gate return new CGI::Cookie(@param); 27870Sstevel@tonic-gate} 27880Sstevel@tonic-gateEND_OF_FUNC 27890Sstevel@tonic-gate 27900Sstevel@tonic-gate'parse_keywordlist' => <<'END_OF_FUNC', 27910Sstevel@tonic-gatesub parse_keywordlist { 27920Sstevel@tonic-gate my($self,$tosplit) = @_; 27930Sstevel@tonic-gate $tosplit = unescape($tosplit); # unescape the keywords 27940Sstevel@tonic-gate $tosplit=~tr/+/ /; # pluses to spaces 27950Sstevel@tonic-gate my(@keywords) = split(/\s+/,$tosplit); 27960Sstevel@tonic-gate return @keywords; 27970Sstevel@tonic-gate} 27980Sstevel@tonic-gateEND_OF_FUNC 27990Sstevel@tonic-gate 28000Sstevel@tonic-gate'param_fetch' => <<'END_OF_FUNC', 28010Sstevel@tonic-gatesub param_fetch { 28020Sstevel@tonic-gate my($self,@p) = self_or_default(@_); 28030Sstevel@tonic-gate my($name) = rearrange([NAME],@p); 28040Sstevel@tonic-gate unless (exists($self->{$name})) { 28050Sstevel@tonic-gate $self->add_parameter($name); 28060Sstevel@tonic-gate $self->{$name} = []; 28070Sstevel@tonic-gate } 28080Sstevel@tonic-gate 28090Sstevel@tonic-gate return $self->{$name}; 28100Sstevel@tonic-gate} 28110Sstevel@tonic-gateEND_OF_FUNC 28120Sstevel@tonic-gate 28130Sstevel@tonic-gate############################################### 28140Sstevel@tonic-gate# OTHER INFORMATION PROVIDED BY THE ENVIRONMENT 28150Sstevel@tonic-gate############################################### 28160Sstevel@tonic-gate 28170Sstevel@tonic-gate#### Method: path_info 28180Sstevel@tonic-gate# Return the extra virtual path information provided 28190Sstevel@tonic-gate# after the URL (if any) 28200Sstevel@tonic-gate#### 28210Sstevel@tonic-gate'path_info' => <<'END_OF_FUNC', 28220Sstevel@tonic-gatesub path_info { 28230Sstevel@tonic-gate my ($self,$info) = self_or_default(@_); 28240Sstevel@tonic-gate if (defined($info)) { 28250Sstevel@tonic-gate $info = "/$info" if $info ne '' && substr($info,0,1) ne '/'; 28260Sstevel@tonic-gate $self->{'.path_info'} = $info; 28270Sstevel@tonic-gate } elsif (! defined($self->{'.path_info'}) ) { 2828667Sps156622 my (undef,$path_info) = $self->_name_and_path_from_env; 2829667Sps156622 $self->{'.path_info'} = $path_info || ''; 28300Sstevel@tonic-gate } 28310Sstevel@tonic-gate return $self->{'.path_info'}; 28320Sstevel@tonic-gate} 28330Sstevel@tonic-gateEND_OF_FUNC 28340Sstevel@tonic-gate 2835667Sps156622# WE USE THIS TO COMPENSATE FOR A BUG IN APACHE 2 PRESENT AT LEAST UP THROUGH 2.0.54 2836667Sps156622'_name_and_path_from_env' => <<'END_OF_FUNC', 2837667Sps156622sub _name_and_path_from_env { 2838667Sps156622 my $self = shift; 2839667Sps156622 my $raw_script_name = $ENV{SCRIPT_NAME} || ''; 2840667Sps156622 my $raw_path_info = $ENV{PATH_INFO} || ''; 2841*6287Sps156622 my $uri = unescape($self->request_uri) || ''; 2842*6287Sps156622 2843*6287Sps156622 my $protected = quotemeta($raw_path_info); 2844*6287Sps156622 $raw_script_name =~ s/$protected$//; 2845667Sps156622 2846667Sps156622 my @uri_double_slashes = $uri =~ m^(/{2,}?)^g; 2847667Sps156622 my @path_double_slashes = "$raw_script_name $raw_path_info" =~ m^(/{2,}?)^g; 2848667Sps156622 2849667Sps156622 my $apache_bug = @uri_double_slashes != @path_double_slashes; 2850667Sps156622 return ($raw_script_name,$raw_path_info) unless $apache_bug; 2851667Sps156622 2852*6287Sps156622 my $path_info_search = quotemeta($raw_path_info); 2853667Sps156622 $path_info_search =~ s!/!/+!g; 2854667Sps156622 if ($uri =~ m/^(.+)($path_info_search)/) { 2855667Sps156622 return ($1,$2); 2856667Sps156622 } else { 2857667Sps156622 return ($raw_script_name,$raw_path_info); 2858667Sps156622 } 2859667Sps156622} 2860667Sps156622END_OF_FUNC 2861667Sps156622 28620Sstevel@tonic-gate 28630Sstevel@tonic-gate#### Method: request_method 28640Sstevel@tonic-gate# Returns 'POST', 'GET', 'PUT' or 'HEAD' 28650Sstevel@tonic-gate#### 28660Sstevel@tonic-gate'request_method' => <<'END_OF_FUNC', 28670Sstevel@tonic-gatesub request_method { 28680Sstevel@tonic-gate return $ENV{'REQUEST_METHOD'}; 28690Sstevel@tonic-gate} 28700Sstevel@tonic-gateEND_OF_FUNC 28710Sstevel@tonic-gate 28720Sstevel@tonic-gate#### Method: content_type 28730Sstevel@tonic-gate# Returns the content_type string 28740Sstevel@tonic-gate#### 28750Sstevel@tonic-gate'content_type' => <<'END_OF_FUNC', 28760Sstevel@tonic-gatesub content_type { 28770Sstevel@tonic-gate return $ENV{'CONTENT_TYPE'}; 28780Sstevel@tonic-gate} 28790Sstevel@tonic-gateEND_OF_FUNC 28800Sstevel@tonic-gate 28810Sstevel@tonic-gate#### Method: path_translated 28820Sstevel@tonic-gate# Return the physical path information provided 28830Sstevel@tonic-gate# by the URL (if any) 28840Sstevel@tonic-gate#### 28850Sstevel@tonic-gate'path_translated' => <<'END_OF_FUNC', 28860Sstevel@tonic-gatesub path_translated { 28870Sstevel@tonic-gate return $ENV{'PATH_TRANSLATED'}; 28880Sstevel@tonic-gate} 28890Sstevel@tonic-gateEND_OF_FUNC 28900Sstevel@tonic-gate 28910Sstevel@tonic-gate 2892667Sps156622#### Method: request_uri 2893667Sps156622# Return the literal request URI 2894667Sps156622#### 2895667Sps156622'request_uri' => <<'END_OF_FUNC', 2896667Sps156622sub request_uri { 2897667Sps156622 return $ENV{'REQUEST_URI'}; 2898667Sps156622} 2899667Sps156622END_OF_FUNC 2900667Sps156622 2901667Sps156622 29020Sstevel@tonic-gate#### Method: query_string 29030Sstevel@tonic-gate# Synthesize a query string from our current 29040Sstevel@tonic-gate# parameters 29050Sstevel@tonic-gate#### 29060Sstevel@tonic-gate'query_string' => <<'END_OF_FUNC', 29070Sstevel@tonic-gatesub query_string { 29080Sstevel@tonic-gate my($self) = self_or_default(@_); 29090Sstevel@tonic-gate my($param,$value,@pairs); 29100Sstevel@tonic-gate foreach $param ($self->param) { 29110Sstevel@tonic-gate my($eparam) = escape($param); 29120Sstevel@tonic-gate foreach $value ($self->param($param)) { 29130Sstevel@tonic-gate $value = escape($value); 29140Sstevel@tonic-gate next unless defined $value; 29150Sstevel@tonic-gate push(@pairs,"$eparam=$value"); 29160Sstevel@tonic-gate } 29170Sstevel@tonic-gate } 29180Sstevel@tonic-gate foreach (keys %{$self->{'.fieldnames'}}) { 29190Sstevel@tonic-gate push(@pairs,".cgifields=".escape("$_")); 29200Sstevel@tonic-gate } 29210Sstevel@tonic-gate return join($USE_PARAM_SEMICOLONS ? ';' : '&',@pairs); 29220Sstevel@tonic-gate} 29230Sstevel@tonic-gateEND_OF_FUNC 29240Sstevel@tonic-gate 29250Sstevel@tonic-gate 29260Sstevel@tonic-gate#### Method: accept 29270Sstevel@tonic-gate# Without parameters, returns an array of the 29280Sstevel@tonic-gate# MIME types the browser accepts. 29290Sstevel@tonic-gate# With a single parameter equal to a MIME 29300Sstevel@tonic-gate# type, will return undef if the browser won't 29310Sstevel@tonic-gate# accept it, 1 if the browser accepts it but 29320Sstevel@tonic-gate# doesn't give a preference, or a floating point 29330Sstevel@tonic-gate# value between 0.0 and 1.0 if the browser 29340Sstevel@tonic-gate# declares a quantitative score for it. 29350Sstevel@tonic-gate# This handles MIME type globs correctly. 29360Sstevel@tonic-gate#### 29370Sstevel@tonic-gate'Accept' => <<'END_OF_FUNC', 29380Sstevel@tonic-gatesub Accept { 29390Sstevel@tonic-gate my($self,$search) = self_or_CGI(@_); 29400Sstevel@tonic-gate my(%prefs,$type,$pref,$pat); 29410Sstevel@tonic-gate 29420Sstevel@tonic-gate my(@accept) = split(',',$self->http('accept')); 29430Sstevel@tonic-gate 29440Sstevel@tonic-gate foreach (@accept) { 29450Sstevel@tonic-gate ($pref) = /q=(\d\.\d+|\d+)/; 29460Sstevel@tonic-gate ($type) = m#(\S+/[^;]+)#; 29470Sstevel@tonic-gate next unless $type; 29480Sstevel@tonic-gate $prefs{$type}=$pref || 1; 29490Sstevel@tonic-gate } 29500Sstevel@tonic-gate 29510Sstevel@tonic-gate return keys %prefs unless $search; 29520Sstevel@tonic-gate 29530Sstevel@tonic-gate # if a search type is provided, we may need to 29540Sstevel@tonic-gate # perform a pattern matching operation. 29550Sstevel@tonic-gate # The MIME types use a glob mechanism, which 29560Sstevel@tonic-gate # is easily translated into a perl pattern match 29570Sstevel@tonic-gate 29580Sstevel@tonic-gate # First return the preference for directly supported 29590Sstevel@tonic-gate # types: 29600Sstevel@tonic-gate return $prefs{$search} if $prefs{$search}; 29610Sstevel@tonic-gate 29620Sstevel@tonic-gate # Didn't get it, so try pattern matching. 29630Sstevel@tonic-gate foreach (keys %prefs) { 29640Sstevel@tonic-gate next unless /\*/; # not a pattern match 29650Sstevel@tonic-gate ($pat = $_) =~ s/([^\w*])/\\$1/g; # escape meta characters 29660Sstevel@tonic-gate $pat =~ s/\*/.*/g; # turn it into a pattern 29670Sstevel@tonic-gate return $prefs{$_} if $search=~/$pat/; 29680Sstevel@tonic-gate } 29690Sstevel@tonic-gate} 29700Sstevel@tonic-gateEND_OF_FUNC 29710Sstevel@tonic-gate 29720Sstevel@tonic-gate 29730Sstevel@tonic-gate#### Method: user_agent 29740Sstevel@tonic-gate# If called with no parameters, returns the user agent. 29750Sstevel@tonic-gate# If called with one parameter, does a pattern match (case 29760Sstevel@tonic-gate# insensitive) on the user agent. 29770Sstevel@tonic-gate#### 29780Sstevel@tonic-gate'user_agent' => <<'END_OF_FUNC', 29790Sstevel@tonic-gatesub user_agent { 29800Sstevel@tonic-gate my($self,$match)=self_or_CGI(@_); 29810Sstevel@tonic-gate return $self->http('user_agent') unless $match; 29820Sstevel@tonic-gate return $self->http('user_agent') =~ /$match/i; 29830Sstevel@tonic-gate} 29840Sstevel@tonic-gateEND_OF_FUNC 29850Sstevel@tonic-gate 29860Sstevel@tonic-gate 29870Sstevel@tonic-gate#### Method: raw_cookie 29880Sstevel@tonic-gate# Returns the magic cookies for the session. 29890Sstevel@tonic-gate# The cookies are not parsed or altered in any way, i.e. 29900Sstevel@tonic-gate# cookies are returned exactly as given in the HTTP 29910Sstevel@tonic-gate# headers. If a cookie name is given, only that cookie's 29920Sstevel@tonic-gate# value is returned, otherwise the entire raw cookie 29930Sstevel@tonic-gate# is returned. 29940Sstevel@tonic-gate#### 29950Sstevel@tonic-gate'raw_cookie' => <<'END_OF_FUNC', 29960Sstevel@tonic-gatesub raw_cookie { 29970Sstevel@tonic-gate my($self,$key) = self_or_CGI(@_); 29980Sstevel@tonic-gate 29990Sstevel@tonic-gate require CGI::Cookie; 30000Sstevel@tonic-gate 30010Sstevel@tonic-gate if (defined($key)) { 30020Sstevel@tonic-gate $self->{'.raw_cookies'} = CGI::Cookie->raw_fetch 30030Sstevel@tonic-gate unless $self->{'.raw_cookies'}; 30040Sstevel@tonic-gate 30050Sstevel@tonic-gate return () unless $self->{'.raw_cookies'}; 30060Sstevel@tonic-gate return () unless $self->{'.raw_cookies'}->{$key}; 30070Sstevel@tonic-gate return $self->{'.raw_cookies'}->{$key}; 30080Sstevel@tonic-gate } 30090Sstevel@tonic-gate return $self->http('cookie') || $ENV{'COOKIE'} || ''; 30100Sstevel@tonic-gate} 30110Sstevel@tonic-gateEND_OF_FUNC 30120Sstevel@tonic-gate 30130Sstevel@tonic-gate#### Method: virtual_host 30140Sstevel@tonic-gate# Return the name of the virtual_host, which 30150Sstevel@tonic-gate# is not always the same as the server 30160Sstevel@tonic-gate###### 30170Sstevel@tonic-gate'virtual_host' => <<'END_OF_FUNC', 30180Sstevel@tonic-gatesub virtual_host { 3019667Sps156622 my $vh = http('x_forwarded_host') || http('host') || server_name(); 30200Sstevel@tonic-gate $vh =~ s/:\d+$//; # get rid of port number 30210Sstevel@tonic-gate return $vh; 30220Sstevel@tonic-gate} 30230Sstevel@tonic-gateEND_OF_FUNC 30240Sstevel@tonic-gate 30250Sstevel@tonic-gate#### Method: remote_host 30260Sstevel@tonic-gate# Return the name of the remote host, or its IP 30270Sstevel@tonic-gate# address if unavailable. If this variable isn't 30280Sstevel@tonic-gate# defined, it returns "localhost" for debugging 30290Sstevel@tonic-gate# purposes. 30300Sstevel@tonic-gate#### 30310Sstevel@tonic-gate'remote_host' => <<'END_OF_FUNC', 30320Sstevel@tonic-gatesub remote_host { 30330Sstevel@tonic-gate return $ENV{'REMOTE_HOST'} || $ENV{'REMOTE_ADDR'} 30340Sstevel@tonic-gate || 'localhost'; 30350Sstevel@tonic-gate} 30360Sstevel@tonic-gateEND_OF_FUNC 30370Sstevel@tonic-gate 30380Sstevel@tonic-gate 30390Sstevel@tonic-gate#### Method: remote_addr 30400Sstevel@tonic-gate# Return the IP addr of the remote host. 30410Sstevel@tonic-gate#### 30420Sstevel@tonic-gate'remote_addr' => <<'END_OF_FUNC', 30430Sstevel@tonic-gatesub remote_addr { 30440Sstevel@tonic-gate return $ENV{'REMOTE_ADDR'} || '127.0.0.1'; 30450Sstevel@tonic-gate} 30460Sstevel@tonic-gateEND_OF_FUNC 30470Sstevel@tonic-gate 30480Sstevel@tonic-gate 30490Sstevel@tonic-gate#### Method: script_name 30500Sstevel@tonic-gate# Return the partial URL to this script for 30510Sstevel@tonic-gate# self-referencing scripts. Also see 30520Sstevel@tonic-gate# self_url(), which returns a URL with all state information 30530Sstevel@tonic-gate# preserved. 30540Sstevel@tonic-gate#### 30550Sstevel@tonic-gate'script_name' => <<'END_OF_FUNC', 30560Sstevel@tonic-gatesub script_name { 3057667Sps156622 my ($self,@p) = self_or_default(@_); 3058667Sps156622 if (@p) { 3059*6287Sps156622 $self->{'.script_name'} = shift @p; 3060667Sps156622 } elsif (!exists $self->{'.script_name'}) { 3061667Sps156622 my ($script_name,$path_info) = $self->_name_and_path_from_env(); 3062667Sps156622 $self->{'.script_name'} = $script_name; 3063667Sps156622 } 3064667Sps156622 return $self->{'.script_name'}; 30650Sstevel@tonic-gate} 30660Sstevel@tonic-gateEND_OF_FUNC 30670Sstevel@tonic-gate 30680Sstevel@tonic-gate 30690Sstevel@tonic-gate#### Method: referer 30700Sstevel@tonic-gate# Return the HTTP_REFERER: useful for generating 30710Sstevel@tonic-gate# a GO BACK button. 30720Sstevel@tonic-gate#### 30730Sstevel@tonic-gate'referer' => <<'END_OF_FUNC', 30740Sstevel@tonic-gatesub referer { 30750Sstevel@tonic-gate my($self) = self_or_CGI(@_); 30760Sstevel@tonic-gate return $self->http('referer'); 30770Sstevel@tonic-gate} 30780Sstevel@tonic-gateEND_OF_FUNC 30790Sstevel@tonic-gate 30800Sstevel@tonic-gate 30810Sstevel@tonic-gate#### Method: server_name 30820Sstevel@tonic-gate# Return the name of the server 30830Sstevel@tonic-gate#### 30840Sstevel@tonic-gate'server_name' => <<'END_OF_FUNC', 30850Sstevel@tonic-gatesub server_name { 30860Sstevel@tonic-gate return $ENV{'SERVER_NAME'} || 'localhost'; 30870Sstevel@tonic-gate} 30880Sstevel@tonic-gateEND_OF_FUNC 30890Sstevel@tonic-gate 30900Sstevel@tonic-gate#### Method: server_software 30910Sstevel@tonic-gate# Return the name of the server software 30920Sstevel@tonic-gate#### 30930Sstevel@tonic-gate'server_software' => <<'END_OF_FUNC', 30940Sstevel@tonic-gatesub server_software { 30950Sstevel@tonic-gate return $ENV{'SERVER_SOFTWARE'} || 'cmdline'; 30960Sstevel@tonic-gate} 30970Sstevel@tonic-gateEND_OF_FUNC 30980Sstevel@tonic-gate 30990Sstevel@tonic-gate#### Method: virtual_port 31000Sstevel@tonic-gate# Return the server port, taking virtual hosts into account 31010Sstevel@tonic-gate#### 31020Sstevel@tonic-gate'virtual_port' => <<'END_OF_FUNC', 31030Sstevel@tonic-gatesub virtual_port { 31040Sstevel@tonic-gate my($self) = self_or_default(@_); 3105667Sps156622 my $vh = $self->http('x_forwarded_host') || $self->http('host'); 3106*6287Sps156622 my $protocol = $self->protocol; 31070Sstevel@tonic-gate if ($vh) { 3108*6287Sps156622 return ($vh =~ /:(\d+)$/)[0] || ($protocol eq 'https' ? 443 : 80); 31090Sstevel@tonic-gate } else { 31100Sstevel@tonic-gate return $self->server_port(); 31110Sstevel@tonic-gate } 31120Sstevel@tonic-gate} 31130Sstevel@tonic-gateEND_OF_FUNC 31140Sstevel@tonic-gate 31150Sstevel@tonic-gate#### Method: server_port 31160Sstevel@tonic-gate# Return the tcp/ip port the server is running on 31170Sstevel@tonic-gate#### 31180Sstevel@tonic-gate'server_port' => <<'END_OF_FUNC', 31190Sstevel@tonic-gatesub server_port { 31200Sstevel@tonic-gate return $ENV{'SERVER_PORT'} || 80; # for debugging 31210Sstevel@tonic-gate} 31220Sstevel@tonic-gateEND_OF_FUNC 31230Sstevel@tonic-gate 31240Sstevel@tonic-gate#### Method: server_protocol 31250Sstevel@tonic-gate# Return the protocol (usually HTTP/1.0) 31260Sstevel@tonic-gate#### 31270Sstevel@tonic-gate'server_protocol' => <<'END_OF_FUNC', 31280Sstevel@tonic-gatesub server_protocol { 31290Sstevel@tonic-gate return $ENV{'SERVER_PROTOCOL'} || 'HTTP/1.0'; # for debugging 31300Sstevel@tonic-gate} 31310Sstevel@tonic-gateEND_OF_FUNC 31320Sstevel@tonic-gate 31330Sstevel@tonic-gate#### Method: http 31340Sstevel@tonic-gate# Return the value of an HTTP variable, or 31350Sstevel@tonic-gate# the list of variables if none provided 31360Sstevel@tonic-gate#### 31370Sstevel@tonic-gate'http' => <<'END_OF_FUNC', 31380Sstevel@tonic-gatesub http { 31390Sstevel@tonic-gate my ($self,$parameter) = self_or_CGI(@_); 31400Sstevel@tonic-gate return $ENV{$parameter} if $parameter=~/^HTTP/; 31410Sstevel@tonic-gate $parameter =~ tr/-/_/; 31420Sstevel@tonic-gate return $ENV{"HTTP_\U$parameter\E"} if $parameter; 31430Sstevel@tonic-gate my(@p); 31440Sstevel@tonic-gate foreach (keys %ENV) { 31450Sstevel@tonic-gate push(@p,$_) if /^HTTP/; 31460Sstevel@tonic-gate } 31470Sstevel@tonic-gate return @p; 31480Sstevel@tonic-gate} 31490Sstevel@tonic-gateEND_OF_FUNC 31500Sstevel@tonic-gate 31510Sstevel@tonic-gate#### Method: https 31520Sstevel@tonic-gate# Return the value of HTTPS 31530Sstevel@tonic-gate#### 31540Sstevel@tonic-gate'https' => <<'END_OF_FUNC', 31550Sstevel@tonic-gatesub https { 31560Sstevel@tonic-gate local($^W)=0; 31570Sstevel@tonic-gate my ($self,$parameter) = self_or_CGI(@_); 31580Sstevel@tonic-gate return $ENV{HTTPS} unless $parameter; 31590Sstevel@tonic-gate return $ENV{$parameter} if $parameter=~/^HTTPS/; 31600Sstevel@tonic-gate $parameter =~ tr/-/_/; 31610Sstevel@tonic-gate return $ENV{"HTTPS_\U$parameter\E"} if $parameter; 31620Sstevel@tonic-gate my(@p); 31630Sstevel@tonic-gate foreach (keys %ENV) { 31640Sstevel@tonic-gate push(@p,$_) if /^HTTPS/; 31650Sstevel@tonic-gate } 31660Sstevel@tonic-gate return @p; 31670Sstevel@tonic-gate} 31680Sstevel@tonic-gateEND_OF_FUNC 31690Sstevel@tonic-gate 31700Sstevel@tonic-gate#### Method: protocol 31710Sstevel@tonic-gate# Return the protocol (http or https currently) 31720Sstevel@tonic-gate#### 31730Sstevel@tonic-gate'protocol' => <<'END_OF_FUNC', 31740Sstevel@tonic-gatesub protocol { 31750Sstevel@tonic-gate local($^W)=0; 31760Sstevel@tonic-gate my $self = shift; 31770Sstevel@tonic-gate return 'https' if uc($self->https()) eq 'ON'; 31780Sstevel@tonic-gate return 'https' if $self->server_port == 443; 31790Sstevel@tonic-gate my $prot = $self->server_protocol; 31800Sstevel@tonic-gate my($protocol,$version) = split('/',$prot); 31810Sstevel@tonic-gate return "\L$protocol\E"; 31820Sstevel@tonic-gate} 31830Sstevel@tonic-gateEND_OF_FUNC 31840Sstevel@tonic-gate 31850Sstevel@tonic-gate#### Method: remote_ident 31860Sstevel@tonic-gate# Return the identity of the remote user 31870Sstevel@tonic-gate# (but only if his host is running identd) 31880Sstevel@tonic-gate#### 31890Sstevel@tonic-gate'remote_ident' => <<'END_OF_FUNC', 31900Sstevel@tonic-gatesub remote_ident { 31910Sstevel@tonic-gate return $ENV{'REMOTE_IDENT'}; 31920Sstevel@tonic-gate} 31930Sstevel@tonic-gateEND_OF_FUNC 31940Sstevel@tonic-gate 31950Sstevel@tonic-gate 31960Sstevel@tonic-gate#### Method: auth_type 31970Sstevel@tonic-gate# Return the type of use verification/authorization in use, if any. 31980Sstevel@tonic-gate#### 31990Sstevel@tonic-gate'auth_type' => <<'END_OF_FUNC', 32000Sstevel@tonic-gatesub auth_type { 32010Sstevel@tonic-gate return $ENV{'AUTH_TYPE'}; 32020Sstevel@tonic-gate} 32030Sstevel@tonic-gateEND_OF_FUNC 32040Sstevel@tonic-gate 32050Sstevel@tonic-gate 32060Sstevel@tonic-gate#### Method: remote_user 32070Sstevel@tonic-gate# Return the authorization name used for user 32080Sstevel@tonic-gate# verification. 32090Sstevel@tonic-gate#### 32100Sstevel@tonic-gate'remote_user' => <<'END_OF_FUNC', 32110Sstevel@tonic-gatesub remote_user { 32120Sstevel@tonic-gate return $ENV{'REMOTE_USER'}; 32130Sstevel@tonic-gate} 32140Sstevel@tonic-gateEND_OF_FUNC 32150Sstevel@tonic-gate 32160Sstevel@tonic-gate 32170Sstevel@tonic-gate#### Method: user_name 32180Sstevel@tonic-gate# Try to return the remote user's name by hook or by 32190Sstevel@tonic-gate# crook 32200Sstevel@tonic-gate#### 32210Sstevel@tonic-gate'user_name' => <<'END_OF_FUNC', 32220Sstevel@tonic-gatesub user_name { 32230Sstevel@tonic-gate my ($self) = self_or_CGI(@_); 32240Sstevel@tonic-gate return $self->http('from') || $ENV{'REMOTE_IDENT'} || $ENV{'REMOTE_USER'}; 32250Sstevel@tonic-gate} 32260Sstevel@tonic-gateEND_OF_FUNC 32270Sstevel@tonic-gate 32280Sstevel@tonic-gate#### Method: nosticky 32290Sstevel@tonic-gate# Set or return the NOSTICKY global flag 32300Sstevel@tonic-gate#### 32310Sstevel@tonic-gate'nosticky' => <<'END_OF_FUNC', 32320Sstevel@tonic-gatesub nosticky { 32330Sstevel@tonic-gate my ($self,$param) = self_or_CGI(@_); 32340Sstevel@tonic-gate $CGI::NOSTICKY = $param if defined($param); 32350Sstevel@tonic-gate return $CGI::NOSTICKY; 32360Sstevel@tonic-gate} 32370Sstevel@tonic-gateEND_OF_FUNC 32380Sstevel@tonic-gate 32390Sstevel@tonic-gate#### Method: nph 32400Sstevel@tonic-gate# Set or return the NPH global flag 32410Sstevel@tonic-gate#### 32420Sstevel@tonic-gate'nph' => <<'END_OF_FUNC', 32430Sstevel@tonic-gatesub nph { 32440Sstevel@tonic-gate my ($self,$param) = self_or_CGI(@_); 32450Sstevel@tonic-gate $CGI::NPH = $param if defined($param); 32460Sstevel@tonic-gate return $CGI::NPH; 32470Sstevel@tonic-gate} 32480Sstevel@tonic-gateEND_OF_FUNC 32490Sstevel@tonic-gate 32500Sstevel@tonic-gate#### Method: private_tempfiles 32510Sstevel@tonic-gate# Set or return the private_tempfiles global flag 32520Sstevel@tonic-gate#### 32530Sstevel@tonic-gate'private_tempfiles' => <<'END_OF_FUNC', 32540Sstevel@tonic-gatesub private_tempfiles { 32550Sstevel@tonic-gate my ($self,$param) = self_or_CGI(@_); 32560Sstevel@tonic-gate $CGI::PRIVATE_TEMPFILES = $param if defined($param); 32570Sstevel@tonic-gate return $CGI::PRIVATE_TEMPFILES; 32580Sstevel@tonic-gate} 32590Sstevel@tonic-gateEND_OF_FUNC 32600Sstevel@tonic-gate#### Method: close_upload_files 32610Sstevel@tonic-gate# Set or return the close_upload_files global flag 32620Sstevel@tonic-gate#### 32630Sstevel@tonic-gate'close_upload_files' => <<'END_OF_FUNC', 32640Sstevel@tonic-gatesub close_upload_files { 32650Sstevel@tonic-gate my ($self,$param) = self_or_CGI(@_); 32660Sstevel@tonic-gate $CGI::CLOSE_UPLOAD_FILES = $param if defined($param); 32670Sstevel@tonic-gate return $CGI::CLOSE_UPLOAD_FILES; 32680Sstevel@tonic-gate} 32690Sstevel@tonic-gateEND_OF_FUNC 32700Sstevel@tonic-gate 32710Sstevel@tonic-gate 32720Sstevel@tonic-gate#### Method: default_dtd 32730Sstevel@tonic-gate# Set or return the default_dtd global 32740Sstevel@tonic-gate#### 32750Sstevel@tonic-gate'default_dtd' => <<'END_OF_FUNC', 32760Sstevel@tonic-gatesub default_dtd { 32770Sstevel@tonic-gate my ($self,$param,$param2) = self_or_CGI(@_); 32780Sstevel@tonic-gate if (defined $param2 && defined $param) { 32790Sstevel@tonic-gate $CGI::DEFAULT_DTD = [ $param, $param2 ]; 32800Sstevel@tonic-gate } elsif (defined $param) { 32810Sstevel@tonic-gate $CGI::DEFAULT_DTD = $param; 32820Sstevel@tonic-gate } 32830Sstevel@tonic-gate return $CGI::DEFAULT_DTD; 32840Sstevel@tonic-gate} 32850Sstevel@tonic-gateEND_OF_FUNC 32860Sstevel@tonic-gate 32870Sstevel@tonic-gate# -------------- really private subroutines ----------------- 32880Sstevel@tonic-gate'previous_or_default' => <<'END_OF_FUNC', 32890Sstevel@tonic-gatesub previous_or_default { 32900Sstevel@tonic-gate my($self,$name,$defaults,$override) = @_; 32910Sstevel@tonic-gate my(%selected); 32920Sstevel@tonic-gate 32930Sstevel@tonic-gate if (!$override && ($self->{'.fieldnames'}->{$name} || 32940Sstevel@tonic-gate defined($self->param($name)) ) ) { 32950Sstevel@tonic-gate grep($selected{$_}++,$self->param($name)); 32960Sstevel@tonic-gate } elsif (defined($defaults) && ref($defaults) && 32970Sstevel@tonic-gate (ref($defaults) eq 'ARRAY')) { 32980Sstevel@tonic-gate grep($selected{$_}++,@{$defaults}); 32990Sstevel@tonic-gate } else { 33000Sstevel@tonic-gate $selected{$defaults}++ if defined($defaults); 33010Sstevel@tonic-gate } 33020Sstevel@tonic-gate 33030Sstevel@tonic-gate return %selected; 33040Sstevel@tonic-gate} 33050Sstevel@tonic-gateEND_OF_FUNC 33060Sstevel@tonic-gate 33070Sstevel@tonic-gate'register_parameter' => <<'END_OF_FUNC', 33080Sstevel@tonic-gatesub register_parameter { 33090Sstevel@tonic-gate my($self,$param) = @_; 33100Sstevel@tonic-gate $self->{'.parametersToAdd'}->{$param}++; 33110Sstevel@tonic-gate} 33120Sstevel@tonic-gateEND_OF_FUNC 33130Sstevel@tonic-gate 33140Sstevel@tonic-gate'get_fields' => <<'END_OF_FUNC', 33150Sstevel@tonic-gatesub get_fields { 33160Sstevel@tonic-gate my($self) = @_; 33170Sstevel@tonic-gate return $self->CGI::hidden('-name'=>'.cgifields', 33180Sstevel@tonic-gate '-values'=>[keys %{$self->{'.parametersToAdd'}}], 33190Sstevel@tonic-gate '-override'=>1); 33200Sstevel@tonic-gate} 33210Sstevel@tonic-gateEND_OF_FUNC 33220Sstevel@tonic-gate 33230Sstevel@tonic-gate'read_from_cmdline' => <<'END_OF_FUNC', 33240Sstevel@tonic-gatesub read_from_cmdline { 33250Sstevel@tonic-gate my($input,@words); 33260Sstevel@tonic-gate my($query_string); 33270Sstevel@tonic-gate my($subpath); 33280Sstevel@tonic-gate if ($DEBUG && @ARGV) { 33290Sstevel@tonic-gate @words = @ARGV; 33300Sstevel@tonic-gate } elsif ($DEBUG > 1) { 33310Sstevel@tonic-gate require "shellwords.pl"; 33320Sstevel@tonic-gate print STDERR "(offline mode: enter name=value pairs on standard input; press ^D or ^Z when done)\n"; 33330Sstevel@tonic-gate chomp(@lines = <STDIN>); # remove newlines 33340Sstevel@tonic-gate $input = join(" ",@lines); 33350Sstevel@tonic-gate @words = &shellwords($input); 33360Sstevel@tonic-gate } 33370Sstevel@tonic-gate foreach (@words) { 33380Sstevel@tonic-gate s/\\=/%3D/g; 33390Sstevel@tonic-gate s/\\&/%26/g; 33400Sstevel@tonic-gate } 33410Sstevel@tonic-gate 33420Sstevel@tonic-gate if ("@words"=~/=/) { 33430Sstevel@tonic-gate $query_string = join('&',@words); 33440Sstevel@tonic-gate } else { 33450Sstevel@tonic-gate $query_string = join('+',@words); 33460Sstevel@tonic-gate } 33470Sstevel@tonic-gate if ($query_string =~ /^(.*?)\?(.*)$/) 33480Sstevel@tonic-gate { 33490Sstevel@tonic-gate $query_string = $2; 33500Sstevel@tonic-gate $subpath = $1; 33510Sstevel@tonic-gate } 33520Sstevel@tonic-gate return { 'query_string' => $query_string, 'subpath' => $subpath }; 33530Sstevel@tonic-gate} 33540Sstevel@tonic-gateEND_OF_FUNC 33550Sstevel@tonic-gate 33560Sstevel@tonic-gate##### 33570Sstevel@tonic-gate# subroutine: read_multipart 33580Sstevel@tonic-gate# 33590Sstevel@tonic-gate# Read multipart data and store it into our parameters. 33600Sstevel@tonic-gate# An interesting feature is that if any of the parts is a file, we 33610Sstevel@tonic-gate# create a temporary file and open up a filehandle on it so that the 33620Sstevel@tonic-gate# caller can read from it if necessary. 33630Sstevel@tonic-gate##### 33640Sstevel@tonic-gate'read_multipart' => <<'END_OF_FUNC', 33650Sstevel@tonic-gatesub read_multipart { 33660Sstevel@tonic-gate my($self,$boundary,$length) = @_; 33670Sstevel@tonic-gate my($buffer) = $self->new_MultipartBuffer($boundary,$length); 33680Sstevel@tonic-gate return unless $buffer; 33690Sstevel@tonic-gate my(%header,$body); 33700Sstevel@tonic-gate my $filenumber = 0; 33710Sstevel@tonic-gate while (!$buffer->eof) { 33720Sstevel@tonic-gate %header = $buffer->readHeader; 33730Sstevel@tonic-gate 33740Sstevel@tonic-gate unless (%header) { 33750Sstevel@tonic-gate $self->cgi_error("400 Bad request (malformed multipart POST)"); 33760Sstevel@tonic-gate return; 33770Sstevel@tonic-gate } 33780Sstevel@tonic-gate 3379*6287Sps156622 my($param)= $header{'Content-Disposition'}=~/ name="([^"]*)"/; 33800Sstevel@tonic-gate $param .= $TAINTED; 33810Sstevel@tonic-gate 33820Sstevel@tonic-gate # Bug: Netscape doesn't escape quotation marks in file names!!! 3383*6287Sps156622 my($filename) = $header{'Content-Disposition'}=~/ filename="([^"]*)"/; 33840Sstevel@tonic-gate # Test for Opera's multiple upload feature 33850Sstevel@tonic-gate my($multipart) = ( defined( $header{'Content-Type'} ) && 33860Sstevel@tonic-gate $header{'Content-Type'} =~ /multipart\/mixed/ ) ? 33870Sstevel@tonic-gate 1 : 0; 33880Sstevel@tonic-gate 33890Sstevel@tonic-gate # add this parameter to our list 33900Sstevel@tonic-gate $self->add_parameter($param); 33910Sstevel@tonic-gate 33920Sstevel@tonic-gate # If no filename specified, then just read the data and assign it 33930Sstevel@tonic-gate # to our parameter list. 33940Sstevel@tonic-gate if ( ( !defined($filename) || $filename eq '' ) && !$multipart ) { 33950Sstevel@tonic-gate my($value) = $buffer->readBody; 33960Sstevel@tonic-gate $value .= $TAINTED; 33970Sstevel@tonic-gate push(@{$self->{$param}},$value); 33980Sstevel@tonic-gate next; 33990Sstevel@tonic-gate } 34000Sstevel@tonic-gate 34010Sstevel@tonic-gate my ($tmpfile,$tmp,$filehandle); 34020Sstevel@tonic-gate UPLOADS: { 34030Sstevel@tonic-gate # If we get here, then we are dealing with a potentially large 34040Sstevel@tonic-gate # uploaded form. Save the data to a temporary file, then open 34050Sstevel@tonic-gate # the file for reading. 34060Sstevel@tonic-gate 34070Sstevel@tonic-gate # skip the file if uploads disabled 34080Sstevel@tonic-gate if ($DISABLE_UPLOADS) { 34090Sstevel@tonic-gate while (defined($data = $buffer->read)) { } 34100Sstevel@tonic-gate last UPLOADS; 34110Sstevel@tonic-gate } 34120Sstevel@tonic-gate 34130Sstevel@tonic-gate # set the filename to some recognizable value 34140Sstevel@tonic-gate if ( ( !defined($filename) || $filename eq '' ) && $multipart ) { 34150Sstevel@tonic-gate $filename = "multipart/mixed"; 34160Sstevel@tonic-gate } 34170Sstevel@tonic-gate 34180Sstevel@tonic-gate # choose a relatively unpredictable tmpfile sequence number 3419667Sps156622 my $seqno = unpack("%16C*",join('',localtime,grep {defined $_} values %ENV)); 34200Sstevel@tonic-gate for (my $cnt=10;$cnt>0;$cnt--) { 34210Sstevel@tonic-gate next unless $tmpfile = new CGITempFile($seqno); 34220Sstevel@tonic-gate $tmp = $tmpfile->as_string; 34230Sstevel@tonic-gate last if defined($filehandle = Fh->new($filename,$tmp,$PRIVATE_TEMPFILES)); 34240Sstevel@tonic-gate $seqno += int rand(100); 34250Sstevel@tonic-gate } 34260Sstevel@tonic-gate die "CGI open of tmpfile: $!\n" unless defined $filehandle; 34270Sstevel@tonic-gate $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode 34280Sstevel@tonic-gate && defined fileno($filehandle); 34290Sstevel@tonic-gate 34300Sstevel@tonic-gate # if this is an multipart/mixed attachment, save the header 34310Sstevel@tonic-gate # together with the body for later parsing with an external 34320Sstevel@tonic-gate # MIME parser module 34330Sstevel@tonic-gate if ( $multipart ) { 34340Sstevel@tonic-gate foreach ( keys %header ) { 34350Sstevel@tonic-gate print $filehandle "$_: $header{$_}${CRLF}"; 34360Sstevel@tonic-gate } 34370Sstevel@tonic-gate print $filehandle "${CRLF}"; 34380Sstevel@tonic-gate } 34390Sstevel@tonic-gate 34400Sstevel@tonic-gate my ($data); 34410Sstevel@tonic-gate local($\) = ''; 3442*6287Sps156622 my $totalbytes = 0; 34430Sstevel@tonic-gate while (defined($data = $buffer->read)) { 34440Sstevel@tonic-gate if (defined $self->{'.upload_hook'}) 34450Sstevel@tonic-gate { 34460Sstevel@tonic-gate $totalbytes += length($data); 34470Sstevel@tonic-gate &{$self->{'.upload_hook'}}($filename ,$data, $totalbytes, $self->{'.upload_data'}); 34480Sstevel@tonic-gate } 3449*6287Sps156622 print $filehandle $data if ($self->{'use_tempfile'}); 34500Sstevel@tonic-gate } 34510Sstevel@tonic-gate 34520Sstevel@tonic-gate # back up to beginning of file 34530Sstevel@tonic-gate seek($filehandle,0,0); 34540Sstevel@tonic-gate 34550Sstevel@tonic-gate ## Close the filehandle if requested this allows a multipart MIME 34560Sstevel@tonic-gate ## upload to contain many files, and we won't die due to too many 34570Sstevel@tonic-gate ## open file handles. The user can access the files using the hash 34580Sstevel@tonic-gate ## below. 34590Sstevel@tonic-gate close $filehandle if $CLOSE_UPLOAD_FILES; 34600Sstevel@tonic-gate $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode; 34610Sstevel@tonic-gate 34620Sstevel@tonic-gate # Save some information about the uploaded file where we can get 34630Sstevel@tonic-gate # at it later. 3464*6287Sps156622 # Use the typeglob as the key, as this is guaranteed to be 3465*6287Sps156622 # unique for each filehandle. Don't use the file descriptor as 3466*6287Sps156622 # this will be re-used for each filehandle if the 3467*6287Sps156622 # close_upload_files feature is used. 3468*6287Sps156622 $self->{'.tmpfiles'}->{$$filehandle}= { 34690Sstevel@tonic-gate hndl => $filehandle, 34700Sstevel@tonic-gate name => $tmpfile, 34710Sstevel@tonic-gate info => {%header}, 34720Sstevel@tonic-gate }; 34730Sstevel@tonic-gate push(@{$self->{$param}},$filehandle); 34740Sstevel@tonic-gate } 34750Sstevel@tonic-gate } 34760Sstevel@tonic-gate} 34770Sstevel@tonic-gateEND_OF_FUNC 34780Sstevel@tonic-gate 3479*6287Sps156622##### 3480*6287Sps156622# subroutine: read_multipart_related 3481*6287Sps156622# 3482*6287Sps156622# Read multipart/related data and store it into our parameters. The 3483*6287Sps156622# first parameter sets the start of the data. The part identified by 3484*6287Sps156622# this Content-ID will not be stored as a file upload, but will be 3485*6287Sps156622# returned by this method. All other parts will be available as file 3486*6287Sps156622# uploads accessible by their Content-ID 3487*6287Sps156622##### 3488*6287Sps156622'read_multipart_related' => <<'END_OF_FUNC', 3489*6287Sps156622sub read_multipart_related { 3490*6287Sps156622 my($self,$start,$boundary,$length) = @_; 3491*6287Sps156622 my($buffer) = $self->new_MultipartBuffer($boundary,$length); 3492*6287Sps156622 return unless $buffer; 3493*6287Sps156622 my(%header,$body); 3494*6287Sps156622 my $filenumber = 0; 3495*6287Sps156622 my $returnvalue; 3496*6287Sps156622 while (!$buffer->eof) { 3497*6287Sps156622 %header = $buffer->readHeader; 3498*6287Sps156622 3499*6287Sps156622 unless (%header) { 3500*6287Sps156622 $self->cgi_error("400 Bad request (malformed multipart POST)"); 3501*6287Sps156622 return; 3502*6287Sps156622 } 3503*6287Sps156622 3504*6287Sps156622 my($param) = $header{'Content-ID'}=~/\<([^\>]*)\>/; 3505*6287Sps156622 $param .= $TAINTED; 3506*6287Sps156622 3507*6287Sps156622 # If this is the start part, then just read the data and assign it 3508*6287Sps156622 # to our return variable. 3509*6287Sps156622 if ( $param eq $start ) { 3510*6287Sps156622 $returnvalue = $buffer->readBody; 3511*6287Sps156622 $returnvalue .= $TAINTED; 3512*6287Sps156622 next; 3513*6287Sps156622 } 3514*6287Sps156622 3515*6287Sps156622 # add this parameter to our list 3516*6287Sps156622 $self->add_parameter($param); 3517*6287Sps156622 3518*6287Sps156622 my ($tmpfile,$tmp,$filehandle); 3519*6287Sps156622 UPLOADS: { 3520*6287Sps156622 # If we get here, then we are dealing with a potentially large 3521*6287Sps156622 # uploaded form. Save the data to a temporary file, then open 3522*6287Sps156622 # the file for reading. 3523*6287Sps156622 3524*6287Sps156622 # skip the file if uploads disabled 3525*6287Sps156622 if ($DISABLE_UPLOADS) { 3526*6287Sps156622 while (defined($data = $buffer->read)) { } 3527*6287Sps156622 last UPLOADS; 3528*6287Sps156622 } 3529*6287Sps156622 3530*6287Sps156622 # choose a relatively unpredictable tmpfile sequence number 3531*6287Sps156622 my $seqno = unpack("%16C*",join('',localtime,grep {defined $_} values %ENV)); 3532*6287Sps156622 for (my $cnt=10;$cnt>0;$cnt--) { 3533*6287Sps156622 next unless $tmpfile = new CGITempFile($seqno); 3534*6287Sps156622 $tmp = $tmpfile->as_string; 3535*6287Sps156622 last if defined($filehandle = Fh->new($param,$tmp,$PRIVATE_TEMPFILES)); 3536*6287Sps156622 $seqno += int rand(100); 3537*6287Sps156622 } 3538*6287Sps156622 die "CGI open of tmpfile: $!\n" unless defined $filehandle; 3539*6287Sps156622 $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode 3540*6287Sps156622 && defined fileno($filehandle); 3541*6287Sps156622 3542*6287Sps156622 my ($data); 3543*6287Sps156622 local($\) = ''; 3544*6287Sps156622 my $totalbytes; 3545*6287Sps156622 while (defined($data = $buffer->read)) { 3546*6287Sps156622 if (defined $self->{'.upload_hook'}) 3547*6287Sps156622 { 3548*6287Sps156622 $totalbytes += length($data); 3549*6287Sps156622 &{$self->{'.upload_hook'}}($param ,$data, $totalbytes, $self->{'.upload_data'}); 3550*6287Sps156622 } 3551*6287Sps156622 print $filehandle $data if ($self->{'use_tempfile'}); 3552*6287Sps156622 } 3553*6287Sps156622 3554*6287Sps156622 # back up to beginning of file 3555*6287Sps156622 seek($filehandle,0,0); 3556*6287Sps156622 3557*6287Sps156622 ## Close the filehandle if requested this allows a multipart MIME 3558*6287Sps156622 ## upload to contain many files, and we won't die due to too many 3559*6287Sps156622 ## open file handles. The user can access the files using the hash 3560*6287Sps156622 ## below. 3561*6287Sps156622 close $filehandle if $CLOSE_UPLOAD_FILES; 3562*6287Sps156622 $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode; 3563*6287Sps156622 3564*6287Sps156622 # Save some information about the uploaded file where we can get 3565*6287Sps156622 # at it later. 3566*6287Sps156622 # Use the typeglob as the key, as this is guaranteed to be 3567*6287Sps156622 # unique for each filehandle. Don't use the file descriptor as 3568*6287Sps156622 # this will be re-used for each filehandle if the 3569*6287Sps156622 # close_upload_files feature is used. 3570*6287Sps156622 $self->{'.tmpfiles'}->{$$filehandle}= { 3571*6287Sps156622 hndl => $filehandle, 3572*6287Sps156622 name => $tmpfile, 3573*6287Sps156622 info => {%header}, 3574*6287Sps156622 }; 3575*6287Sps156622 push(@{$self->{$param}},$filehandle); 3576*6287Sps156622 } 3577*6287Sps156622 } 3578*6287Sps156622 return $returnvalue; 3579*6287Sps156622} 3580*6287Sps156622END_OF_FUNC 3581*6287Sps156622 3582*6287Sps156622 35830Sstevel@tonic-gate'upload' =><<'END_OF_FUNC', 35840Sstevel@tonic-gatesub upload { 35850Sstevel@tonic-gate my($self,$param_name) = self_or_default(@_); 3586*6287Sps156622 my @param = grep {ref($_) && defined(fileno($_))} $self->param($param_name); 35870Sstevel@tonic-gate return unless @param; 35880Sstevel@tonic-gate return wantarray ? @param : $param[0]; 35890Sstevel@tonic-gate} 35900Sstevel@tonic-gateEND_OF_FUNC 35910Sstevel@tonic-gate 35920Sstevel@tonic-gate'tmpFileName' => <<'END_OF_FUNC', 35930Sstevel@tonic-gatesub tmpFileName { 35940Sstevel@tonic-gate my($self,$filename) = self_or_default(@_); 3595*6287Sps156622 return $self->{'.tmpfiles'}->{$$filename}->{name} ? 3596*6287Sps156622 $self->{'.tmpfiles'}->{$$filename}->{name}->as_string 35970Sstevel@tonic-gate : ''; 35980Sstevel@tonic-gate} 35990Sstevel@tonic-gateEND_OF_FUNC 36000Sstevel@tonic-gate 36010Sstevel@tonic-gate'uploadInfo' => <<'END_OF_FUNC', 36020Sstevel@tonic-gatesub uploadInfo { 36030Sstevel@tonic-gate my($self,$filename) = self_or_default(@_); 3604*6287Sps156622 return $self->{'.tmpfiles'}->{$$filename}->{info}; 36050Sstevel@tonic-gate} 36060Sstevel@tonic-gateEND_OF_FUNC 36070Sstevel@tonic-gate 36080Sstevel@tonic-gate# internal routine, don't use 36090Sstevel@tonic-gate'_set_values_and_labels' => <<'END_OF_FUNC', 36100Sstevel@tonic-gatesub _set_values_and_labels { 36110Sstevel@tonic-gate my $self = shift; 36120Sstevel@tonic-gate my ($v,$l,$n) = @_; 36130Sstevel@tonic-gate $$l = $v if ref($v) eq 'HASH' && !ref($$l); 36140Sstevel@tonic-gate return $self->param($n) if !defined($v); 36150Sstevel@tonic-gate return $v if !ref($v); 36160Sstevel@tonic-gate return ref($v) eq 'HASH' ? keys %$v : @$v; 36170Sstevel@tonic-gate} 36180Sstevel@tonic-gateEND_OF_FUNC 36190Sstevel@tonic-gate 36200Sstevel@tonic-gate# internal routine, don't use 36210Sstevel@tonic-gate'_set_attributes' => <<'END_OF_FUNC', 36220Sstevel@tonic-gatesub _set_attributes { 36230Sstevel@tonic-gate my $self = shift; 36240Sstevel@tonic-gate my($element, $attributes) = @_; 36250Sstevel@tonic-gate return '' unless defined($attributes->{$element}); 36260Sstevel@tonic-gate $attribs = ' '; 36270Sstevel@tonic-gate foreach my $attrib (keys %{$attributes->{$element}}) { 3628667Sps156622 (my $clean_attrib = $attrib) =~ s/^-//; 3629667Sps156622 $attribs .= "@{[lc($clean_attrib)]}=\"$attributes->{$element}{$attrib}\" "; 36300Sstevel@tonic-gate } 36310Sstevel@tonic-gate $attribs =~ s/ $//; 36320Sstevel@tonic-gate return $attribs; 36330Sstevel@tonic-gate} 36340Sstevel@tonic-gateEND_OF_FUNC 36350Sstevel@tonic-gate 36360Sstevel@tonic-gate'_compile_all' => <<'END_OF_FUNC', 36370Sstevel@tonic-gatesub _compile_all { 36380Sstevel@tonic-gate foreach (@_) { 36390Sstevel@tonic-gate next if defined(&$_); 36400Sstevel@tonic-gate $AUTOLOAD = "CGI::$_"; 36410Sstevel@tonic-gate _compile(); 36420Sstevel@tonic-gate } 36430Sstevel@tonic-gate} 36440Sstevel@tonic-gateEND_OF_FUNC 36450Sstevel@tonic-gate 36460Sstevel@tonic-gate); 36470Sstevel@tonic-gateEND_OF_AUTOLOAD 36480Sstevel@tonic-gate; 36490Sstevel@tonic-gate 36500Sstevel@tonic-gate######################################################### 36510Sstevel@tonic-gate# Globals and stubs for other packages that we use. 36520Sstevel@tonic-gate######################################################### 36530Sstevel@tonic-gate 36540Sstevel@tonic-gate################### Fh -- lightweight filehandle ############### 36550Sstevel@tonic-gatepackage Fh; 36560Sstevel@tonic-gateuse overload 36570Sstevel@tonic-gate '""' => \&asString, 36580Sstevel@tonic-gate 'cmp' => \&compare, 36590Sstevel@tonic-gate 'fallback'=>1; 36600Sstevel@tonic-gate 36610Sstevel@tonic-gate$FH='fh00000'; 36620Sstevel@tonic-gate 36630Sstevel@tonic-gate*Fh::AUTOLOAD = \&CGI::AUTOLOAD; 36640Sstevel@tonic-gate 3665667Sps156622sub DESTROY { 3666667Sps156622 my $self = shift; 3667667Sps156622 close $self; 3668667Sps156622} 3669667Sps156622 36700Sstevel@tonic-gate$AUTOLOADED_ROUTINES = ''; # prevent -w error 36710Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; 36720Sstevel@tonic-gate%SUBS = ( 36730Sstevel@tonic-gate'asString' => <<'END_OF_FUNC', 36740Sstevel@tonic-gatesub asString { 36750Sstevel@tonic-gate my $self = shift; 36760Sstevel@tonic-gate # get rid of package name 36770Sstevel@tonic-gate (my $i = $$self) =~ s/^\*(\w+::fh\d{5})+//; 36780Sstevel@tonic-gate $i =~ s/%(..)/ chr(hex($1)) /eg; 36790Sstevel@tonic-gate return $i.$CGI::TAINTED; 36800Sstevel@tonic-gate# BEGIN DEAD CODE 36810Sstevel@tonic-gate# This was an extremely clever patch that allowed "use strict refs". 36820Sstevel@tonic-gate# Unfortunately it relied on another bug that caused leaky file descriptors. 36830Sstevel@tonic-gate# The underlying bug has been fixed, so this no longer works. However 36840Sstevel@tonic-gate# "strict refs" still works for some reason. 36850Sstevel@tonic-gate# my $self = shift; 36860Sstevel@tonic-gate# return ${*{$self}{SCALAR}}; 36870Sstevel@tonic-gate# END DEAD CODE 36880Sstevel@tonic-gate} 36890Sstevel@tonic-gateEND_OF_FUNC 36900Sstevel@tonic-gate 36910Sstevel@tonic-gate'compare' => <<'END_OF_FUNC', 36920Sstevel@tonic-gatesub compare { 36930Sstevel@tonic-gate my $self = shift; 36940Sstevel@tonic-gate my $value = shift; 36950Sstevel@tonic-gate return "$self" cmp $value; 36960Sstevel@tonic-gate} 36970Sstevel@tonic-gateEND_OF_FUNC 36980Sstevel@tonic-gate 36990Sstevel@tonic-gate'new' => <<'END_OF_FUNC', 37000Sstevel@tonic-gatesub new { 37010Sstevel@tonic-gate my($pack,$name,$file,$delete) = @_; 37020Sstevel@tonic-gate _setup_symbols(@SAVED_SYMBOLS) if @SAVED_SYMBOLS; 37030Sstevel@tonic-gate require Fcntl unless defined &Fcntl::O_RDWR; 37040Sstevel@tonic-gate (my $safename = $name) =~ s/([':%])/ sprintf '%%%02X', ord $1 /eg; 37050Sstevel@tonic-gate my $fv = ++$FH . $safename; 37060Sstevel@tonic-gate my $ref = \*{"Fh::$fv"}; 3707*6287Sps156622 $file =~ m!^([a-zA-Z0-9_\+ \'\":/.\$\\-]+)$! || return; 37080Sstevel@tonic-gate my $safe = $1; 37090Sstevel@tonic-gate sysopen($ref,$safe,Fcntl::O_RDWR()|Fcntl::O_CREAT()|Fcntl::O_EXCL(),0600) || return; 37100Sstevel@tonic-gate unlink($safe) if $delete; 37110Sstevel@tonic-gate CORE::delete $Fh::{$fv}; 37120Sstevel@tonic-gate return bless $ref,$pack; 37130Sstevel@tonic-gate} 37140Sstevel@tonic-gateEND_OF_FUNC 37150Sstevel@tonic-gate 37160Sstevel@tonic-gate); 37170Sstevel@tonic-gateEND_OF_AUTOLOAD 37180Sstevel@tonic-gate 37190Sstevel@tonic-gate######################## MultipartBuffer #################### 37200Sstevel@tonic-gatepackage MultipartBuffer; 37210Sstevel@tonic-gate 37220Sstevel@tonic-gateuse constant DEBUG => 0; 37230Sstevel@tonic-gate 37240Sstevel@tonic-gate# how many bytes to read at a time. We use 37250Sstevel@tonic-gate# a 4K buffer by default. 37260Sstevel@tonic-gate$INITIAL_FILLUNIT = 1024 * 4; 37270Sstevel@tonic-gate$TIMEOUT = 240*60; # 4 hour timeout for big files 37280Sstevel@tonic-gate$SPIN_LOOP_MAX = 2000; # bug fix for some Netscape servers 37290Sstevel@tonic-gate$CRLF=$CGI::CRLF; 37300Sstevel@tonic-gate 37310Sstevel@tonic-gate#reuse the autoload function 37320Sstevel@tonic-gate*MultipartBuffer::AUTOLOAD = \&CGI::AUTOLOAD; 37330Sstevel@tonic-gate 37340Sstevel@tonic-gate# avoid autoloader warnings 37350Sstevel@tonic-gatesub DESTROY {} 37360Sstevel@tonic-gate 37370Sstevel@tonic-gate############################################################################### 37380Sstevel@tonic-gate################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND #################### 37390Sstevel@tonic-gate############################################################################### 37400Sstevel@tonic-gate$AUTOLOADED_ROUTINES = ''; # prevent -w error 37410Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; 37420Sstevel@tonic-gate%SUBS = ( 37430Sstevel@tonic-gate 37440Sstevel@tonic-gate'new' => <<'END_OF_FUNC', 37450Sstevel@tonic-gatesub new { 37460Sstevel@tonic-gate my($package,$interface,$boundary,$length) = @_; 37470Sstevel@tonic-gate $FILLUNIT = $INITIAL_FILLUNIT; 37480Sstevel@tonic-gate $CGI::DefaultClass->binmode($IN); # if $CGI::needs_binmode; # just do it always 3749667Sps156622 37500Sstevel@tonic-gate # If the user types garbage into the file upload field, 37510Sstevel@tonic-gate # then Netscape passes NOTHING to the server (not good). 37520Sstevel@tonic-gate # We may hang on this read in that case. So we implement 37530Sstevel@tonic-gate # a read timeout. If nothing is ready to read 37540Sstevel@tonic-gate # by then, we return. 37550Sstevel@tonic-gate 37560Sstevel@tonic-gate # Netscape seems to be a little bit unreliable 37570Sstevel@tonic-gate # about providing boundary strings. 37580Sstevel@tonic-gate my $boundary_read = 0; 37590Sstevel@tonic-gate if ($boundary) { 37600Sstevel@tonic-gate 37610Sstevel@tonic-gate # Under the MIME spec, the boundary consists of the 37620Sstevel@tonic-gate # characters "--" PLUS the Boundary string 37630Sstevel@tonic-gate 37640Sstevel@tonic-gate # BUG: IE 3.01 on the Macintosh uses just the boundary -- not 37650Sstevel@tonic-gate # the two extra hyphens. We do a special case here on the user-agent!!!! 37660Sstevel@tonic-gate $boundary = "--$boundary" unless CGI::user_agent('MSIE\s+3\.0[12];\s*Mac|DreamPassport'); 37670Sstevel@tonic-gate 37680Sstevel@tonic-gate } else { # otherwise we find it ourselves 37690Sstevel@tonic-gate my($old); 37700Sstevel@tonic-gate ($old,$/) = ($/,$CRLF); # read a CRLF-delimited line 37710Sstevel@tonic-gate $boundary = <STDIN>; # BUG: This won't work correctly under mod_perl 37720Sstevel@tonic-gate $length -= length($boundary); 37730Sstevel@tonic-gate chomp($boundary); # remove the CRLF 37740Sstevel@tonic-gate $/ = $old; # restore old line separator 37750Sstevel@tonic-gate $boundary_read++; 37760Sstevel@tonic-gate } 37770Sstevel@tonic-gate 37780Sstevel@tonic-gate my $self = {LENGTH=>$length, 3779667Sps156622 CHUNKED=>!defined $length, 37800Sstevel@tonic-gate BOUNDARY=>$boundary, 37810Sstevel@tonic-gate INTERFACE=>$interface, 37820Sstevel@tonic-gate BUFFER=>'', 37830Sstevel@tonic-gate }; 37840Sstevel@tonic-gate 37850Sstevel@tonic-gate $FILLUNIT = length($boundary) 37860Sstevel@tonic-gate if length($boundary) > $FILLUNIT; 37870Sstevel@tonic-gate 37880Sstevel@tonic-gate my $retval = bless $self,ref $package || $package; 37890Sstevel@tonic-gate 37900Sstevel@tonic-gate # Read the preamble and the topmost (boundary) line plus the CRLF. 37910Sstevel@tonic-gate unless ($boundary_read) { 37920Sstevel@tonic-gate while ($self->read(0)) { } 37930Sstevel@tonic-gate } 37940Sstevel@tonic-gate die "Malformed multipart POST: data truncated\n" if $self->eof; 37950Sstevel@tonic-gate 37960Sstevel@tonic-gate return $retval; 37970Sstevel@tonic-gate} 37980Sstevel@tonic-gateEND_OF_FUNC 37990Sstevel@tonic-gate 38000Sstevel@tonic-gate'readHeader' => <<'END_OF_FUNC', 38010Sstevel@tonic-gatesub readHeader { 38020Sstevel@tonic-gate my($self) = @_; 38030Sstevel@tonic-gate my($end); 38040Sstevel@tonic-gate my($ok) = 0; 38050Sstevel@tonic-gate my($bad) = 0; 38060Sstevel@tonic-gate 38070Sstevel@tonic-gate local($CRLF) = "\015\012" if $CGI::OS eq 'VMS' || $CGI::EBCDIC; 38080Sstevel@tonic-gate 38090Sstevel@tonic-gate do { 38100Sstevel@tonic-gate $self->fillBuffer($FILLUNIT); 38110Sstevel@tonic-gate $ok++ if ($end = index($self->{BUFFER},"${CRLF}${CRLF}")) >= 0; 38120Sstevel@tonic-gate $ok++ if $self->{BUFFER} eq ''; 38130Sstevel@tonic-gate $bad++ if !$ok && $self->{LENGTH} <= 0; 38140Sstevel@tonic-gate # this was a bad idea 38150Sstevel@tonic-gate # $FILLUNIT *= 2 if length($self->{BUFFER}) >= $FILLUNIT; 38160Sstevel@tonic-gate } until $ok || $bad; 38170Sstevel@tonic-gate return () if $bad; 38180Sstevel@tonic-gate 38190Sstevel@tonic-gate #EBCDIC NOTE: translate header into EBCDIC, but watch out for continuation lines! 38200Sstevel@tonic-gate 38210Sstevel@tonic-gate my($header) = substr($self->{BUFFER},0,$end+2); 38220Sstevel@tonic-gate substr($self->{BUFFER},0,$end+4) = ''; 38230Sstevel@tonic-gate my %return; 38240Sstevel@tonic-gate 38250Sstevel@tonic-gate if ($CGI::EBCDIC) { 38260Sstevel@tonic-gate warn "untranslated header=$header\n" if DEBUG; 38270Sstevel@tonic-gate $header = CGI::Util::ascii2ebcdic($header); 38280Sstevel@tonic-gate warn "translated header=$header\n" if DEBUG; 38290Sstevel@tonic-gate } 38300Sstevel@tonic-gate 38310Sstevel@tonic-gate # See RFC 2045 Appendix A and RFC 822 sections 3.4.8 38320Sstevel@tonic-gate # (Folding Long Header Fields), 3.4.3 (Comments) 38330Sstevel@tonic-gate # and 3.4.5 (Quoted-Strings). 38340Sstevel@tonic-gate 38350Sstevel@tonic-gate my $token = '[-\w!\#$%&\'*+.^_\`|{}~]'; 38360Sstevel@tonic-gate $header=~s/$CRLF\s+/ /og; # merge continuation lines 38370Sstevel@tonic-gate 38380Sstevel@tonic-gate while ($header=~/($token+):\s+([^$CRLF]*)/mgox) { 38390Sstevel@tonic-gate my ($field_name,$field_value) = ($1,$2); 38400Sstevel@tonic-gate $field_name =~ s/\b(\w)/uc($1)/eg; #canonicalize 38410Sstevel@tonic-gate $return{$field_name}=$field_value; 38420Sstevel@tonic-gate } 38430Sstevel@tonic-gate return %return; 38440Sstevel@tonic-gate} 38450Sstevel@tonic-gateEND_OF_FUNC 38460Sstevel@tonic-gate 38470Sstevel@tonic-gate# This reads and returns the body as a single scalar value. 38480Sstevel@tonic-gate'readBody' => <<'END_OF_FUNC', 38490Sstevel@tonic-gatesub readBody { 38500Sstevel@tonic-gate my($self) = @_; 38510Sstevel@tonic-gate my($data); 38520Sstevel@tonic-gate my($returnval)=''; 38530Sstevel@tonic-gate 38540Sstevel@tonic-gate #EBCDIC NOTE: want to translate returnval into EBCDIC HERE 38550Sstevel@tonic-gate 38560Sstevel@tonic-gate while (defined($data = $self->read)) { 38570Sstevel@tonic-gate $returnval .= $data; 38580Sstevel@tonic-gate } 38590Sstevel@tonic-gate 38600Sstevel@tonic-gate if ($CGI::EBCDIC) { 38610Sstevel@tonic-gate warn "untranslated body=$returnval\n" if DEBUG; 38620Sstevel@tonic-gate $returnval = CGI::Util::ascii2ebcdic($returnval); 38630Sstevel@tonic-gate warn "translated body=$returnval\n" if DEBUG; 38640Sstevel@tonic-gate } 38650Sstevel@tonic-gate return $returnval; 38660Sstevel@tonic-gate} 38670Sstevel@tonic-gateEND_OF_FUNC 38680Sstevel@tonic-gate 38690Sstevel@tonic-gate# This will read $bytes or until the boundary is hit, whichever happens 38700Sstevel@tonic-gate# first. After the boundary is hit, we return undef. The next read will 38710Sstevel@tonic-gate# skip over the boundary and begin reading again; 38720Sstevel@tonic-gate'read' => <<'END_OF_FUNC', 38730Sstevel@tonic-gatesub read { 38740Sstevel@tonic-gate my($self,$bytes) = @_; 38750Sstevel@tonic-gate 38760Sstevel@tonic-gate # default number of bytes to read 38770Sstevel@tonic-gate $bytes = $bytes || $FILLUNIT; 38780Sstevel@tonic-gate 38790Sstevel@tonic-gate # Fill up our internal buffer in such a way that the boundary 38800Sstevel@tonic-gate # is never split between reads. 38810Sstevel@tonic-gate $self->fillBuffer($bytes); 38820Sstevel@tonic-gate 38830Sstevel@tonic-gate my $boundary_start = $CGI::EBCDIC ? CGI::Util::ebcdic2ascii($self->{BOUNDARY}) : $self->{BOUNDARY}; 38840Sstevel@tonic-gate my $boundary_end = $CGI::EBCDIC ? CGI::Util::ebcdic2ascii($self->{BOUNDARY}.'--') : $self->{BOUNDARY}.'--'; 38850Sstevel@tonic-gate 38860Sstevel@tonic-gate # Find the boundary in the buffer (it may not be there). 38870Sstevel@tonic-gate my $start = index($self->{BUFFER},$boundary_start); 38880Sstevel@tonic-gate 38890Sstevel@tonic-gate warn "boundary=$self->{BOUNDARY} length=$self->{LENGTH} start=$start\n" if DEBUG; 3890667Sps156622 38910Sstevel@tonic-gate # protect against malformed multipart POST operations 3892667Sps156622 die "Malformed multipart POST\n" unless $self->{CHUNKED} || ($start >= 0 || $self->{LENGTH} > 0); 38930Sstevel@tonic-gate 38940Sstevel@tonic-gate #EBCDIC NOTE: want to translate boundary search into ASCII here. 38950Sstevel@tonic-gate 38960Sstevel@tonic-gate # If the boundary begins the data, then skip past it 38970Sstevel@tonic-gate # and return undef. 38980Sstevel@tonic-gate if ($start == 0) { 38990Sstevel@tonic-gate 39000Sstevel@tonic-gate # clear us out completely if we've hit the last boundary. 39010Sstevel@tonic-gate if (index($self->{BUFFER},$boundary_end)==0) { 39020Sstevel@tonic-gate $self->{BUFFER}=''; 39030Sstevel@tonic-gate $self->{LENGTH}=0; 39040Sstevel@tonic-gate return undef; 39050Sstevel@tonic-gate } 39060Sstevel@tonic-gate 39070Sstevel@tonic-gate # just remove the boundary. 39080Sstevel@tonic-gate substr($self->{BUFFER},0,length($boundary_start))=''; 39090Sstevel@tonic-gate $self->{BUFFER} =~ s/^\012\015?//; 39100Sstevel@tonic-gate return undef; 39110Sstevel@tonic-gate } 39120Sstevel@tonic-gate 39130Sstevel@tonic-gate my $bytesToReturn; 39140Sstevel@tonic-gate if ($start > 0) { # read up to the boundary 39150Sstevel@tonic-gate $bytesToReturn = $start-2 > $bytes ? $bytes : $start; 39160Sstevel@tonic-gate } else { # read the requested number of bytes 39170Sstevel@tonic-gate # leave enough bytes in the buffer to allow us to read 39180Sstevel@tonic-gate # the boundary. Thanks to Kevin Hendrick for finding 39190Sstevel@tonic-gate # this one. 39200Sstevel@tonic-gate $bytesToReturn = $bytes - (length($boundary_start)+1); 39210Sstevel@tonic-gate } 39220Sstevel@tonic-gate 39230Sstevel@tonic-gate my $returnval=substr($self->{BUFFER},0,$bytesToReturn); 39240Sstevel@tonic-gate substr($self->{BUFFER},0,$bytesToReturn)=''; 39250Sstevel@tonic-gate 39260Sstevel@tonic-gate # If we hit the boundary, remove the CRLF from the end. 39270Sstevel@tonic-gate return ($bytesToReturn==$start) 39280Sstevel@tonic-gate ? substr($returnval,0,-2) : $returnval; 39290Sstevel@tonic-gate} 39300Sstevel@tonic-gateEND_OF_FUNC 39310Sstevel@tonic-gate 39320Sstevel@tonic-gate 39330Sstevel@tonic-gate# This fills up our internal buffer in such a way that the 39340Sstevel@tonic-gate# boundary is never split between reads 39350Sstevel@tonic-gate'fillBuffer' => <<'END_OF_FUNC', 39360Sstevel@tonic-gatesub fillBuffer { 39370Sstevel@tonic-gate my($self,$bytes) = @_; 3938667Sps156622 return unless $self->{CHUNKED} || $self->{LENGTH}; 39390Sstevel@tonic-gate 39400Sstevel@tonic-gate my($boundaryLength) = length($self->{BOUNDARY}); 39410Sstevel@tonic-gate my($bufferLength) = length($self->{BUFFER}); 39420Sstevel@tonic-gate my($bytesToRead) = $bytes - $bufferLength + $boundaryLength + 2; 3943667Sps156622 $bytesToRead = $self->{LENGTH} if !$self->{CHUNKED} && $self->{LENGTH} < $bytesToRead; 39440Sstevel@tonic-gate 39450Sstevel@tonic-gate # Try to read some data. We may hang here if the browser is screwed up. 39460Sstevel@tonic-gate my $bytesRead = $self->{INTERFACE}->read_from_client(\$self->{BUFFER}, 39470Sstevel@tonic-gate $bytesToRead, 39480Sstevel@tonic-gate $bufferLength); 39490Sstevel@tonic-gate warn "bytesToRead=$bytesToRead, bufferLength=$bufferLength, buffer=$self->{BUFFER}\n" if DEBUG; 39500Sstevel@tonic-gate $self->{BUFFER} = '' unless defined $self->{BUFFER}; 39510Sstevel@tonic-gate 39520Sstevel@tonic-gate # An apparent bug in the Apache server causes the read() 39530Sstevel@tonic-gate # to return zero bytes repeatedly without blocking if the 39540Sstevel@tonic-gate # remote user aborts during a file transfer. I don't know how 39550Sstevel@tonic-gate # they manage this, but the workaround is to abort if we get 39560Sstevel@tonic-gate # more than SPIN_LOOP_MAX consecutive zero reads. 3957667Sps156622 if ($bytesRead <= 0) { 39580Sstevel@tonic-gate die "CGI.pm: Server closed socket during multipart read (client aborted?).\n" 39590Sstevel@tonic-gate if ($self->{ZERO_LOOP_COUNTER}++ >= $SPIN_LOOP_MAX); 39600Sstevel@tonic-gate } else { 39610Sstevel@tonic-gate $self->{ZERO_LOOP_COUNTER}=0; 39620Sstevel@tonic-gate } 39630Sstevel@tonic-gate 3964667Sps156622 $self->{LENGTH} -= $bytesRead if !$self->{CHUNKED} && $bytesRead; 39650Sstevel@tonic-gate} 39660Sstevel@tonic-gateEND_OF_FUNC 39670Sstevel@tonic-gate 39680Sstevel@tonic-gate 39690Sstevel@tonic-gate# Return true when we've finished reading 39700Sstevel@tonic-gate'eof' => <<'END_OF_FUNC' 39710Sstevel@tonic-gatesub eof { 39720Sstevel@tonic-gate my($self) = @_; 39730Sstevel@tonic-gate return 1 if (length($self->{BUFFER}) == 0) 39740Sstevel@tonic-gate && ($self->{LENGTH} <= 0); 39750Sstevel@tonic-gate undef; 39760Sstevel@tonic-gate} 39770Sstevel@tonic-gateEND_OF_FUNC 39780Sstevel@tonic-gate 39790Sstevel@tonic-gate); 39800Sstevel@tonic-gateEND_OF_AUTOLOAD 39810Sstevel@tonic-gate 39820Sstevel@tonic-gate#################################################################################### 39830Sstevel@tonic-gate################################## TEMPORARY FILES ################################# 39840Sstevel@tonic-gate#################################################################################### 39850Sstevel@tonic-gatepackage CGITempFile; 39860Sstevel@tonic-gate 39870Sstevel@tonic-gatesub find_tempdir { 39880Sstevel@tonic-gate $SL = $CGI::SL; 39890Sstevel@tonic-gate $MAC = $CGI::OS eq 'MACINTOSH'; 39900Sstevel@tonic-gate my ($vol) = $MAC ? MacPerl::Volumes() =~ /:(.*)/ : ""; 3991*6287Sps156622 unless (defined $TMPDIRECTORY) { 39920Sstevel@tonic-gate @TEMP=("${SL}usr${SL}tmp","${SL}var${SL}tmp", 39930Sstevel@tonic-gate "C:${SL}temp","${SL}tmp","${SL}temp", 39940Sstevel@tonic-gate "${vol}${SL}Temporary Items", 39950Sstevel@tonic-gate "${SL}WWW_ROOT", "${SL}SYS\$SCRATCH", 39960Sstevel@tonic-gate "C:${SL}system${SL}temp"); 39970Sstevel@tonic-gate unshift(@TEMP,$ENV{'TMPDIR'}) if defined $ENV{'TMPDIR'}; 39980Sstevel@tonic-gate 39990Sstevel@tonic-gate # this feature was supposed to provide per-user tmpfiles, but 40000Sstevel@tonic-gate # it is problematic. 40010Sstevel@tonic-gate # unshift(@TEMP,(getpwuid($<))[7].'/tmp') if $CGI::OS eq 'UNIX'; 40020Sstevel@tonic-gate # Rob: getpwuid() is unfortunately UNIX specific. On brain dead OS'es this 40030Sstevel@tonic-gate # : can generate a 'getpwuid() not implemented' exception, even though 40040Sstevel@tonic-gate # : it's never called. Found under DOS/Win with the DJGPP perl port. 40050Sstevel@tonic-gate # : Refer to getpwuid() only at run-time if we're fortunate and have UNIX. 40060Sstevel@tonic-gate # unshift(@TEMP,(eval {(getpwuid($>))[7]}).'/tmp') if $CGI::OS eq 'UNIX' and $> != 0; 40070Sstevel@tonic-gate 40080Sstevel@tonic-gate foreach (@TEMP) { 40090Sstevel@tonic-gate do {$TMPDIRECTORY = $_; last} if -d $_ && -w _; 40100Sstevel@tonic-gate } 40110Sstevel@tonic-gate } 40120Sstevel@tonic-gate $TMPDIRECTORY = $MAC ? "" : "." unless $TMPDIRECTORY; 40130Sstevel@tonic-gate} 40140Sstevel@tonic-gate 40150Sstevel@tonic-gatefind_tempdir(); 40160Sstevel@tonic-gate 40170Sstevel@tonic-gate$MAXTRIES = 5000; 40180Sstevel@tonic-gate 40190Sstevel@tonic-gate# cute feature, but overload implementation broke it 40200Sstevel@tonic-gate# %OVERLOAD = ('""'=>'as_string'); 40210Sstevel@tonic-gate*CGITempFile::AUTOLOAD = \&CGI::AUTOLOAD; 40220Sstevel@tonic-gate 40230Sstevel@tonic-gatesub DESTROY { 40240Sstevel@tonic-gate my($self) = @_; 40250Sstevel@tonic-gate $$self =~ m!^([a-zA-Z0-9_ \'\":/.\$\\-]+)$! || return; 40260Sstevel@tonic-gate my $safe = $1; # untaint operation 40270Sstevel@tonic-gate unlink $safe; # get rid of the file 40280Sstevel@tonic-gate} 40290Sstevel@tonic-gate 40300Sstevel@tonic-gate############################################################################### 40310Sstevel@tonic-gate################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND #################### 40320Sstevel@tonic-gate############################################################################### 40330Sstevel@tonic-gate$AUTOLOADED_ROUTINES = ''; # prevent -w error 40340Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD'; 40350Sstevel@tonic-gate%SUBS = ( 40360Sstevel@tonic-gate 40370Sstevel@tonic-gate'new' => <<'END_OF_FUNC', 40380Sstevel@tonic-gatesub new { 40390Sstevel@tonic-gate my($package,$sequence) = @_; 40400Sstevel@tonic-gate my $filename; 40410Sstevel@tonic-gate find_tempdir() unless -w $TMPDIRECTORY; 40420Sstevel@tonic-gate for (my $i = 0; $i < $MAXTRIES; $i++) { 40430Sstevel@tonic-gate last if ! -f ($filename = sprintf("${TMPDIRECTORY}${SL}CGItemp%d",$sequence++)); 40440Sstevel@tonic-gate } 40450Sstevel@tonic-gate # check that it is a more-or-less valid filename 4046*6287Sps156622 return unless $filename =~ m!^([a-zA-Z0-9_\+ \'\":/.\$\\-]+)$!; 40470Sstevel@tonic-gate # this used to untaint, now it doesn't 40480Sstevel@tonic-gate # $filename = $1; 40490Sstevel@tonic-gate return bless \$filename; 40500Sstevel@tonic-gate} 40510Sstevel@tonic-gateEND_OF_FUNC 40520Sstevel@tonic-gate 40530Sstevel@tonic-gate'as_string' => <<'END_OF_FUNC' 40540Sstevel@tonic-gatesub as_string { 40550Sstevel@tonic-gate my($self) = @_; 40560Sstevel@tonic-gate return $$self; 40570Sstevel@tonic-gate} 40580Sstevel@tonic-gateEND_OF_FUNC 40590Sstevel@tonic-gate 40600Sstevel@tonic-gate); 40610Sstevel@tonic-gateEND_OF_AUTOLOAD 40620Sstevel@tonic-gate 40630Sstevel@tonic-gatepackage CGI; 40640Sstevel@tonic-gate 40650Sstevel@tonic-gate# We get a whole bunch of warnings about "possibly uninitialized variables" 40660Sstevel@tonic-gate# when running with the -w switch. Touch them all once to get rid of the 40670Sstevel@tonic-gate# warnings. This is ugly and I hate it. 40680Sstevel@tonic-gateif ($^W) { 40690Sstevel@tonic-gate $CGI::CGI = ''; 40700Sstevel@tonic-gate $CGI::CGI=<<EOF; 40710Sstevel@tonic-gate $CGI::VERSION; 40720Sstevel@tonic-gate $MultipartBuffer::SPIN_LOOP_MAX; 40730Sstevel@tonic-gate $MultipartBuffer::CRLF; 40740Sstevel@tonic-gate $MultipartBuffer::TIMEOUT; 40750Sstevel@tonic-gate $MultipartBuffer::INITIAL_FILLUNIT; 40760Sstevel@tonic-gateEOF 40770Sstevel@tonic-gate ; 40780Sstevel@tonic-gate} 40790Sstevel@tonic-gate 40800Sstevel@tonic-gate1; 40810Sstevel@tonic-gate 40820Sstevel@tonic-gate__END__ 40830Sstevel@tonic-gate 40840Sstevel@tonic-gate=head1 NAME 40850Sstevel@tonic-gate 40860Sstevel@tonic-gateCGI - Simple Common Gateway Interface Class 40870Sstevel@tonic-gate 40880Sstevel@tonic-gate=head1 SYNOPSIS 40890Sstevel@tonic-gate 40900Sstevel@tonic-gate # CGI script that creates a fill-out form 40910Sstevel@tonic-gate # and echoes back its values. 40920Sstevel@tonic-gate 40930Sstevel@tonic-gate use CGI qw/:standard/; 40940Sstevel@tonic-gate print header, 40950Sstevel@tonic-gate start_html('A Simple Example'), 40960Sstevel@tonic-gate h1('A Simple Example'), 40970Sstevel@tonic-gate start_form, 40980Sstevel@tonic-gate "What's your name? ",textfield('name'),p, 40990Sstevel@tonic-gate "What's the combination?", p, 41000Sstevel@tonic-gate checkbox_group(-name=>'words', 41010Sstevel@tonic-gate -values=>['eenie','meenie','minie','moe'], 41020Sstevel@tonic-gate -defaults=>['eenie','minie']), p, 41030Sstevel@tonic-gate "What's your favorite color? ", 41040Sstevel@tonic-gate popup_menu(-name=>'color', 41050Sstevel@tonic-gate -values=>['red','green','blue','chartreuse']),p, 41060Sstevel@tonic-gate submit, 41070Sstevel@tonic-gate end_form, 41080Sstevel@tonic-gate hr; 41090Sstevel@tonic-gate 41100Sstevel@tonic-gate if (param()) { 4111667Sps156622 my $name = param('name'); 4112667Sps156622 my $keywords = join ', ',param('words'); 4113667Sps156622 my $color = param('color'); 4114667Sps156622 print "Your name is",em(escapeHTML($name)),p, 4115667Sps156622 "The keywords are: ",em(escapeHTML($keywords)),p, 4116667Sps156622 "Your favorite color is ",em(escapeHTML($color)), 41170Sstevel@tonic-gate hr; 41180Sstevel@tonic-gate } 41190Sstevel@tonic-gate 41200Sstevel@tonic-gate=head1 ABSTRACT 41210Sstevel@tonic-gate 41220Sstevel@tonic-gateThis perl library uses perl5 objects to make it easy to create Web 41230Sstevel@tonic-gatefill-out forms and parse their contents. This package defines CGI 41240Sstevel@tonic-gateobjects, entities that contain the values of the current query string 41250Sstevel@tonic-gateand other state variables. Using a CGI object's methods, you can 41260Sstevel@tonic-gateexamine keywords and parameters passed to your script, and create 41270Sstevel@tonic-gateforms whose initial values are taken from the current query (thereby 41280Sstevel@tonic-gatepreserving state information). The module provides shortcut functions 41290Sstevel@tonic-gatethat produce boilerplate HTML, reducing typing and coding errors. It 41300Sstevel@tonic-gatealso provides functionality for some of the more advanced features of 41310Sstevel@tonic-gateCGI scripting, including support for file uploads, cookies, cascading 41320Sstevel@tonic-gatestyle sheets, server push, and frames. 41330Sstevel@tonic-gate 41340Sstevel@tonic-gateCGI.pm also provides a simple function-oriented programming style for 41350Sstevel@tonic-gatethose who don't need its object-oriented features. 41360Sstevel@tonic-gate 41370Sstevel@tonic-gateThe current version of CGI.pm is available at 41380Sstevel@tonic-gate 41390Sstevel@tonic-gate http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html 41400Sstevel@tonic-gate ftp://ftp-genome.wi.mit.edu/pub/software/WWW/ 41410Sstevel@tonic-gate 41420Sstevel@tonic-gate=head1 DESCRIPTION 41430Sstevel@tonic-gate 41440Sstevel@tonic-gate=head2 PROGRAMMING STYLE 41450Sstevel@tonic-gate 41460Sstevel@tonic-gateThere are two styles of programming with CGI.pm, an object-oriented 41470Sstevel@tonic-gatestyle and a function-oriented style. In the object-oriented style you 41480Sstevel@tonic-gatecreate one or more CGI objects and then use object methods to create 41490Sstevel@tonic-gatethe various elements of the page. Each CGI object starts out with the 41500Sstevel@tonic-gatelist of named parameters that were passed to your CGI script by the 41510Sstevel@tonic-gateserver. You can modify the objects, save them to a file or database 41520Sstevel@tonic-gateand recreate them. Because each object corresponds to the "state" of 41530Sstevel@tonic-gatethe CGI script, and because each object's parameter list is 41540Sstevel@tonic-gateindependent of the others, this allows you to save the state of the 41550Sstevel@tonic-gatescript and restore it later. 41560Sstevel@tonic-gate 41570Sstevel@tonic-gateFor example, using the object oriented style, here is how you create 41580Sstevel@tonic-gatea simple "Hello World" HTML page: 41590Sstevel@tonic-gate 41600Sstevel@tonic-gate #!/usr/local/bin/perl -w 41610Sstevel@tonic-gate use CGI; # load CGI routines 41620Sstevel@tonic-gate $q = new CGI; # create new CGI object 41630Sstevel@tonic-gate print $q->header, # create the HTTP header 41640Sstevel@tonic-gate $q->start_html('hello world'), # start the HTML 41650Sstevel@tonic-gate $q->h1('hello world'), # level 1 header 41660Sstevel@tonic-gate $q->end_html; # end the HTML 41670Sstevel@tonic-gate 41680Sstevel@tonic-gateIn the function-oriented style, there is one default CGI object that 41690Sstevel@tonic-gateyou rarely deal with directly. Instead you just call functions to 41700Sstevel@tonic-gateretrieve CGI parameters, create HTML tags, manage cookies, and so 41710Sstevel@tonic-gateon. This provides you with a cleaner programming interface, but 41720Sstevel@tonic-gatelimits you to using one CGI object at a time. The following example 41730Sstevel@tonic-gateprints the same page, but uses the function-oriented interface. 41740Sstevel@tonic-gateThe main differences are that we now need to import a set of functions 41750Sstevel@tonic-gateinto our name space (usually the "standard" functions), and we don't 41760Sstevel@tonic-gateneed to create the CGI object. 41770Sstevel@tonic-gate 41780Sstevel@tonic-gate #!/usr/local/bin/perl 41790Sstevel@tonic-gate use CGI qw/:standard/; # load standard CGI routines 41800Sstevel@tonic-gate print header, # create the HTTP header 41810Sstevel@tonic-gate start_html('hello world'), # start the HTML 41820Sstevel@tonic-gate h1('hello world'), # level 1 header 41830Sstevel@tonic-gate end_html; # end the HTML 41840Sstevel@tonic-gate 41850Sstevel@tonic-gateThe examples in this document mainly use the object-oriented style. 41860Sstevel@tonic-gateSee HOW TO IMPORT FUNCTIONS for important information on 41870Sstevel@tonic-gatefunction-oriented programming in CGI.pm 41880Sstevel@tonic-gate 41890Sstevel@tonic-gate=head2 CALLING CGI.PM ROUTINES 41900Sstevel@tonic-gate 41910Sstevel@tonic-gateMost CGI.pm routines accept several arguments, sometimes as many as 20 41920Sstevel@tonic-gateoptional ones! To simplify this interface, all routines use a named 41930Sstevel@tonic-gateargument calling style that looks like this: 41940Sstevel@tonic-gate 41950Sstevel@tonic-gate print $q->header(-type=>'image/gif',-expires=>'+3d'); 41960Sstevel@tonic-gate 41970Sstevel@tonic-gateEach argument name is preceded by a dash. Neither case nor order 41980Sstevel@tonic-gatematters in the argument list. -type, -Type, and -TYPE are all 41990Sstevel@tonic-gateacceptable. In fact, only the first argument needs to begin with a 42000Sstevel@tonic-gatedash. If a dash is present in the first argument, CGI.pm assumes 42010Sstevel@tonic-gatedashes for the subsequent ones. 42020Sstevel@tonic-gate 42030Sstevel@tonic-gateSeveral routines are commonly called with just one argument. In the 42040Sstevel@tonic-gatecase of these routines you can provide the single argument without an 42050Sstevel@tonic-gateargument name. header() happens to be one of these routines. In this 42060Sstevel@tonic-gatecase, the single argument is the document type. 42070Sstevel@tonic-gate 42080Sstevel@tonic-gate print $q->header('text/html'); 42090Sstevel@tonic-gate 42100Sstevel@tonic-gateOther such routines are documented below. 42110Sstevel@tonic-gate 42120Sstevel@tonic-gateSometimes named arguments expect a scalar, sometimes a reference to an 42130Sstevel@tonic-gatearray, and sometimes a reference to a hash. Often, you can pass any 42140Sstevel@tonic-gatetype of argument and the routine will do whatever is most appropriate. 42150Sstevel@tonic-gateFor example, the param() routine is used to set a CGI parameter to a 42160Sstevel@tonic-gatesingle or a multi-valued value. The two cases are shown below: 42170Sstevel@tonic-gate 42180Sstevel@tonic-gate $q->param(-name=>'veggie',-value=>'tomato'); 42190Sstevel@tonic-gate $q->param(-name=>'veggie',-value=>['tomato','tomahto','potato','potahto']); 42200Sstevel@tonic-gate 42210Sstevel@tonic-gateA large number of routines in CGI.pm actually aren't specifically 42220Sstevel@tonic-gatedefined in the module, but are generated automatically as needed. 42230Sstevel@tonic-gateThese are the "HTML shortcuts," routines that generate HTML tags for 42240Sstevel@tonic-gateuse in dynamically-generated pages. HTML tags have both attributes 42250Sstevel@tonic-gate(the attribute="value" pairs within the tag itself) and contents (the 42260Sstevel@tonic-gatepart between the opening and closing pairs.) To distinguish between 42270Sstevel@tonic-gateattributes and contents, CGI.pm uses the convention of passing HTML 42280Sstevel@tonic-gateattributes as a hash reference as the first argument, and the 42290Sstevel@tonic-gatecontents, if any, as any subsequent arguments. It works out like 42300Sstevel@tonic-gatethis: 42310Sstevel@tonic-gate 42320Sstevel@tonic-gate Code Generated HTML 42330Sstevel@tonic-gate ---- -------------- 42340Sstevel@tonic-gate h1() <h1> 42350Sstevel@tonic-gate h1('some','contents'); <h1>some contents</h1> 42360Sstevel@tonic-gate h1({-align=>left}); <h1 align="LEFT"> 42370Sstevel@tonic-gate h1({-align=>left},'contents'); <h1 align="LEFT">contents</h1> 42380Sstevel@tonic-gate 42390Sstevel@tonic-gateHTML tags are described in more detail later. 42400Sstevel@tonic-gate 42410Sstevel@tonic-gateMany newcomers to CGI.pm are puzzled by the difference between the 42420Sstevel@tonic-gatecalling conventions for the HTML shortcuts, which require curly braces 42430Sstevel@tonic-gatearound the HTML tag attributes, and the calling conventions for other 42440Sstevel@tonic-gateroutines, which manage to generate attributes without the curly 42450Sstevel@tonic-gatebrackets. Don't be confused. As a convenience the curly braces are 42460Sstevel@tonic-gateoptional in all but the HTML shortcuts. If you like, you can use 42470Sstevel@tonic-gatecurly braces when calling any routine that takes named arguments. For 42480Sstevel@tonic-gateexample: 42490Sstevel@tonic-gate 42500Sstevel@tonic-gate print $q->header( {-type=>'image/gif',-expires=>'+3d'} ); 42510Sstevel@tonic-gate 42520Sstevel@tonic-gateIf you use the B<-w> switch, you will be warned that some CGI.pm argument 42530Sstevel@tonic-gatenames conflict with built-in Perl functions. The most frequent of 42540Sstevel@tonic-gatethese is the -values argument, used to create multi-valued menus, 42550Sstevel@tonic-gateradio button clusters and the like. To get around this warning, you 42560Sstevel@tonic-gatehave several choices: 42570Sstevel@tonic-gate 42580Sstevel@tonic-gate=over 4 42590Sstevel@tonic-gate 42600Sstevel@tonic-gate=item 1. 42610Sstevel@tonic-gate 42620Sstevel@tonic-gateUse another name for the argument, if one is available. 42630Sstevel@tonic-gateFor example, -value is an alias for -values. 42640Sstevel@tonic-gate 42650Sstevel@tonic-gate=item 2. 42660Sstevel@tonic-gate 42670Sstevel@tonic-gateChange the capitalization, e.g. -Values 42680Sstevel@tonic-gate 42690Sstevel@tonic-gate=item 3. 42700Sstevel@tonic-gate 42710Sstevel@tonic-gatePut quotes around the argument name, e.g. '-values' 42720Sstevel@tonic-gate 42730Sstevel@tonic-gate=back 42740Sstevel@tonic-gate 42750Sstevel@tonic-gateMany routines will do something useful with a named argument that it 42760Sstevel@tonic-gatedoesn't recognize. For example, you can produce non-standard HTTP 42770Sstevel@tonic-gateheader fields by providing them as named arguments: 42780Sstevel@tonic-gate 42790Sstevel@tonic-gate print $q->header(-type => 'text/html', 42800Sstevel@tonic-gate -cost => 'Three smackers', 42810Sstevel@tonic-gate -annoyance_level => 'high', 42820Sstevel@tonic-gate -complaints_to => 'bit bucket'); 42830Sstevel@tonic-gate 42840Sstevel@tonic-gateThis will produce the following nonstandard HTTP header: 42850Sstevel@tonic-gate 42860Sstevel@tonic-gate HTTP/1.0 200 OK 42870Sstevel@tonic-gate Cost: Three smackers 42880Sstevel@tonic-gate Annoyance-level: high 42890Sstevel@tonic-gate Complaints-to: bit bucket 42900Sstevel@tonic-gate Content-type: text/html 42910Sstevel@tonic-gate 42920Sstevel@tonic-gateNotice the way that underscores are translated automatically into 42930Sstevel@tonic-gatehyphens. HTML-generating routines perform a different type of 42940Sstevel@tonic-gatetranslation. 42950Sstevel@tonic-gate 42960Sstevel@tonic-gateThis feature allows you to keep up with the rapidly changing HTTP and 42970Sstevel@tonic-gateHTML "standards". 42980Sstevel@tonic-gate 42990Sstevel@tonic-gate=head2 CREATING A NEW QUERY OBJECT (OBJECT-ORIENTED STYLE): 43000Sstevel@tonic-gate 43010Sstevel@tonic-gate $query = new CGI; 43020Sstevel@tonic-gate 43030Sstevel@tonic-gateThis will parse the input (from both POST and GET methods) and store 4304*6287Sps156622it into a perl5 object called $query. 4305*6287Sps156622 4306*6287Sps156622Any filehandles from file uploads will have their position reset to 4307*6287Sps156622the beginning of the file. 43080Sstevel@tonic-gate 43090Sstevel@tonic-gate=head2 CREATING A NEW QUERY OBJECT FROM AN INPUT FILE 43100Sstevel@tonic-gate 43110Sstevel@tonic-gate $query = new CGI(INPUTFILE); 43120Sstevel@tonic-gate 43130Sstevel@tonic-gateIf you provide a file handle to the new() method, it will read 43140Sstevel@tonic-gateparameters from the file (or STDIN, or whatever). The file can be in 43150Sstevel@tonic-gateany of the forms describing below under debugging (i.e. a series of 43160Sstevel@tonic-gatenewline delimited TAG=VALUE pairs will work). Conveniently, this type 43170Sstevel@tonic-gateof file is created by the save() method (see below). Multiple records 43180Sstevel@tonic-gatecan be saved and restored. 43190Sstevel@tonic-gate 43200Sstevel@tonic-gatePerl purists will be pleased to know that this syntax accepts 43210Sstevel@tonic-gatereferences to file handles, or even references to filehandle globs, 43220Sstevel@tonic-gatewhich is the "official" way to pass a filehandle: 43230Sstevel@tonic-gate 43240Sstevel@tonic-gate $query = new CGI(\*STDIN); 43250Sstevel@tonic-gate 43260Sstevel@tonic-gateYou can also initialize the CGI object with a FileHandle or IO::File 43270Sstevel@tonic-gateobject. 43280Sstevel@tonic-gate 43290Sstevel@tonic-gateIf you are using the function-oriented interface and want to 43300Sstevel@tonic-gateinitialize CGI state from a file handle, the way to do this is with 43310Sstevel@tonic-gateB<restore_parameters()>. This will (re)initialize the 43320Sstevel@tonic-gatedefault CGI object from the indicated file handle. 43330Sstevel@tonic-gate 43340Sstevel@tonic-gate open (IN,"test.in") || die; 43350Sstevel@tonic-gate restore_parameters(IN); 43360Sstevel@tonic-gate close IN; 43370Sstevel@tonic-gate 43380Sstevel@tonic-gateYou can also initialize the query object from an associative array 43390Sstevel@tonic-gatereference: 43400Sstevel@tonic-gate 43410Sstevel@tonic-gate $query = new CGI( {'dinosaur'=>'barney', 43420Sstevel@tonic-gate 'song'=>'I love you', 43430Sstevel@tonic-gate 'friends'=>[qw/Jessica George Nancy/]} 43440Sstevel@tonic-gate ); 43450Sstevel@tonic-gate 43460Sstevel@tonic-gateor from a properly formatted, URL-escaped query string: 43470Sstevel@tonic-gate 43480Sstevel@tonic-gate $query = new CGI('dinosaur=barney&color=purple'); 43490Sstevel@tonic-gate 43500Sstevel@tonic-gateor from a previously existing CGI object (currently this clones the 43510Sstevel@tonic-gateparameter list, but none of the other object-specific fields, such as 43520Sstevel@tonic-gateautoescaping): 43530Sstevel@tonic-gate 43540Sstevel@tonic-gate $old_query = new CGI; 43550Sstevel@tonic-gate $new_query = new CGI($old_query); 43560Sstevel@tonic-gate 43570Sstevel@tonic-gateTo create an empty query, initialize it from an empty string or hash: 43580Sstevel@tonic-gate 43590Sstevel@tonic-gate $empty_query = new CGI(""); 43600Sstevel@tonic-gate 43610Sstevel@tonic-gate -or- 43620Sstevel@tonic-gate 43630Sstevel@tonic-gate $empty_query = new CGI({}); 43640Sstevel@tonic-gate 43650Sstevel@tonic-gate=head2 FETCHING A LIST OF KEYWORDS FROM THE QUERY: 43660Sstevel@tonic-gate 43670Sstevel@tonic-gate @keywords = $query->keywords 43680Sstevel@tonic-gate 43690Sstevel@tonic-gateIf the script was invoked as the result of an <ISINDEX> search, the 43700Sstevel@tonic-gateparsed keywords can be obtained as an array using the keywords() method. 43710Sstevel@tonic-gate 43720Sstevel@tonic-gate=head2 FETCHING THE NAMES OF ALL THE PARAMETERS PASSED TO YOUR SCRIPT: 43730Sstevel@tonic-gate 43740Sstevel@tonic-gate @names = $query->param 43750Sstevel@tonic-gate 43760Sstevel@tonic-gateIf the script was invoked with a parameter list 43770Sstevel@tonic-gate(e.g. "name1=value1&name2=value2&name3=value3"), the param() method 43780Sstevel@tonic-gatewill return the parameter names as a list. If the script was invoked 43790Sstevel@tonic-gateas an <ISINDEX> script and contains a string without ampersands 43800Sstevel@tonic-gate(e.g. "value1+value2+value3") , there will be a single parameter named 43810Sstevel@tonic-gate"keywords" containing the "+"-delimited keywords. 43820Sstevel@tonic-gate 43830Sstevel@tonic-gateNOTE: As of version 1.5, the array of parameter names returned will 43840Sstevel@tonic-gatebe in the same order as they were submitted by the browser. 43850Sstevel@tonic-gateUsually this order is the same as the order in which the 43860Sstevel@tonic-gateparameters are defined in the form (however, this isn't part 43870Sstevel@tonic-gateof the spec, and so isn't guaranteed). 43880Sstevel@tonic-gate 43890Sstevel@tonic-gate=head2 FETCHING THE VALUE OR VALUES OF A SINGLE NAMED PARAMETER: 43900Sstevel@tonic-gate 43910Sstevel@tonic-gate @values = $query->param('foo'); 43920Sstevel@tonic-gate 43930Sstevel@tonic-gate -or- 43940Sstevel@tonic-gate 43950Sstevel@tonic-gate $value = $query->param('foo'); 43960Sstevel@tonic-gate 43970Sstevel@tonic-gatePass the param() method a single argument to fetch the value of the 43980Sstevel@tonic-gatenamed parameter. If the parameter is multivalued (e.g. from multiple 43990Sstevel@tonic-gateselections in a scrolling list), you can ask to receive an array. Otherwise 44000Sstevel@tonic-gatethe method will return a single value. 44010Sstevel@tonic-gate 44020Sstevel@tonic-gateIf a value is not given in the query string, as in the queries 44030Sstevel@tonic-gate"name1=&name2=" or "name1&name2", it will be returned as an empty 44040Sstevel@tonic-gatestring. This feature is new in 2.63. 44050Sstevel@tonic-gate 44060Sstevel@tonic-gate 44070Sstevel@tonic-gateIf the parameter does not exist at all, then param() will return undef 44080Sstevel@tonic-gatein a scalar context, and the empty list in a list context. 44090Sstevel@tonic-gate 44100Sstevel@tonic-gate 44110Sstevel@tonic-gate=head2 SETTING THE VALUE(S) OF A NAMED PARAMETER: 44120Sstevel@tonic-gate 44130Sstevel@tonic-gate $query->param('foo','an','array','of','values'); 44140Sstevel@tonic-gate 44150Sstevel@tonic-gateThis sets the value for the named parameter 'foo' to an array of 44160Sstevel@tonic-gatevalues. This is one way to change the value of a field AFTER 44170Sstevel@tonic-gatethe script has been invoked once before. (Another way is with 44180Sstevel@tonic-gatethe -override parameter accepted by all methods that generate 44190Sstevel@tonic-gateform elements.) 44200Sstevel@tonic-gate 44210Sstevel@tonic-gateparam() also recognizes a named parameter style of calling described 44220Sstevel@tonic-gatein more detail later: 44230Sstevel@tonic-gate 44240Sstevel@tonic-gate $query->param(-name=>'foo',-values=>['an','array','of','values']); 44250Sstevel@tonic-gate 44260Sstevel@tonic-gate -or- 44270Sstevel@tonic-gate 44280Sstevel@tonic-gate $query->param(-name=>'foo',-value=>'the value'); 44290Sstevel@tonic-gate 44300Sstevel@tonic-gate=head2 APPENDING ADDITIONAL VALUES TO A NAMED PARAMETER: 44310Sstevel@tonic-gate 44320Sstevel@tonic-gate $query->append(-name=>'foo',-values=>['yet','more','values']); 44330Sstevel@tonic-gate 44340Sstevel@tonic-gateThis adds a value or list of values to the named parameter. The 44350Sstevel@tonic-gatevalues are appended to the end of the parameter if it already exists. 44360Sstevel@tonic-gateOtherwise the parameter is created. Note that this method only 44370Sstevel@tonic-gaterecognizes the named argument calling syntax. 44380Sstevel@tonic-gate 44390Sstevel@tonic-gate=head2 IMPORTING ALL PARAMETERS INTO A NAMESPACE: 44400Sstevel@tonic-gate 44410Sstevel@tonic-gate $query->import_names('R'); 44420Sstevel@tonic-gate 44430Sstevel@tonic-gateThis creates a series of variables in the 'R' namespace. For example, 44440Sstevel@tonic-gate$R::foo, @R:foo. For keyword lists, a variable @R::keywords will appear. 44450Sstevel@tonic-gateIf no namespace is given, this method will assume 'Q'. 44460Sstevel@tonic-gateWARNING: don't import anything into 'main'; this is a major security 44470Sstevel@tonic-gaterisk!!!! 44480Sstevel@tonic-gate 44490Sstevel@tonic-gateNOTE 1: Variable names are transformed as necessary into legal Perl 44500Sstevel@tonic-gatevariable names. All non-legal characters are transformed into 44510Sstevel@tonic-gateunderscores. If you need to keep the original names, you should use 44520Sstevel@tonic-gatethe param() method instead to access CGI variables by name. 44530Sstevel@tonic-gate 44540Sstevel@tonic-gateNOTE 2: In older versions, this method was called B<import()>. As of version 2.20, 44550Sstevel@tonic-gatethis name has been removed completely to avoid conflict with the built-in 44560Sstevel@tonic-gatePerl module B<import> operator. 44570Sstevel@tonic-gate 44580Sstevel@tonic-gate=head2 DELETING A PARAMETER COMPLETELY: 44590Sstevel@tonic-gate 44600Sstevel@tonic-gate $query->delete('foo','bar','baz'); 44610Sstevel@tonic-gate 44620Sstevel@tonic-gateThis completely clears a list of parameters. It sometimes useful for 44630Sstevel@tonic-gateresetting parameters that you don't want passed down between script 44640Sstevel@tonic-gateinvocations. 44650Sstevel@tonic-gate 44660Sstevel@tonic-gateIf you are using the function call interface, use "Delete()" instead 44670Sstevel@tonic-gateto avoid conflicts with Perl's built-in delete operator. 44680Sstevel@tonic-gate 44690Sstevel@tonic-gate=head2 DELETING ALL PARAMETERS: 44700Sstevel@tonic-gate 44710Sstevel@tonic-gate $query->delete_all(); 44720Sstevel@tonic-gate 44730Sstevel@tonic-gateThis clears the CGI object completely. It might be useful to ensure 44740Sstevel@tonic-gatethat all the defaults are taken when you create a fill-out form. 44750Sstevel@tonic-gate 44760Sstevel@tonic-gateUse Delete_all() instead if you are using the function call interface. 44770Sstevel@tonic-gate 4478*6287Sps156622=head2 HANDLING NON-URLENCODED ARGUMENTS 4479*6287Sps156622 4480*6287Sps156622 4481*6287Sps156622If POSTed data is not of type application/x-www-form-urlencoded or 4482*6287Sps156622multipart/form-data, then the POSTed data will not be processed, but 4483*6287Sps156622instead be returned as-is in a parameter named POSTDATA. To retrieve 4484*6287Sps156622it, use code like this: 4485*6287Sps156622 4486*6287Sps156622 my $data = $query->param('POSTDATA'); 4487*6287Sps156622 4488*6287Sps156622Likewise if PUTed data can be retrieved with code like this: 4489*6287Sps156622 4490*6287Sps156622 my $data = $query->param('PUTDATA'); 4491*6287Sps156622 4492*6287Sps156622(If you don't know what the preceding means, don't worry about it. It 4493*6287Sps156622only affects people trying to use CGI for XML processing and other 4494*6287Sps156622specialized tasks.) 4495*6287Sps156622 4496*6287Sps156622 44970Sstevel@tonic-gate=head2 DIRECT ACCESS TO THE PARAMETER LIST: 44980Sstevel@tonic-gate 44990Sstevel@tonic-gate $q->param_fetch('address')->[1] = '1313 Mockingbird Lane'; 45000Sstevel@tonic-gate unshift @{$q->param_fetch(-name=>'address')},'George Munster'; 45010Sstevel@tonic-gate 45020Sstevel@tonic-gateIf you need access to the parameter list in a way that isn't covered 45030Sstevel@tonic-gateby the methods above, you can obtain a direct reference to it by 45040Sstevel@tonic-gatecalling the B<param_fetch()> method with the name of the . This 45050Sstevel@tonic-gatewill return an array reference to the named parameters, which you then 45060Sstevel@tonic-gatecan manipulate in any way you like. 45070Sstevel@tonic-gate 45080Sstevel@tonic-gateYou can also use a named argument style using the B<-name> argument. 45090Sstevel@tonic-gate 45100Sstevel@tonic-gate=head2 FETCHING THE PARAMETER LIST AS A HASH: 45110Sstevel@tonic-gate 45120Sstevel@tonic-gate $params = $q->Vars; 45130Sstevel@tonic-gate print $params->{'address'}; 45140Sstevel@tonic-gate @foo = split("\0",$params->{'foo'}); 45150Sstevel@tonic-gate %params = $q->Vars; 45160Sstevel@tonic-gate 45170Sstevel@tonic-gate use CGI ':cgi-lib'; 45180Sstevel@tonic-gate $params = Vars; 45190Sstevel@tonic-gate 45200Sstevel@tonic-gateMany people want to fetch the entire parameter list as a hash in which 45210Sstevel@tonic-gatethe keys are the names of the CGI parameters, and the values are the 45220Sstevel@tonic-gateparameters' values. The Vars() method does this. Called in a scalar 45230Sstevel@tonic-gatecontext, it returns the parameter list as a tied hash reference. 45240Sstevel@tonic-gateChanging a key changes the value of the parameter in the underlying 45250Sstevel@tonic-gateCGI parameter list. Called in a list context, it returns the 45260Sstevel@tonic-gateparameter list as an ordinary hash. This allows you to read the 45270Sstevel@tonic-gatecontents of the parameter list, but not to change it. 45280Sstevel@tonic-gate 45290Sstevel@tonic-gateWhen using this, the thing you must watch out for are multivalued CGI 45300Sstevel@tonic-gateparameters. Because a hash cannot distinguish between scalar and 45310Sstevel@tonic-gatelist context, multivalued parameters will be returned as a packed 45320Sstevel@tonic-gatestring, separated by the "\0" (null) character. You must split this 45330Sstevel@tonic-gatepacked string in order to get at the individual values. This is the 45340Sstevel@tonic-gateconvention introduced long ago by Steve Brenner in his cgi-lib.pl 45350Sstevel@tonic-gatemodule for Perl version 4. 45360Sstevel@tonic-gate 45370Sstevel@tonic-gateIf you wish to use Vars() as a function, import the I<:cgi-lib> set of 45380Sstevel@tonic-gatefunction calls (also see the section on CGI-LIB compatibility). 45390Sstevel@tonic-gate 45400Sstevel@tonic-gate=head2 SAVING THE STATE OF THE SCRIPT TO A FILE: 45410Sstevel@tonic-gate 4542667Sps156622 $query->save(\*FILEHANDLE) 45430Sstevel@tonic-gate 45440Sstevel@tonic-gateThis will write the current state of the form to the provided 45450Sstevel@tonic-gatefilehandle. You can read it back in by providing a filehandle 45460Sstevel@tonic-gateto the new() method. Note that the filehandle can be a file, a pipe, 45470Sstevel@tonic-gateor whatever! 45480Sstevel@tonic-gate 45490Sstevel@tonic-gateThe format of the saved file is: 45500Sstevel@tonic-gate 45510Sstevel@tonic-gate NAME1=VALUE1 45520Sstevel@tonic-gate NAME1=VALUE1' 45530Sstevel@tonic-gate NAME2=VALUE2 45540Sstevel@tonic-gate NAME3=VALUE3 45550Sstevel@tonic-gate = 45560Sstevel@tonic-gate 45570Sstevel@tonic-gateBoth name and value are URL escaped. Multi-valued CGI parameters are 45580Sstevel@tonic-gaterepresented as repeated names. A session record is delimited by a 45590Sstevel@tonic-gatesingle = symbol. You can write out multiple records and read them 45600Sstevel@tonic-gateback in with several calls to B<new>. You can do this across several 45610Sstevel@tonic-gatesessions by opening the file in append mode, allowing you to create 45620Sstevel@tonic-gateprimitive guest books, or to keep a history of users' queries. Here's 45630Sstevel@tonic-gatea short example of creating multiple session records: 45640Sstevel@tonic-gate 45650Sstevel@tonic-gate use CGI; 45660Sstevel@tonic-gate 45670Sstevel@tonic-gate open (OUT,">>test.out") || die; 45680Sstevel@tonic-gate $records = 5; 45690Sstevel@tonic-gate foreach (0..$records) { 45700Sstevel@tonic-gate my $q = new CGI; 45710Sstevel@tonic-gate $q->param(-name=>'counter',-value=>$_); 4572667Sps156622 $q->save(\*OUT); 45730Sstevel@tonic-gate } 45740Sstevel@tonic-gate close OUT; 45750Sstevel@tonic-gate 45760Sstevel@tonic-gate # reopen for reading 45770Sstevel@tonic-gate open (IN,"test.out") || die; 45780Sstevel@tonic-gate while (!eof(IN)) { 4579667Sps156622 my $q = new CGI(\*IN); 45800Sstevel@tonic-gate print $q->param('counter'),"\n"; 45810Sstevel@tonic-gate } 45820Sstevel@tonic-gate 45830Sstevel@tonic-gateThe file format used for save/restore is identical to that used by the 45840Sstevel@tonic-gateWhitehead Genome Center's data exchange format "Boulderio", and can be 45850Sstevel@tonic-gatemanipulated and even databased using Boulderio utilities. See 45860Sstevel@tonic-gate 45870Sstevel@tonic-gate http://stein.cshl.org/boulder/ 45880Sstevel@tonic-gate 45890Sstevel@tonic-gatefor further details. 45900Sstevel@tonic-gate 45910Sstevel@tonic-gateIf you wish to use this method from the function-oriented (non-OO) 45920Sstevel@tonic-gateinterface, the exported name for this method is B<save_parameters()>. 45930Sstevel@tonic-gate 45940Sstevel@tonic-gate=head2 RETRIEVING CGI ERRORS 45950Sstevel@tonic-gate 45960Sstevel@tonic-gateErrors can occur while processing user input, particularly when 45970Sstevel@tonic-gateprocessing uploaded files. When these errors occur, CGI will stop 45980Sstevel@tonic-gateprocessing and return an empty parameter list. You can test for 45990Sstevel@tonic-gatethe existence and nature of errors using the I<cgi_error()> function. 46000Sstevel@tonic-gateThe error messages are formatted as HTTP status codes. You can either 46010Sstevel@tonic-gateincorporate the error text into an HTML page, or use it as the value 46020Sstevel@tonic-gateof the HTTP status: 46030Sstevel@tonic-gate 46040Sstevel@tonic-gate my $error = $q->cgi_error; 46050Sstevel@tonic-gate if ($error) { 46060Sstevel@tonic-gate print $q->header(-status=>$error), 46070Sstevel@tonic-gate $q->start_html('Problems'), 46080Sstevel@tonic-gate $q->h2('Request not processed'), 46090Sstevel@tonic-gate $q->strong($error); 46100Sstevel@tonic-gate exit 0; 46110Sstevel@tonic-gate } 46120Sstevel@tonic-gate 46130Sstevel@tonic-gateWhen using the function-oriented interface (see the next section), 46140Sstevel@tonic-gateerrors may only occur the first time you call I<param()>. Be ready 46150Sstevel@tonic-gatefor this! 46160Sstevel@tonic-gate 46170Sstevel@tonic-gate=head2 USING THE FUNCTION-ORIENTED INTERFACE 46180Sstevel@tonic-gate 46190Sstevel@tonic-gateTo use the function-oriented interface, you must specify which CGI.pm 46200Sstevel@tonic-gateroutines or sets of routines to import into your script's namespace. 46210Sstevel@tonic-gateThere is a small overhead associated with this importation, but it 46220Sstevel@tonic-gateisn't much. 46230Sstevel@tonic-gate 46240Sstevel@tonic-gate use CGI <list of methods>; 46250Sstevel@tonic-gate 46260Sstevel@tonic-gateThe listed methods will be imported into the current package; you can 46270Sstevel@tonic-gatecall them directly without creating a CGI object first. This example 46280Sstevel@tonic-gateshows how to import the B<param()> and B<header()> 46290Sstevel@tonic-gatemethods, and then use them directly: 46300Sstevel@tonic-gate 46310Sstevel@tonic-gate use CGI 'param','header'; 46320Sstevel@tonic-gate print header('text/plain'); 46330Sstevel@tonic-gate $zipcode = param('zipcode'); 46340Sstevel@tonic-gate 46350Sstevel@tonic-gateMore frequently, you'll import common sets of functions by referring 46360Sstevel@tonic-gateto the groups by name. All function sets are preceded with a ":" 46370Sstevel@tonic-gatecharacter as in ":html3" (for tags defined in the HTML 3 standard). 46380Sstevel@tonic-gate 46390Sstevel@tonic-gateHere is a list of the function sets you can import: 46400Sstevel@tonic-gate 46410Sstevel@tonic-gate=over 4 46420Sstevel@tonic-gate 46430Sstevel@tonic-gate=item B<:cgi> 46440Sstevel@tonic-gate 46450Sstevel@tonic-gateImport all CGI-handling methods, such as B<param()>, B<path_info()> 46460Sstevel@tonic-gateand the like. 46470Sstevel@tonic-gate 46480Sstevel@tonic-gate=item B<:form> 46490Sstevel@tonic-gate 46500Sstevel@tonic-gateImport all fill-out form generating methods, such as B<textfield()>. 46510Sstevel@tonic-gate 46520Sstevel@tonic-gate=item B<:html2> 46530Sstevel@tonic-gate 46540Sstevel@tonic-gateImport all methods that generate HTML 2.0 standard elements. 46550Sstevel@tonic-gate 46560Sstevel@tonic-gate=item B<:html3> 46570Sstevel@tonic-gate 46580Sstevel@tonic-gateImport all methods that generate HTML 3.0 elements (such as 46590Sstevel@tonic-gate<table>, <super> and <sub>). 46600Sstevel@tonic-gate 46610Sstevel@tonic-gate=item B<:html4> 46620Sstevel@tonic-gate 46630Sstevel@tonic-gateImport all methods that generate HTML 4 elements (such as 46640Sstevel@tonic-gate<abbrev>, <acronym> and <thead>). 46650Sstevel@tonic-gate 46660Sstevel@tonic-gate=item B<:netscape> 46670Sstevel@tonic-gate 46680Sstevel@tonic-gateImport all methods that generate Netscape-specific HTML extensions. 46690Sstevel@tonic-gate 46700Sstevel@tonic-gate=item B<:html> 46710Sstevel@tonic-gate 46720Sstevel@tonic-gateImport all HTML-generating shortcuts (i.e. 'html2' + 'html3' + 46730Sstevel@tonic-gate'netscape')... 46740Sstevel@tonic-gate 46750Sstevel@tonic-gate=item B<:standard> 46760Sstevel@tonic-gate 46770Sstevel@tonic-gateImport "standard" features, 'html2', 'html3', 'html4', 'form' and 'cgi'. 46780Sstevel@tonic-gate 46790Sstevel@tonic-gate=item B<:all> 46800Sstevel@tonic-gate 46810Sstevel@tonic-gateImport all the available methods. For the full list, see the CGI.pm 46820Sstevel@tonic-gatecode, where the variable %EXPORT_TAGS is defined. 46830Sstevel@tonic-gate 46840Sstevel@tonic-gate=back 46850Sstevel@tonic-gate 46860Sstevel@tonic-gateIf you import a function name that is not part of CGI.pm, the module 46870Sstevel@tonic-gatewill treat it as a new HTML tag and generate the appropriate 46880Sstevel@tonic-gatesubroutine. You can then use it like any other HTML tag. This is to 46890Sstevel@tonic-gateprovide for the rapidly-evolving HTML "standard." For example, say 46900Sstevel@tonic-gateMicrosoft comes out with a new tag called <gradient> (which causes the 46910Sstevel@tonic-gateuser's desktop to be flooded with a rotating gradient fill until his 46920Sstevel@tonic-gatemachine reboots). You don't need to wait for a new version of CGI.pm 46930Sstevel@tonic-gateto start using it immediately: 46940Sstevel@tonic-gate 46950Sstevel@tonic-gate use CGI qw/:standard :html3 gradient/; 46960Sstevel@tonic-gate print gradient({-start=>'red',-end=>'blue'}); 46970Sstevel@tonic-gate 46980Sstevel@tonic-gateNote that in the interests of execution speed CGI.pm does B<not> use 46990Sstevel@tonic-gatethe standard L<Exporter> syntax for specifying load symbols. This may 47000Sstevel@tonic-gatechange in the future. 47010Sstevel@tonic-gate 47020Sstevel@tonic-gateIf you import any of the state-maintaining CGI or form-generating 47030Sstevel@tonic-gatemethods, a default CGI object will be created and initialized 47040Sstevel@tonic-gateautomatically the first time you use any of the methods that require 47050Sstevel@tonic-gateone to be present. This includes B<param()>, B<textfield()>, 47060Sstevel@tonic-gateB<submit()> and the like. (If you need direct access to the CGI 47070Sstevel@tonic-gateobject, you can find it in the global variable B<$CGI::Q>). By 47080Sstevel@tonic-gateimporting CGI.pm methods, you can create visually elegant scripts: 47090Sstevel@tonic-gate 47100Sstevel@tonic-gate use CGI qw/:standard/; 47110Sstevel@tonic-gate print 47120Sstevel@tonic-gate header, 47130Sstevel@tonic-gate start_html('Simple Script'), 47140Sstevel@tonic-gate h1('Simple Script'), 47150Sstevel@tonic-gate start_form, 47160Sstevel@tonic-gate "What's your name? ",textfield('name'),p, 47170Sstevel@tonic-gate "What's the combination?", 47180Sstevel@tonic-gate checkbox_group(-name=>'words', 47190Sstevel@tonic-gate -values=>['eenie','meenie','minie','moe'], 47200Sstevel@tonic-gate -defaults=>['eenie','moe']),p, 47210Sstevel@tonic-gate "What's your favorite color?", 47220Sstevel@tonic-gate popup_menu(-name=>'color', 47230Sstevel@tonic-gate -values=>['red','green','blue','chartreuse']),p, 47240Sstevel@tonic-gate submit, 47250Sstevel@tonic-gate end_form, 47260Sstevel@tonic-gate hr,"\n"; 47270Sstevel@tonic-gate 47280Sstevel@tonic-gate if (param) { 47290Sstevel@tonic-gate print 47300Sstevel@tonic-gate "Your name is ",em(param('name')),p, 47310Sstevel@tonic-gate "The keywords are: ",em(join(", ",param('words'))),p, 47320Sstevel@tonic-gate "Your favorite color is ",em(param('color')),".\n"; 47330Sstevel@tonic-gate } 47340Sstevel@tonic-gate print end_html; 47350Sstevel@tonic-gate 47360Sstevel@tonic-gate=head2 PRAGMAS 47370Sstevel@tonic-gate 47380Sstevel@tonic-gateIn addition to the function sets, there are a number of pragmas that 47390Sstevel@tonic-gateyou can import. Pragmas, which are always preceded by a hyphen, 47400Sstevel@tonic-gatechange the way that CGI.pm functions in various ways. Pragmas, 47410Sstevel@tonic-gatefunction sets, and individual functions can all be imported in the 47420Sstevel@tonic-gatesame use() line. For example, the following use statement imports the 47430Sstevel@tonic-gatestandard set of functions and enables debugging mode (pragma 47440Sstevel@tonic-gate-debug): 47450Sstevel@tonic-gate 47460Sstevel@tonic-gate use CGI qw/:standard -debug/; 47470Sstevel@tonic-gate 47480Sstevel@tonic-gateThe current list of pragmas is as follows: 47490Sstevel@tonic-gate 47500Sstevel@tonic-gate=over 4 47510Sstevel@tonic-gate 47520Sstevel@tonic-gate=item -any 47530Sstevel@tonic-gate 47540Sstevel@tonic-gateWhen you I<use CGI -any>, then any method that the query object 47550Sstevel@tonic-gatedoesn't recognize will be interpreted as a new HTML tag. This allows 47560Sstevel@tonic-gateyou to support the next I<ad hoc> Netscape or Microsoft HTML 47570Sstevel@tonic-gateextension. This lets you go wild with new and unsupported tags: 47580Sstevel@tonic-gate 47590Sstevel@tonic-gate use CGI qw(-any); 47600Sstevel@tonic-gate $q=new CGI; 47610Sstevel@tonic-gate print $q->gradient({speed=>'fast',start=>'red',end=>'blue'}); 47620Sstevel@tonic-gate 47630Sstevel@tonic-gateSince using <cite>any</cite> causes any mistyped method name 47640Sstevel@tonic-gateto be interpreted as an HTML tag, use it with care or not at 47650Sstevel@tonic-gateall. 47660Sstevel@tonic-gate 47670Sstevel@tonic-gate=item -compile 47680Sstevel@tonic-gate 47690Sstevel@tonic-gateThis causes the indicated autoloaded methods to be compiled up front, 47700Sstevel@tonic-gaterather than deferred to later. This is useful for scripts that run 47710Sstevel@tonic-gatefor an extended period of time under FastCGI or mod_perl, and for 4772*6287Sps156622those destined to be crunched by Malcolm Beattie's Perl compiler. Use 47730Sstevel@tonic-gateit in conjunction with the methods or method families you plan to use. 47740Sstevel@tonic-gate 47750Sstevel@tonic-gate use CGI qw(-compile :standard :html3); 47760Sstevel@tonic-gate 47770Sstevel@tonic-gateor even 47780Sstevel@tonic-gate 47790Sstevel@tonic-gate use CGI qw(-compile :all); 47800Sstevel@tonic-gate 47810Sstevel@tonic-gateNote that using the -compile pragma in this way will always have 47820Sstevel@tonic-gatethe effect of importing the compiled functions into the current 47830Sstevel@tonic-gatenamespace. If you want to compile without importing use the 47840Sstevel@tonic-gatecompile() method instead: 47850Sstevel@tonic-gate 47860Sstevel@tonic-gate use CGI(); 47870Sstevel@tonic-gate CGI->compile(); 47880Sstevel@tonic-gate 47890Sstevel@tonic-gateThis is particularly useful in a mod_perl environment, in which you 47900Sstevel@tonic-gatemight want to precompile all CGI routines in a startup script, and 47910Sstevel@tonic-gatethen import the functions individually in each mod_perl script. 47920Sstevel@tonic-gate 47930Sstevel@tonic-gate=item -nosticky 47940Sstevel@tonic-gate 4795667Sps156622By default the CGI module implements a state-preserving behavior 4796667Sps156622called "sticky" fields. The way this works is that if you are 4797667Sps156622regenerating a form, the methods that generate the form field values 4798667Sps156622will interrogate param() to see if similarly-named parameters are 4799667Sps156622present in the query string. If they find a like-named parameter, they 4800667Sps156622will use it to set their default values. 4801667Sps156622 4802667Sps156622Sometimes this isn't what you want. The B<-nosticky> pragma prevents 4803667Sps156622this behavior. You can also selectively change the sticky behavior in 4804667Sps156622each element that you generate. 48050Sstevel@tonic-gate 4806*6287Sps156622=item -tabindex 4807*6287Sps156622 4808*6287Sps156622Automatically add tab index attributes to each form field. With this 4809*6287Sps156622option turned off, you can still add tab indexes manually by passing a 4810*6287Sps156622-tabindex option to each field-generating method. 4811*6287Sps156622 48120Sstevel@tonic-gate=item -no_undef_params 48130Sstevel@tonic-gate 48140Sstevel@tonic-gateThis keeps CGI.pm from including undef params in the parameter list. 48150Sstevel@tonic-gate 48160Sstevel@tonic-gate=item -no_xhtml 48170Sstevel@tonic-gate 48180Sstevel@tonic-gateBy default, CGI.pm versions 2.69 and higher emit XHTML 48190Sstevel@tonic-gate(http://www.w3.org/TR/xhtml1/). The -no_xhtml pragma disables this 48200Sstevel@tonic-gatefeature. Thanks to Michalis Kabrianis <kabrianis@hellug.gr> for this 48210Sstevel@tonic-gatefeature. 48220Sstevel@tonic-gate 4823667Sps156622If start_html()'s -dtd parameter specifies an HTML 2.0 or 3.2 DTD, 4824667Sps156622XHTML will automatically be disabled without needing to use this 4825667Sps156622pragma. 4826667Sps156622 4827*6287Sps156622=item -utf8 4828*6287Sps156622 4829*6287Sps156622This makes CGI.pm treat all parameters as UTF-8 strings. Use this with 4830*6287Sps156622care, as it will interfere with the processing of binary uploads. It 4831*6287Sps156622is better to manually select which fields are expected to return utf-8 4832*6287Sps156622strings and convert them using code like this: 4833*6287Sps156622 4834*6287Sps156622 use Encode; 4835*6287Sps156622 my $arg = decode utf8=>param('foo'); 4836*6287Sps156622 48370Sstevel@tonic-gate=item -nph 48380Sstevel@tonic-gate 48390Sstevel@tonic-gateThis makes CGI.pm produce a header appropriate for an NPH (no 48400Sstevel@tonic-gateparsed header) script. You may need to do other things as well 48410Sstevel@tonic-gateto tell the server that the script is NPH. See the discussion 48420Sstevel@tonic-gateof NPH scripts below. 48430Sstevel@tonic-gate 48440Sstevel@tonic-gate=item -newstyle_urls 48450Sstevel@tonic-gate 48460Sstevel@tonic-gateSeparate the name=value pairs in CGI parameter query strings with 48470Sstevel@tonic-gatesemicolons rather than ampersands. For example: 48480Sstevel@tonic-gate 48490Sstevel@tonic-gate ?name=fred;age=24;favorite_color=3 48500Sstevel@tonic-gate 48510Sstevel@tonic-gateSemicolon-delimited query strings are always accepted, but will not be 48520Sstevel@tonic-gateemitted by self_url() and query_string() unless the -newstyle_urls 48530Sstevel@tonic-gatepragma is specified. 48540Sstevel@tonic-gate 48550Sstevel@tonic-gateThis became the default in version 2.64. 48560Sstevel@tonic-gate 48570Sstevel@tonic-gate=item -oldstyle_urls 48580Sstevel@tonic-gate 48590Sstevel@tonic-gateSeparate the name=value pairs in CGI parameter query strings with 48600Sstevel@tonic-gateampersands rather than semicolons. This is no longer the default. 48610Sstevel@tonic-gate 48620Sstevel@tonic-gate=item -autoload 48630Sstevel@tonic-gate 48640Sstevel@tonic-gateThis overrides the autoloader so that any function in your program 48650Sstevel@tonic-gatethat is not recognized is referred to CGI.pm for possible evaluation. 48660Sstevel@tonic-gateThis allows you to use all the CGI.pm functions without adding them to 48670Sstevel@tonic-gateyour symbol table, which is of concern for mod_perl users who are 48680Sstevel@tonic-gateworried about memory consumption. I<Warning:> when 48690Sstevel@tonic-gateI<-autoload> is in effect, you cannot use "poetry mode" 48700Sstevel@tonic-gate(functions without the parenthesis). Use I<hr()> rather 48710Sstevel@tonic-gatethan I<hr>, or add something like I<use subs qw/hr p header/> 48720Sstevel@tonic-gateto the top of your script. 48730Sstevel@tonic-gate 48740Sstevel@tonic-gate=item -no_debug 48750Sstevel@tonic-gate 48760Sstevel@tonic-gateThis turns off the command-line processing features. If you want to 48770Sstevel@tonic-gaterun a CGI.pm script from the command line to produce HTML, and you 48780Sstevel@tonic-gatedon't want it to read CGI parameters from the command line or STDIN, 48790Sstevel@tonic-gatethen use this pragma: 48800Sstevel@tonic-gate 48810Sstevel@tonic-gate use CGI qw(-no_debug :standard); 48820Sstevel@tonic-gate 48830Sstevel@tonic-gate=item -debug 48840Sstevel@tonic-gate 48850Sstevel@tonic-gateThis turns on full debugging. In addition to reading CGI arguments 48860Sstevel@tonic-gatefrom the command-line processing, CGI.pm will pause and try to read 48870Sstevel@tonic-gatearguments from STDIN, producing the message "(offline mode: enter 48880Sstevel@tonic-gatename=value pairs on standard input)" features. 48890Sstevel@tonic-gate 48900Sstevel@tonic-gateSee the section on debugging for more details. 48910Sstevel@tonic-gate 48920Sstevel@tonic-gate=item -private_tempfiles 48930Sstevel@tonic-gate 48940Sstevel@tonic-gateCGI.pm can process uploaded file. Ordinarily it spools the uploaded 48950Sstevel@tonic-gatefile to a temporary directory, then deletes the file when done. 48960Sstevel@tonic-gateHowever, this opens the risk of eavesdropping as described in the file 48970Sstevel@tonic-gateupload section. Another CGI script author could peek at this data 48980Sstevel@tonic-gateduring the upload, even if it is confidential information. On Unix 48990Sstevel@tonic-gatesystems, the -private_tempfiles pragma will cause the temporary file 49000Sstevel@tonic-gateto be unlinked as soon as it is opened and before any data is written 49010Sstevel@tonic-gateinto it, reducing, but not eliminating the risk of eavesdropping 49020Sstevel@tonic-gate(there is still a potential race condition). To make life harder for 49030Sstevel@tonic-gatethe attacker, the program chooses tempfile names by calculating a 32 49040Sstevel@tonic-gatebit checksum of the incoming HTTP headers. 49050Sstevel@tonic-gate 49060Sstevel@tonic-gateTo ensure that the temporary file cannot be read by other CGI scripts, 49070Sstevel@tonic-gateuse suEXEC or a CGI wrapper program to run your script. The temporary 49080Sstevel@tonic-gatefile is created with mode 0600 (neither world nor group readable). 49090Sstevel@tonic-gate 49100Sstevel@tonic-gateThe temporary directory is selected using the following algorithm: 49110Sstevel@tonic-gate 49120Sstevel@tonic-gate 1. if the current user (e.g. "nobody") has a directory named 49130Sstevel@tonic-gate "tmp" in its home directory, use that (Unix systems only). 49140Sstevel@tonic-gate 49150Sstevel@tonic-gate 2. if the environment variable TMPDIR exists, use the location 49160Sstevel@tonic-gate indicated. 49170Sstevel@tonic-gate 49180Sstevel@tonic-gate 3. Otherwise try the locations /usr/tmp, /var/tmp, C:\temp, 49190Sstevel@tonic-gate /tmp, /temp, ::Temporary Items, and \WWW_ROOT. 49200Sstevel@tonic-gate 49210Sstevel@tonic-gateEach of these locations is checked that it is a directory and is 49220Sstevel@tonic-gatewritable. If not, the algorithm tries the next choice. 49230Sstevel@tonic-gate 49240Sstevel@tonic-gate=back 49250Sstevel@tonic-gate 49260Sstevel@tonic-gate=head2 SPECIAL FORMS FOR IMPORTING HTML-TAG FUNCTIONS 49270Sstevel@tonic-gate 49280Sstevel@tonic-gateMany of the methods generate HTML tags. As described below, tag 49290Sstevel@tonic-gatefunctions automatically generate both the opening and closing tags. 49300Sstevel@tonic-gateFor example: 49310Sstevel@tonic-gate 49320Sstevel@tonic-gate print h1('Level 1 Header'); 49330Sstevel@tonic-gate 49340Sstevel@tonic-gateproduces 49350Sstevel@tonic-gate 49360Sstevel@tonic-gate <h1>Level 1 Header</h1> 49370Sstevel@tonic-gate 49380Sstevel@tonic-gateThere will be some times when you want to produce the start and end 49390Sstevel@tonic-gatetags yourself. In this case, you can use the form start_I<tag_name> 49400Sstevel@tonic-gateand end_I<tag_name>, as in: 49410Sstevel@tonic-gate 49420Sstevel@tonic-gate print start_h1,'Level 1 Header',end_h1; 49430Sstevel@tonic-gate 49440Sstevel@tonic-gateWith a few exceptions (described below), start_I<tag_name> and 49450Sstevel@tonic-gateend_I<tag_name> functions are not generated automatically when you 49460Sstevel@tonic-gateI<use CGI>. However, you can specify the tags you want to generate 49470Sstevel@tonic-gateI<start/end> functions for by putting an asterisk in front of their 49480Sstevel@tonic-gatename, or, alternatively, requesting either "start_I<tag_name>" or 49490Sstevel@tonic-gate"end_I<tag_name>" in the import list. 49500Sstevel@tonic-gate 49510Sstevel@tonic-gateExample: 49520Sstevel@tonic-gate 49530Sstevel@tonic-gate use CGI qw/:standard *table start_ul/; 49540Sstevel@tonic-gate 49550Sstevel@tonic-gateIn this example, the following functions are generated in addition to 49560Sstevel@tonic-gatethe standard ones: 49570Sstevel@tonic-gate 49580Sstevel@tonic-gate=over 4 49590Sstevel@tonic-gate 49600Sstevel@tonic-gate=item 1. start_table() (generates a <table> tag) 49610Sstevel@tonic-gate 49620Sstevel@tonic-gate=item 2. end_table() (generates a </table> tag) 49630Sstevel@tonic-gate 49640Sstevel@tonic-gate=item 3. start_ul() (generates a <ul> tag) 49650Sstevel@tonic-gate 49660Sstevel@tonic-gate=item 4. end_ul() (generates a </ul> tag) 49670Sstevel@tonic-gate 49680Sstevel@tonic-gate=back 49690Sstevel@tonic-gate 49700Sstevel@tonic-gate=head1 GENERATING DYNAMIC DOCUMENTS 49710Sstevel@tonic-gate 49720Sstevel@tonic-gateMost of CGI.pm's functions deal with creating documents on the fly. 49730Sstevel@tonic-gateGenerally you will produce the HTTP header first, followed by the 49740Sstevel@tonic-gatedocument itself. CGI.pm provides functions for generating HTTP 49750Sstevel@tonic-gateheaders of various types as well as for generating HTML. For creating 49760Sstevel@tonic-gateGIF images, see the GD.pm module. 49770Sstevel@tonic-gate 49780Sstevel@tonic-gateEach of these functions produces a fragment of HTML or HTTP which you 49790Sstevel@tonic-gatecan print out directly so that it displays in the browser window, 49800Sstevel@tonic-gateappend to a string, or save to a file for later use. 49810Sstevel@tonic-gate 49820Sstevel@tonic-gate=head2 CREATING A STANDARD HTTP HEADER: 49830Sstevel@tonic-gate 49840Sstevel@tonic-gateNormally the first thing you will do in any CGI script is print out an 49850Sstevel@tonic-gateHTTP header. This tells the browser what type of document to expect, 49860Sstevel@tonic-gateand gives other optional information, such as the language, expiration 49870Sstevel@tonic-gatedate, and whether to cache the document. The header can also be 49880Sstevel@tonic-gatemanipulated for special purposes, such as server push and pay per view 49890Sstevel@tonic-gatepages. 49900Sstevel@tonic-gate 4991667Sps156622 print header; 49920Sstevel@tonic-gate 49930Sstevel@tonic-gate -or- 49940Sstevel@tonic-gate 4995667Sps156622 print header('image/gif'); 49960Sstevel@tonic-gate 49970Sstevel@tonic-gate -or- 49980Sstevel@tonic-gate 4999667Sps156622 print header('text/html','204 No response'); 50000Sstevel@tonic-gate 50010Sstevel@tonic-gate -or- 50020Sstevel@tonic-gate 5003667Sps156622 print header(-type=>'image/gif', 50040Sstevel@tonic-gate -nph=>1, 50050Sstevel@tonic-gate -status=>'402 Payment required', 50060Sstevel@tonic-gate -expires=>'+3d', 50070Sstevel@tonic-gate -cookie=>$cookie, 50080Sstevel@tonic-gate -charset=>'utf-7', 50090Sstevel@tonic-gate -attachment=>'foo.gif', 50100Sstevel@tonic-gate -Cost=>'$2.00'); 50110Sstevel@tonic-gate 50120Sstevel@tonic-gateheader() returns the Content-type: header. You can provide your own 50130Sstevel@tonic-gateMIME type if you choose, otherwise it defaults to text/html. An 50140Sstevel@tonic-gateoptional second parameter specifies the status code and a human-readable 50150Sstevel@tonic-gatemessage. For example, you can specify 204, "No response" to create a 50160Sstevel@tonic-gatescript that tells the browser to do nothing at all. 50170Sstevel@tonic-gate 50180Sstevel@tonic-gateThe last example shows the named argument style for passing arguments 50190Sstevel@tonic-gateto the CGI methods using named parameters. Recognized parameters are 50200Sstevel@tonic-gateB<-type>, B<-status>, B<-expires>, and B<-cookie>. Any other named 50210Sstevel@tonic-gateparameters will be stripped of their initial hyphens and turned into 50220Sstevel@tonic-gateheader fields, allowing you to specify any HTTP header you desire. 50230Sstevel@tonic-gateInternal underscores will be turned into hyphens: 50240Sstevel@tonic-gate 5025667Sps156622 print header(-Content_length=>3002); 50260Sstevel@tonic-gate 50270Sstevel@tonic-gateMost browsers will not cache the output from CGI scripts. Every time 50280Sstevel@tonic-gatethe browser reloads the page, the script is invoked anew. You can 50290Sstevel@tonic-gatechange this behavior with the B<-expires> parameter. When you specify 50300Sstevel@tonic-gatean absolute or relative expiration interval with this parameter, some 50310Sstevel@tonic-gatebrowsers and proxy servers will cache the script's output until the 50320Sstevel@tonic-gateindicated expiration date. The following forms are all valid for the 50330Sstevel@tonic-gate-expires field: 50340Sstevel@tonic-gate 50350Sstevel@tonic-gate +30s 30 seconds from now 50360Sstevel@tonic-gate +10m ten minutes from now 50370Sstevel@tonic-gate +1h one hour from now 50380Sstevel@tonic-gate -1d yesterday (i.e. "ASAP!") 50390Sstevel@tonic-gate now immediately 50400Sstevel@tonic-gate +3M in three months 50410Sstevel@tonic-gate +10y in ten years time 50420Sstevel@tonic-gate Thursday, 25-Apr-1999 00:40:33 GMT at the indicated time & date 50430Sstevel@tonic-gate 50440Sstevel@tonic-gateThe B<-cookie> parameter generates a header that tells the browser to provide 50450Sstevel@tonic-gatea "magic cookie" during all subsequent transactions with your script. 50460Sstevel@tonic-gateNetscape cookies have a special format that includes interesting attributes 50470Sstevel@tonic-gatesuch as expiration time. Use the cookie() method to create and retrieve 50480Sstevel@tonic-gatesession cookies. 50490Sstevel@tonic-gate 50500Sstevel@tonic-gateThe B<-nph> parameter, if set to a true value, will issue the correct 50510Sstevel@tonic-gateheaders to work with a NPH (no-parse-header) script. This is important 50520Sstevel@tonic-gateto use with certain servers that expect all their scripts to be NPH. 50530Sstevel@tonic-gate 50540Sstevel@tonic-gateThe B<-charset> parameter can be used to control the character set 50550Sstevel@tonic-gatesent to the browser. If not provided, defaults to ISO-8859-1. As a 50560Sstevel@tonic-gateside effect, this sets the charset() method as well. 50570Sstevel@tonic-gate 50580Sstevel@tonic-gateThe B<-attachment> parameter can be used to turn the page into an 50590Sstevel@tonic-gateattachment. Instead of displaying the page, some browsers will prompt 50600Sstevel@tonic-gatethe user to save it to disk. The value of the argument is the 50610Sstevel@tonic-gatesuggested name for the saved file. In order for this to work, you may 50620Sstevel@tonic-gatehave to set the B<-type> to "application/octet-stream". 50630Sstevel@tonic-gate 50640Sstevel@tonic-gateThe B<-p3p> parameter will add a P3P tag to the outgoing header. The 50650Sstevel@tonic-gateparameter can be an arrayref or a space-delimited string of P3P tags. 50660Sstevel@tonic-gateFor example: 50670Sstevel@tonic-gate 50680Sstevel@tonic-gate print header(-p3p=>[qw(CAO DSP LAW CURa)]); 50690Sstevel@tonic-gate print header(-p3p=>'CAO DSP LAW CURa'); 50700Sstevel@tonic-gate 50710Sstevel@tonic-gateIn either case, the outgoing header will be formatted as: 50720Sstevel@tonic-gate 50730Sstevel@tonic-gate P3P: policyref="/w3c/p3p.xml" cp="CAO DSP LAW CURa" 50740Sstevel@tonic-gate 50750Sstevel@tonic-gate=head2 GENERATING A REDIRECTION HEADER 50760Sstevel@tonic-gate 5077667Sps156622 print redirect('http://somewhere.else/in/movie/land'); 50780Sstevel@tonic-gate 50790Sstevel@tonic-gateSometimes you don't want to produce a document yourself, but simply 50800Sstevel@tonic-gateredirect the browser elsewhere, perhaps choosing a URL based on the 50810Sstevel@tonic-gatetime of day or the identity of the user. 50820Sstevel@tonic-gate 50830Sstevel@tonic-gateThe redirect() function redirects the browser to a different URL. If 50840Sstevel@tonic-gateyou use redirection like this, you should B<not> print out a header as 50850Sstevel@tonic-gatewell. 50860Sstevel@tonic-gate 50870Sstevel@tonic-gateYou should always use full URLs (including the http: or ftp: part) in 50880Sstevel@tonic-gateredirection requests. Relative URLs will not work correctly. 50890Sstevel@tonic-gate 50900Sstevel@tonic-gateYou can also use named arguments: 50910Sstevel@tonic-gate 5092667Sps156622 print redirect(-uri=>'http://somewhere.else/in/movie/land', 5093667Sps156622 -nph=>1, 5094667Sps156622 -status=>301); 50950Sstevel@tonic-gate 50960Sstevel@tonic-gateThe B<-nph> parameter, if set to a true value, will issue the correct 50970Sstevel@tonic-gateheaders to work with a NPH (no-parse-header) script. This is important 50980Sstevel@tonic-gateto use with certain servers, such as Microsoft IIS, which 50990Sstevel@tonic-gateexpect all their scripts to be NPH. 51000Sstevel@tonic-gate 5101667Sps156622The B<-status> parameter will set the status of the redirect. HTTP 5102667Sps156622defines three different possible redirection status codes: 5103667Sps156622 5104667Sps156622 301 Moved Permanently 5105667Sps156622 302 Found 5106667Sps156622 303 See Other 5107667Sps156622 5108667Sps156622The default if not specified is 302, which means "moved temporarily." 5109667Sps156622You may change the status to another status code if you wish. Be 5110667Sps156622advised that changing the status to anything other than 301, 302 or 5111667Sps156622303 will probably break redirection. 5112667Sps156622 51130Sstevel@tonic-gate=head2 CREATING THE HTML DOCUMENT HEADER 51140Sstevel@tonic-gate 5115667Sps156622 print start_html(-title=>'Secrets of the Pyramids', 51160Sstevel@tonic-gate -author=>'fred@capricorn.org', 51170Sstevel@tonic-gate -base=>'true', 51180Sstevel@tonic-gate -target=>'_blank', 51190Sstevel@tonic-gate -meta=>{'keywords'=>'pharaoh secret mummy', 51200Sstevel@tonic-gate 'copyright'=>'copyright 1996 King Tut'}, 51210Sstevel@tonic-gate -style=>{'src'=>'/styles/style1.css'}, 51220Sstevel@tonic-gate -BGCOLOR=>'blue'); 51230Sstevel@tonic-gate 51240Sstevel@tonic-gateAfter creating the HTTP header, most CGI scripts will start writing 51250Sstevel@tonic-gateout an HTML document. The start_html() routine creates the top of the 51260Sstevel@tonic-gatepage, along with a lot of optional information that controls the 51270Sstevel@tonic-gatepage's appearance and behavior. 51280Sstevel@tonic-gate 51290Sstevel@tonic-gateThis method returns a canned HTML header and the opening <body> tag. 51300Sstevel@tonic-gateAll parameters are optional. In the named parameter form, recognized 51310Sstevel@tonic-gateparameters are -title, -author, -base, -xbase, -dtd, -lang and -target 51320Sstevel@tonic-gate(see below for the explanation). Any additional parameters you 51330Sstevel@tonic-gateprovide, such as the Netscape unofficial BGCOLOR attribute, are added 51340Sstevel@tonic-gateto the <body> tag. Additional parameters must be proceeded by a 51350Sstevel@tonic-gatehyphen. 51360Sstevel@tonic-gate 51370Sstevel@tonic-gateThe argument B<-xbase> allows you to provide an HREF for the <base> tag 51380Sstevel@tonic-gatedifferent from the current location, as in 51390Sstevel@tonic-gate 51400Sstevel@tonic-gate -xbase=>"http://home.mcom.com/" 51410Sstevel@tonic-gate 51420Sstevel@tonic-gateAll relative links will be interpreted relative to this tag. 51430Sstevel@tonic-gate 51440Sstevel@tonic-gateThe argument B<-target> allows you to provide a default target frame 51450Sstevel@tonic-gatefor all the links and fill-out forms on the page. B<This is a 51460Sstevel@tonic-gatenon-standard HTTP feature which only works with Netscape browsers!> 51470Sstevel@tonic-gateSee the Netscape documentation on frames for details of how to 51480Sstevel@tonic-gatemanipulate this. 51490Sstevel@tonic-gate 51500Sstevel@tonic-gate -target=>"answer_window" 51510Sstevel@tonic-gate 51520Sstevel@tonic-gateAll relative links will be interpreted relative to this tag. 51530Sstevel@tonic-gateYou add arbitrary meta information to the header with the B<-meta> 51540Sstevel@tonic-gateargument. This argument expects a reference to an associative array 51550Sstevel@tonic-gatecontaining name/value pairs of meta information. These will be turned 51560Sstevel@tonic-gateinto a series of header <meta> tags that look something like this: 51570Sstevel@tonic-gate 51580Sstevel@tonic-gate <meta name="keywords" content="pharaoh secret mummy"> 51590Sstevel@tonic-gate <meta name="description" content="copyright 1996 King Tut"> 51600Sstevel@tonic-gate 51610Sstevel@tonic-gateTo create an HTTP-EQUIV type of <meta> tag, use B<-head>, described 51620Sstevel@tonic-gatebelow. 51630Sstevel@tonic-gate 51640Sstevel@tonic-gateThe B<-style> argument is used to incorporate cascading stylesheets 51650Sstevel@tonic-gateinto your code. See the section on CASCADING STYLESHEETS for more 51660Sstevel@tonic-gateinformation. 51670Sstevel@tonic-gate 51680Sstevel@tonic-gateThe B<-lang> argument is used to incorporate a language attribute into 5169667Sps156622the <html> tag. For example: 51700Sstevel@tonic-gate 51710Sstevel@tonic-gate print $q->start_html(-lang=>'fr-CA'); 51720Sstevel@tonic-gate 5173667Sps156622The default if not specified is "en-US" for US English, unless the 5174667Sps156622-dtd parameter specifies an HTML 2.0 or 3.2 DTD, in which case the 5175667Sps156622lang attribute is left off. You can force the lang attribute to left 5176667Sps156622off in other cases by passing an empty string (-lang=>''). 51770Sstevel@tonic-gate 51780Sstevel@tonic-gateThe B<-encoding> argument can be used to specify the character set for 51790Sstevel@tonic-gateXHTML. It defaults to iso-8859-1 if not specified. 51800Sstevel@tonic-gate 5181667Sps156622The B<-declare_xml> argument, when used in conjunction with XHTML, 5182667Sps156622will put a <?xml> declaration at the top of the HTML header. The sole 5183667Sps156622purpose of this declaration is to declare the character set 5184667Sps156622encoding. In the absence of -declare_xml, the output HTML will contain 5185667Sps156622a <meta> tag that specifies the encoding, allowing the HTML to pass 5186667Sps156622most validators. The default for -declare_xml is false. 5187667Sps156622 51880Sstevel@tonic-gateYou can place other arbitrary HTML elements to the <head> section with the 51890Sstevel@tonic-gateB<-head> tag. For example, to place the rarely-used <link> element in the 51900Sstevel@tonic-gatehead section, use this: 51910Sstevel@tonic-gate 51920Sstevel@tonic-gate print start_html(-head=>Link({-rel=>'next', 51930Sstevel@tonic-gate -href=>'http://www.capricorn.com/s2.html'})); 51940Sstevel@tonic-gate 51950Sstevel@tonic-gateTo incorporate multiple HTML elements into the <head> section, just pass an 51960Sstevel@tonic-gatearray reference: 51970Sstevel@tonic-gate 51980Sstevel@tonic-gate print start_html(-head=>[ 51990Sstevel@tonic-gate Link({-rel=>'next', 52000Sstevel@tonic-gate -href=>'http://www.capricorn.com/s2.html'}), 52010Sstevel@tonic-gate Link({-rel=>'previous', 52020Sstevel@tonic-gate -href=>'http://www.capricorn.com/s1.html'}) 52030Sstevel@tonic-gate ] 52040Sstevel@tonic-gate ); 52050Sstevel@tonic-gate 52060Sstevel@tonic-gateAnd here's how to create an HTTP-EQUIV <meta> tag: 52070Sstevel@tonic-gate 52080Sstevel@tonic-gate print start_html(-head=>meta({-http_equiv => 'Content-Type', 52090Sstevel@tonic-gate -content => 'text/html'})) 52100Sstevel@tonic-gate 52110Sstevel@tonic-gate 52120Sstevel@tonic-gateJAVASCRIPTING: The B<-script>, B<-noScript>, B<-onLoad>, 52130Sstevel@tonic-gateB<-onMouseOver>, B<-onMouseOut> and B<-onUnload> parameters are used 52140Sstevel@tonic-gateto add Netscape JavaScript calls to your pages. B<-script> should 52150Sstevel@tonic-gatepoint to a block of text containing JavaScript function definitions. 52160Sstevel@tonic-gateThis block will be placed within a <script> block inside the HTML (not 52170Sstevel@tonic-gateHTTP) header. The block is placed in the header in order to give your 52180Sstevel@tonic-gatepage a fighting chance of having all its JavaScript functions in place 52190Sstevel@tonic-gateeven if the user presses the stop button before the page has loaded 52200Sstevel@tonic-gatecompletely. CGI.pm attempts to format the script in such a way that 52210Sstevel@tonic-gateJavaScript-naive browsers will not choke on the code: unfortunately 52220Sstevel@tonic-gatethere are some browsers, such as Chimera for Unix, that get confused 52230Sstevel@tonic-gateby it nevertheless. 52240Sstevel@tonic-gate 52250Sstevel@tonic-gateThe B<-onLoad> and B<-onUnload> parameters point to fragments of JavaScript 52260Sstevel@tonic-gatecode to execute when the page is respectively opened and closed by the 52270Sstevel@tonic-gatebrowser. Usually these parameters are calls to functions defined in the 52280Sstevel@tonic-gateB<-script> field: 52290Sstevel@tonic-gate 52300Sstevel@tonic-gate $query = new CGI; 5231667Sps156622 print header; 52320Sstevel@tonic-gate $JSCRIPT=<<END; 52330Sstevel@tonic-gate // Ask a silly question 52340Sstevel@tonic-gate function riddle_me_this() { 52350Sstevel@tonic-gate var r = prompt("What walks on four legs in the morning, " + 52360Sstevel@tonic-gate "two legs in the afternoon, " + 52370Sstevel@tonic-gate "and three legs in the evening?"); 52380Sstevel@tonic-gate response(r); 52390Sstevel@tonic-gate } 52400Sstevel@tonic-gate // Get a silly answer 52410Sstevel@tonic-gate function response(answer) { 52420Sstevel@tonic-gate if (answer == "man") 52430Sstevel@tonic-gate alert("Right you are!"); 52440Sstevel@tonic-gate else 52450Sstevel@tonic-gate alert("Wrong! Guess again."); 52460Sstevel@tonic-gate } 52470Sstevel@tonic-gate END 5248667Sps156622 print start_html(-title=>'The Riddle of the Sphinx', 52490Sstevel@tonic-gate -script=>$JSCRIPT); 52500Sstevel@tonic-gate 52510Sstevel@tonic-gateUse the B<-noScript> parameter to pass some HTML text that will be displayed on 52520Sstevel@tonic-gatebrowsers that do not have JavaScript (or browsers where JavaScript is turned 52530Sstevel@tonic-gateoff). 52540Sstevel@tonic-gate 5255*6287Sps156622The <script> tag, has several attributes including "type" and src. 5256*6287Sps156622The latter is particularly interesting, as it allows you to keep the 5257*6287Sps156622JavaScript code in a file or CGI script rather than cluttering up each 5258*6287Sps156622page with the source. To use these attributes pass a HASH reference 5259*6287Sps156622in the B<-script> parameter containing one or more of -type, -src, or 5260*6287Sps156622-code: 52610Sstevel@tonic-gate 52620Sstevel@tonic-gate print $q->start_html(-title=>'The Riddle of the Sphinx', 5263*6287Sps156622 -script=>{-type=>'JAVASCRIPT', 52640Sstevel@tonic-gate -src=>'/javascript/sphinx.js'} 52650Sstevel@tonic-gate ); 52660Sstevel@tonic-gate 52670Sstevel@tonic-gate print $q->(-title=>'The Riddle of the Sphinx', 5268*6287Sps156622 -script=>{-type=>'PERLSCRIPT', 52690Sstevel@tonic-gate -code=>'print "hello world!\n;"'} 52700Sstevel@tonic-gate ); 52710Sstevel@tonic-gate 52720Sstevel@tonic-gate 52730Sstevel@tonic-gateA final feature allows you to incorporate multiple <script> sections into the 52740Sstevel@tonic-gateheader. Just pass the list of script sections as an array reference. 52750Sstevel@tonic-gatethis allows you to specify different source files for different dialects 5276*6287Sps156622of JavaScript. Example: 52770Sstevel@tonic-gate 52780Sstevel@tonic-gate print $q->start_html(-title=>'The Riddle of the Sphinx', 52790Sstevel@tonic-gate -script=>[ 5280*6287Sps156622 { -type => 'text/javascript', 52810Sstevel@tonic-gate -src => '/javascript/utilities10.js' 52820Sstevel@tonic-gate }, 5283*6287Sps156622 { -type => 'text/javascript', 52840Sstevel@tonic-gate -src => '/javascript/utilities11.js' 52850Sstevel@tonic-gate }, 5286*6287Sps156622 { -type => 'text/jscript', 52870Sstevel@tonic-gate -src => '/javascript/utilities12.js' 52880Sstevel@tonic-gate }, 5289*6287Sps156622 { -type => 'text/ecmascript', 52900Sstevel@tonic-gate -src => '/javascript/utilities219.js' 52910Sstevel@tonic-gate } 52920Sstevel@tonic-gate ] 52930Sstevel@tonic-gate ); 52940Sstevel@tonic-gate 5295*6287Sps156622The option "-language" is a synonym for -type, and is supported for 5296*6287Sps156622backwad compatibility. 52970Sstevel@tonic-gate 52980Sstevel@tonic-gateThe old-style positional parameters are as follows: 52990Sstevel@tonic-gate 53000Sstevel@tonic-gate=over 4 53010Sstevel@tonic-gate 53020Sstevel@tonic-gate=item B<Parameters:> 53030Sstevel@tonic-gate 53040Sstevel@tonic-gate=item 1. 53050Sstevel@tonic-gate 53060Sstevel@tonic-gateThe title 53070Sstevel@tonic-gate 53080Sstevel@tonic-gate=item 2. 53090Sstevel@tonic-gate 53100Sstevel@tonic-gateThe author's e-mail address (will create a <link rev="MADE"> tag if present 53110Sstevel@tonic-gate 53120Sstevel@tonic-gate=item 3. 53130Sstevel@tonic-gate 53140Sstevel@tonic-gateA 'true' flag if you want to include a <base> tag in the header. This 53150Sstevel@tonic-gatehelps resolve relative addresses to absolute ones when the document is moved, 53160Sstevel@tonic-gatebut makes the document hierarchy non-portable. Use with care! 53170Sstevel@tonic-gate 53180Sstevel@tonic-gate=item 4, 5, 6... 53190Sstevel@tonic-gate 53200Sstevel@tonic-gateAny other parameters you want to include in the <body> tag. This is a good 53210Sstevel@tonic-gateplace to put Netscape extensions, such as colors and wallpaper patterns. 53220Sstevel@tonic-gate 53230Sstevel@tonic-gate=back 53240Sstevel@tonic-gate 53250Sstevel@tonic-gate=head2 ENDING THE HTML DOCUMENT: 53260Sstevel@tonic-gate 5327667Sps156622 print end_html 53280Sstevel@tonic-gate 53290Sstevel@tonic-gateThis ends an HTML document by printing the </body></html> tags. 53300Sstevel@tonic-gate 53310Sstevel@tonic-gate=head2 CREATING A SELF-REFERENCING URL THAT PRESERVES STATE INFORMATION: 53320Sstevel@tonic-gate 5333667Sps156622 $myself = self_url; 53340Sstevel@tonic-gate print q(<a href="$myself">I'm talking to myself.</a>); 53350Sstevel@tonic-gate 53360Sstevel@tonic-gateself_url() will return a URL, that, when selected, will reinvoke 53370Sstevel@tonic-gatethis script with all its state information intact. This is most 53380Sstevel@tonic-gateuseful when you want to jump around within the document using 53390Sstevel@tonic-gateinternal anchors but you don't want to disrupt the current contents 53400Sstevel@tonic-gateof the form(s). Something like this will do the trick. 53410Sstevel@tonic-gate 5342667Sps156622 $myself = self_url; 53430Sstevel@tonic-gate print "<a href=\"$myself#table1\">See table 1</a>"; 53440Sstevel@tonic-gate print "<a href=\"$myself#table2\">See table 2</a>"; 53450Sstevel@tonic-gate print "<a href=\"$myself#yourself\">See for yourself</a>"; 53460Sstevel@tonic-gate 53470Sstevel@tonic-gateIf you want more control over what's returned, using the B<url()> 53480Sstevel@tonic-gatemethod instead. 53490Sstevel@tonic-gate 53500Sstevel@tonic-gateYou can also retrieve the unprocessed query string with query_string(): 53510Sstevel@tonic-gate 5352667Sps156622 $the_string = query_string; 53530Sstevel@tonic-gate 53540Sstevel@tonic-gate=head2 OBTAINING THE SCRIPT'S URL 53550Sstevel@tonic-gate 5356667Sps156622 $full_url = url(); 5357667Sps156622 $full_url = url(-full=>1); #alternative syntax 5358667Sps156622 $relative_url = url(-relative=>1); 5359667Sps156622 $absolute_url = url(-absolute=>1); 5360667Sps156622 $url_with_path = url(-path_info=>1); 5361667Sps156622 $url_with_path_and_query = url(-path_info=>1,-query=>1); 5362667Sps156622 $netloc = url(-base => 1); 53630Sstevel@tonic-gate 53640Sstevel@tonic-gateB<url()> returns the script's URL in a variety of formats. Called 53650Sstevel@tonic-gatewithout any arguments, it returns the full form of the URL, including 53660Sstevel@tonic-gatehost name and port number 53670Sstevel@tonic-gate 53680Sstevel@tonic-gate http://your.host.com/path/to/script.cgi 53690Sstevel@tonic-gate 53700Sstevel@tonic-gateYou can modify this format with the following named arguments: 53710Sstevel@tonic-gate 53720Sstevel@tonic-gate=over 4 53730Sstevel@tonic-gate 53740Sstevel@tonic-gate=item B<-absolute> 53750Sstevel@tonic-gate 53760Sstevel@tonic-gateIf true, produce an absolute URL, e.g. 53770Sstevel@tonic-gate 53780Sstevel@tonic-gate /path/to/script.cgi 53790Sstevel@tonic-gate 53800Sstevel@tonic-gate=item B<-relative> 53810Sstevel@tonic-gate 53820Sstevel@tonic-gateProduce a relative URL. This is useful if you want to reinvoke your 53830Sstevel@tonic-gatescript with different parameters. For example: 53840Sstevel@tonic-gate 53850Sstevel@tonic-gate script.cgi 53860Sstevel@tonic-gate 53870Sstevel@tonic-gate=item B<-full> 53880Sstevel@tonic-gate 53890Sstevel@tonic-gateProduce the full URL, exactly as if called without any arguments. 53900Sstevel@tonic-gateThis overrides the -relative and -absolute arguments. 53910Sstevel@tonic-gate 53920Sstevel@tonic-gate=item B<-path> (B<-path_info>) 53930Sstevel@tonic-gate 53940Sstevel@tonic-gateAppend the additional path information to the URL. This can be 53950Sstevel@tonic-gatecombined with B<-full>, B<-absolute> or B<-relative>. B<-path_info> 53960Sstevel@tonic-gateis provided as a synonym. 53970Sstevel@tonic-gate 53980Sstevel@tonic-gate=item B<-query> (B<-query_string>) 53990Sstevel@tonic-gate 54000Sstevel@tonic-gateAppend the query string to the URL. This can be combined with 54010Sstevel@tonic-gateB<-full>, B<-absolute> or B<-relative>. B<-query_string> is provided 54020Sstevel@tonic-gateas a synonym. 54030Sstevel@tonic-gate 54040Sstevel@tonic-gate=item B<-base> 54050Sstevel@tonic-gate 54060Sstevel@tonic-gateGenerate just the protocol and net location, as in http://www.foo.com:8000 54070Sstevel@tonic-gate 5408*6287Sps156622=item B<-rewrite> 5409*6287Sps156622 5410*6287Sps156622If Apache's mod_rewrite is turned on, then the script name and path 5411*6287Sps156622info probably won't match the request that the user sent. Set 5412*6287Sps156622-rewrite=>1 (default) to return URLs that match what the user sent 5413*6287Sps156622(the original request URI). Set -rewrite->0 to return URLs that match 5414*6287Sps156622the URL after mod_rewrite's rules have run. Because the additional 5415*6287Sps156622path information only makes sense in the context of the rewritten URL, 5416*6287Sps156622-rewrite is set to false when you request path info in the URL. 5417*6287Sps156622 54180Sstevel@tonic-gate=back 54190Sstevel@tonic-gate 54200Sstevel@tonic-gate=head2 MIXING POST AND URL PARAMETERS 54210Sstevel@tonic-gate 5422667Sps156622 $color = url_param('color'); 54230Sstevel@tonic-gate 54240Sstevel@tonic-gateIt is possible for a script to receive CGI parameters in the URL as 54250Sstevel@tonic-gatewell as in the fill-out form by creating a form that POSTs to a URL 54260Sstevel@tonic-gatecontaining a query string (a "?" mark followed by arguments). The 54270Sstevel@tonic-gateB<param()> method will always return the contents of the POSTed 54280Sstevel@tonic-gatefill-out form, ignoring the URL's query string. To retrieve URL 54290Sstevel@tonic-gateparameters, call the B<url_param()> method. Use it in the same way as 54300Sstevel@tonic-gateB<param()>. The main difference is that it allows you to read the 54310Sstevel@tonic-gateparameters, but not set them. 54320Sstevel@tonic-gate 54330Sstevel@tonic-gate 54340Sstevel@tonic-gateUnder no circumstances will the contents of the URL query string 54350Sstevel@tonic-gateinterfere with similarly-named CGI parameters in POSTed forms. If you 54360Sstevel@tonic-gatetry to mix a URL query string with a form submitted with the GET 54370Sstevel@tonic-gatemethod, the results will not be what you expect. 54380Sstevel@tonic-gate 54390Sstevel@tonic-gate=head1 CREATING STANDARD HTML ELEMENTS: 54400Sstevel@tonic-gate 54410Sstevel@tonic-gateCGI.pm defines general HTML shortcut methods for most, if not all of 54420Sstevel@tonic-gatethe HTML 3 and HTML 4 tags. HTML shortcuts are named after a single 54430Sstevel@tonic-gateHTML element and return a fragment of HTML text that you can then 54440Sstevel@tonic-gateprint or manipulate as you like. Each shortcut returns a fragment of 54450Sstevel@tonic-gateHTML code that you can append to a string, save to a file, or, most 54460Sstevel@tonic-gatecommonly, print out so that it displays in the browser window. 54470Sstevel@tonic-gate 54480Sstevel@tonic-gateThis example shows how to use the HTML methods: 54490Sstevel@tonic-gate 54500Sstevel@tonic-gate print $q->blockquote( 54510Sstevel@tonic-gate "Many years ago on the island of", 54520Sstevel@tonic-gate $q->a({href=>"http://crete.org/"},"Crete"), 54530Sstevel@tonic-gate "there lived a Minotaur named", 54540Sstevel@tonic-gate $q->strong("Fred."), 54550Sstevel@tonic-gate ), 54560Sstevel@tonic-gate $q->hr; 54570Sstevel@tonic-gate 54580Sstevel@tonic-gateThis results in the following HTML code (extra newlines have been 54590Sstevel@tonic-gateadded for readability): 54600Sstevel@tonic-gate 54610Sstevel@tonic-gate <blockquote> 54620Sstevel@tonic-gate Many years ago on the island of 54630Sstevel@tonic-gate <a href="http://crete.org/">Crete</a> there lived 54640Sstevel@tonic-gate a minotaur named <strong>Fred.</strong> 54650Sstevel@tonic-gate </blockquote> 54660Sstevel@tonic-gate <hr> 54670Sstevel@tonic-gate 54680Sstevel@tonic-gateIf you find the syntax for calling the HTML shortcuts awkward, you can 54690Sstevel@tonic-gateimport them into your namespace and dispense with the object syntax 54700Sstevel@tonic-gatecompletely (see the next section for more details): 54710Sstevel@tonic-gate 54720Sstevel@tonic-gate use CGI ':standard'; 54730Sstevel@tonic-gate print blockquote( 54740Sstevel@tonic-gate "Many years ago on the island of", 54750Sstevel@tonic-gate a({href=>"http://crete.org/"},"Crete"), 54760Sstevel@tonic-gate "there lived a minotaur named", 54770Sstevel@tonic-gate strong("Fred."), 54780Sstevel@tonic-gate ), 54790Sstevel@tonic-gate hr; 54800Sstevel@tonic-gate 54810Sstevel@tonic-gate=head2 PROVIDING ARGUMENTS TO HTML SHORTCUTS 54820Sstevel@tonic-gate 54830Sstevel@tonic-gateThe HTML methods will accept zero, one or multiple arguments. If you 54840Sstevel@tonic-gateprovide no arguments, you get a single tag: 54850Sstevel@tonic-gate 54860Sstevel@tonic-gate print hr; # <hr> 54870Sstevel@tonic-gate 54880Sstevel@tonic-gateIf you provide one or more string arguments, they are concatenated 54890Sstevel@tonic-gatetogether with spaces and placed between opening and closing tags: 54900Sstevel@tonic-gate 54910Sstevel@tonic-gate print h1("Chapter","1"); # <h1>Chapter 1</h1>" 54920Sstevel@tonic-gate 54930Sstevel@tonic-gateIf the first argument is an associative array reference, then the keys 54940Sstevel@tonic-gateand values of the associative array become the HTML tag's attributes: 54950Sstevel@tonic-gate 54960Sstevel@tonic-gate print a({-href=>'fred.html',-target=>'_new'}, 54970Sstevel@tonic-gate "Open a new frame"); 54980Sstevel@tonic-gate 54990Sstevel@tonic-gate <a href="fred.html",target="_new">Open a new frame</a> 55000Sstevel@tonic-gate 55010Sstevel@tonic-gateYou may dispense with the dashes in front of the attribute names if 55020Sstevel@tonic-gateyou prefer: 55030Sstevel@tonic-gate 55040Sstevel@tonic-gate print img {src=>'fred.gif',align=>'LEFT'}; 55050Sstevel@tonic-gate 55060Sstevel@tonic-gate <img align="LEFT" src="fred.gif"> 55070Sstevel@tonic-gate 55080Sstevel@tonic-gateSometimes an HTML tag attribute has no argument. For example, ordered 55090Sstevel@tonic-gatelists can be marked as COMPACT. The syntax for this is an argument that 55100Sstevel@tonic-gatethat points to an undef string: 55110Sstevel@tonic-gate 55120Sstevel@tonic-gate print ol({compact=>undef},li('one'),li('two'),li('three')); 55130Sstevel@tonic-gate 55140Sstevel@tonic-gatePrior to CGI.pm version 2.41, providing an empty ('') string as an 55150Sstevel@tonic-gateattribute argument was the same as providing undef. However, this has 55160Sstevel@tonic-gatechanged in order to accommodate those who want to create tags of the form 55170Sstevel@tonic-gate<img alt="">. The difference is shown in these two pieces of code: 55180Sstevel@tonic-gate 55190Sstevel@tonic-gate CODE RESULT 55200Sstevel@tonic-gate img({alt=>undef}) <img alt> 55210Sstevel@tonic-gate img({alt=>''}) <img alt=""> 55220Sstevel@tonic-gate 55230Sstevel@tonic-gate=head2 THE DISTRIBUTIVE PROPERTY OF HTML SHORTCUTS 55240Sstevel@tonic-gate 55250Sstevel@tonic-gateOne of the cool features of the HTML shortcuts is that they are 55260Sstevel@tonic-gatedistributive. If you give them an argument consisting of a 55270Sstevel@tonic-gateB<reference> to a list, the tag will be distributed across each 55280Sstevel@tonic-gateelement of the list. For example, here's one way to make an ordered 55290Sstevel@tonic-gatelist: 55300Sstevel@tonic-gate 55310Sstevel@tonic-gate print ul( 55320Sstevel@tonic-gate li({-type=>'disc'},['Sneezy','Doc','Sleepy','Happy']) 55330Sstevel@tonic-gate ); 55340Sstevel@tonic-gate 55350Sstevel@tonic-gateThis example will result in HTML output that looks like this: 55360Sstevel@tonic-gate 55370Sstevel@tonic-gate <ul> 55380Sstevel@tonic-gate <li type="disc">Sneezy</li> 55390Sstevel@tonic-gate <li type="disc">Doc</li> 55400Sstevel@tonic-gate <li type="disc">Sleepy</li> 55410Sstevel@tonic-gate <li type="disc">Happy</li> 55420Sstevel@tonic-gate </ul> 55430Sstevel@tonic-gate 55440Sstevel@tonic-gateThis is extremely useful for creating tables. For example: 55450Sstevel@tonic-gate 55460Sstevel@tonic-gate print table({-border=>undef}, 55470Sstevel@tonic-gate caption('When Should You Eat Your Vegetables?'), 55480Sstevel@tonic-gate Tr({-align=>CENTER,-valign=>TOP}, 55490Sstevel@tonic-gate [ 55500Sstevel@tonic-gate th(['Vegetable', 'Breakfast','Lunch','Dinner']), 55510Sstevel@tonic-gate td(['Tomatoes' , 'no', 'yes', 'yes']), 55520Sstevel@tonic-gate td(['Broccoli' , 'no', 'no', 'yes']), 55530Sstevel@tonic-gate td(['Onions' , 'yes','yes', 'yes']) 55540Sstevel@tonic-gate ] 55550Sstevel@tonic-gate ) 55560Sstevel@tonic-gate ); 55570Sstevel@tonic-gate 55580Sstevel@tonic-gate=head2 HTML SHORTCUTS AND LIST INTERPOLATION 55590Sstevel@tonic-gate 55600Sstevel@tonic-gateConsider this bit of code: 55610Sstevel@tonic-gate 55620Sstevel@tonic-gate print blockquote(em('Hi'),'mom!')); 55630Sstevel@tonic-gate 55640Sstevel@tonic-gateIt will ordinarily return the string that you probably expect, namely: 55650Sstevel@tonic-gate 55660Sstevel@tonic-gate <blockquote><em>Hi</em> mom!</blockquote> 55670Sstevel@tonic-gate 55680Sstevel@tonic-gateNote the space between the element "Hi" and the element "mom!". 55690Sstevel@tonic-gateCGI.pm puts the extra space there using array interpolation, which is 55700Sstevel@tonic-gatecontrolled by the magic $" variable. Sometimes this extra space is 55710Sstevel@tonic-gatenot what you want, for example, when you are trying to align a series 55720Sstevel@tonic-gateof images. In this case, you can simply change the value of $" to an 55730Sstevel@tonic-gateempty string. 55740Sstevel@tonic-gate 55750Sstevel@tonic-gate { 55760Sstevel@tonic-gate local($") = ''; 55770Sstevel@tonic-gate print blockquote(em('Hi'),'mom!')); 55780Sstevel@tonic-gate } 55790Sstevel@tonic-gate 55800Sstevel@tonic-gateI suggest you put the code in a block as shown here. Otherwise the 55810Sstevel@tonic-gatechange to $" will affect all subsequent code until you explicitly 55820Sstevel@tonic-gatereset it. 55830Sstevel@tonic-gate 55840Sstevel@tonic-gate=head2 NON-STANDARD HTML SHORTCUTS 55850Sstevel@tonic-gate 55860Sstevel@tonic-gateA few HTML tags don't follow the standard pattern for various 55870Sstevel@tonic-gatereasons. 55880Sstevel@tonic-gate 55890Sstevel@tonic-gateB<comment()> generates an HTML comment (<!-- comment -->). Call it 55900Sstevel@tonic-gatelike 55910Sstevel@tonic-gate 55920Sstevel@tonic-gate print comment('here is my comment'); 55930Sstevel@tonic-gate 55940Sstevel@tonic-gateBecause of conflicts with built-in Perl functions, the following functions 55950Sstevel@tonic-gatebegin with initial caps: 55960Sstevel@tonic-gate 55970Sstevel@tonic-gate Select 55980Sstevel@tonic-gate Tr 55990Sstevel@tonic-gate Link 56000Sstevel@tonic-gate Delete 56010Sstevel@tonic-gate Accept 56020Sstevel@tonic-gate Sub 56030Sstevel@tonic-gate 56040Sstevel@tonic-gateIn addition, start_html(), end_html(), start_form(), end_form(), 56050Sstevel@tonic-gatestart_multipart_form() and all the fill-out form tags are special. 56060Sstevel@tonic-gateSee their respective sections. 56070Sstevel@tonic-gate 56080Sstevel@tonic-gate=head2 AUTOESCAPING HTML 56090Sstevel@tonic-gate 56100Sstevel@tonic-gateBy default, all HTML that is emitted by the form-generating functions 56110Sstevel@tonic-gateis passed through a function called escapeHTML(): 56120Sstevel@tonic-gate 56130Sstevel@tonic-gate=over 4 56140Sstevel@tonic-gate 56150Sstevel@tonic-gate=item $escaped_string = escapeHTML("unescaped string"); 56160Sstevel@tonic-gate 56170Sstevel@tonic-gateEscape HTML formatting characters in a string. 56180Sstevel@tonic-gate 56190Sstevel@tonic-gate=back 56200Sstevel@tonic-gate 56210Sstevel@tonic-gateProvided that you have specified a character set of ISO-8859-1 (the 56220Sstevel@tonic-gatedefault), the standard HTML escaping rules will be used. The "<" 56230Sstevel@tonic-gatecharacter becomes "<", ">" becomes ">", "&" becomes "&", and 56240Sstevel@tonic-gatethe quote character becomes """. In addition, the hexadecimal 56250Sstevel@tonic-gate0x8b and 0x9b characters, which some browsers incorrectly interpret 56260Sstevel@tonic-gateas the left and right angle-bracket characters, are replaced by their 56270Sstevel@tonic-gatenumeric character entities ("‹" and "›"). If you manually change 56280Sstevel@tonic-gatethe charset, either by calling the charset() method explicitly or by 56290Sstevel@tonic-gatepassing a -charset argument to header(), then B<all> characters will 56300Sstevel@tonic-gatebe replaced by their numeric entities, since CGI.pm has no lookup 56310Sstevel@tonic-gatetable for all the possible encodings. 56320Sstevel@tonic-gate 56330Sstevel@tonic-gateThe automatic escaping does not apply to other shortcuts, such as 56340Sstevel@tonic-gateh1(). You should call escapeHTML() yourself on untrusted data in 56350Sstevel@tonic-gateorder to protect your pages against nasty tricks that people may enter 56360Sstevel@tonic-gateinto guestbooks, etc.. To change the character set, use charset(). 56370Sstevel@tonic-gateTo turn autoescaping off completely, use autoEscape(0): 56380Sstevel@tonic-gate 56390Sstevel@tonic-gate=over 4 56400Sstevel@tonic-gate 56410Sstevel@tonic-gate=item $charset = charset([$charset]); 56420Sstevel@tonic-gate 56430Sstevel@tonic-gateGet or set the current character set. 56440Sstevel@tonic-gate 56450Sstevel@tonic-gate=item $flag = autoEscape([$flag]); 56460Sstevel@tonic-gate 56470Sstevel@tonic-gateGet or set the value of the autoescape flag. 56480Sstevel@tonic-gate 56490Sstevel@tonic-gate=back 56500Sstevel@tonic-gate 56510Sstevel@tonic-gate=head2 PRETTY-PRINTING HTML 56520Sstevel@tonic-gate 56530Sstevel@tonic-gateBy default, all the HTML produced by these functions comes out as one 56540Sstevel@tonic-gatelong line without carriage returns or indentation. This is yuck, but 56550Sstevel@tonic-gateit does reduce the size of the documents by 10-20%. To get 56560Sstevel@tonic-gatepretty-printed output, please use L<CGI::Pretty>, a subclass 56570Sstevel@tonic-gatecontributed by Brian Paulsen. 56580Sstevel@tonic-gate 56590Sstevel@tonic-gate=head1 CREATING FILL-OUT FORMS: 56600Sstevel@tonic-gate 56610Sstevel@tonic-gateI<General note> The various form-creating methods all return strings 56620Sstevel@tonic-gateto the caller, containing the tag or tags that will create the requested 56630Sstevel@tonic-gateform element. You are responsible for actually printing out these strings. 56640Sstevel@tonic-gateIt's set up this way so that you can place formatting tags 56650Sstevel@tonic-gatearound the form elements. 56660Sstevel@tonic-gate 56670Sstevel@tonic-gateI<Another note> The default values that you specify for the forms are only 56680Sstevel@tonic-gateused the B<first> time the script is invoked (when there is no query 56690Sstevel@tonic-gatestring). On subsequent invocations of the script (when there is a query 56700Sstevel@tonic-gatestring), the former values are used even if they are blank. 56710Sstevel@tonic-gate 56720Sstevel@tonic-gateIf you want to change the value of a field from its previous value, you have two 56730Sstevel@tonic-gatechoices: 56740Sstevel@tonic-gate 56750Sstevel@tonic-gate(1) call the param() method to set it. 56760Sstevel@tonic-gate 56770Sstevel@tonic-gate(2) use the -override (alias -force) parameter (a new feature in version 2.15). 56780Sstevel@tonic-gateThis forces the default value to be used, regardless of the previous value: 56790Sstevel@tonic-gate 5680667Sps156622 print textfield(-name=>'field_name', 56810Sstevel@tonic-gate -default=>'starting value', 56820Sstevel@tonic-gate -override=>1, 56830Sstevel@tonic-gate -size=>50, 56840Sstevel@tonic-gate -maxlength=>80); 56850Sstevel@tonic-gate 56860Sstevel@tonic-gateI<Yet another note> By default, the text and labels of form elements are 56870Sstevel@tonic-gateescaped according to HTML rules. This means that you can safely use 56880Sstevel@tonic-gate"<CLICK ME>" as the label for a button. However, it also interferes with 56890Sstevel@tonic-gateyour ability to incorporate special HTML character sequences, such as Á, 56900Sstevel@tonic-gateinto your fields. If you wish to turn off automatic escaping, call the 56910Sstevel@tonic-gateautoEscape() method with a false value immediately after creating the CGI object: 56920Sstevel@tonic-gate 56930Sstevel@tonic-gate $query = new CGI; 5694667Sps156622 autoEscape(undef); 5695667Sps156622 5696667Sps156622I<A Lurking Trap!> Some of the form-element generating methods return 5697667Sps156622multiple tags. In a scalar context, the tags will be concatenated 5698667Sps156622together with spaces, or whatever is the current value of the $" 5699667Sps156622global. In a list context, the methods will return a list of 5700667Sps156622elements, allowing you to modify them if you wish. Usually you will 5701667Sps156622not notice this behavior, but beware of this: 5702667Sps156622 5703667Sps156622 printf("%s\n",end_form()) 5704667Sps156622 5705667Sps156622end_form() produces several tags, and only the first of them will be 5706667Sps156622printed because the format only expects one value. 5707667Sps156622 5708667Sps156622<p> 5709667Sps156622 57100Sstevel@tonic-gate 57110Sstevel@tonic-gate=head2 CREATING AN ISINDEX TAG 57120Sstevel@tonic-gate 5713667Sps156622 print isindex(-action=>$action); 57140Sstevel@tonic-gate 57150Sstevel@tonic-gate -or- 57160Sstevel@tonic-gate 5717667Sps156622 print isindex($action); 57180Sstevel@tonic-gate 57190Sstevel@tonic-gatePrints out an <isindex> tag. Not very exciting. The parameter 57200Sstevel@tonic-gate-action specifies the URL of the script to process the query. The 57210Sstevel@tonic-gatedefault is to process the query with the current script. 57220Sstevel@tonic-gate 57230Sstevel@tonic-gate=head2 STARTING AND ENDING A FORM 57240Sstevel@tonic-gate 5725667Sps156622 print start_form(-method=>$method, 5726667Sps156622 -action=>$action, 5727667Sps156622 -enctype=>$encoding); 57280Sstevel@tonic-gate <... various form stuff ...> 5729667Sps156622 print endform; 57300Sstevel@tonic-gate 57310Sstevel@tonic-gate -or- 57320Sstevel@tonic-gate 5733667Sps156622 print start_form($method,$action,$encoding); 57340Sstevel@tonic-gate <... various form stuff ...> 5735667Sps156622 print endform; 57360Sstevel@tonic-gate 57370Sstevel@tonic-gatestart_form() will return a <form> tag with the optional method, 57380Sstevel@tonic-gateaction and form encoding that you specify. The defaults are: 57390Sstevel@tonic-gate 57400Sstevel@tonic-gate method: POST 57410Sstevel@tonic-gate action: this script 57420Sstevel@tonic-gate enctype: application/x-www-form-urlencoded 57430Sstevel@tonic-gate 57440Sstevel@tonic-gateendform() returns the closing </form> tag. 57450Sstevel@tonic-gate 57460Sstevel@tonic-gateStart_form()'s enctype argument tells the browser how to package the various 57470Sstevel@tonic-gatefields of the form before sending the form to the server. Two 57480Sstevel@tonic-gatevalues are possible: 57490Sstevel@tonic-gate 57500Sstevel@tonic-gateB<Note:> This method was previously named startform(), and startform() 57510Sstevel@tonic-gateis still recognized as an alias. 57520Sstevel@tonic-gate 57530Sstevel@tonic-gate=over 4 57540Sstevel@tonic-gate 57550Sstevel@tonic-gate=item B<application/x-www-form-urlencoded> 57560Sstevel@tonic-gate 57570Sstevel@tonic-gateThis is the older type of encoding used by all browsers prior to 57580Sstevel@tonic-gateNetscape 2.0. It is compatible with many CGI scripts and is 57590Sstevel@tonic-gatesuitable for short fields containing text data. For your 57600Sstevel@tonic-gateconvenience, CGI.pm stores the name of this encoding 57610Sstevel@tonic-gatetype in B<&CGI::URL_ENCODED>. 57620Sstevel@tonic-gate 57630Sstevel@tonic-gate=item B<multipart/form-data> 57640Sstevel@tonic-gate 57650Sstevel@tonic-gateThis is the newer type of encoding introduced by Netscape 2.0. 57660Sstevel@tonic-gateIt is suitable for forms that contain very large fields or that 57670Sstevel@tonic-gateare intended for transferring binary data. Most importantly, 57680Sstevel@tonic-gateit enables the "file upload" feature of Netscape 2.0 forms. For 57690Sstevel@tonic-gateyour convenience, CGI.pm stores the name of this encoding type 57700Sstevel@tonic-gatein B<&CGI::MULTIPART> 57710Sstevel@tonic-gate 57720Sstevel@tonic-gateForms that use this type of encoding are not easily interpreted 57730Sstevel@tonic-gateby CGI scripts unless they use CGI.pm or another library designed 57740Sstevel@tonic-gateto handle them. 57750Sstevel@tonic-gate 5776667Sps156622If XHTML is activated (the default), then forms will be automatically 5777667Sps156622created using this type of encoding. 5778667Sps156622 57790Sstevel@tonic-gate=back 57800Sstevel@tonic-gate 57810Sstevel@tonic-gateFor compatibility, the start_form() method uses the older form of 57820Sstevel@tonic-gateencoding by default. If you want to use the newer form of encoding 57830Sstevel@tonic-gateby default, you can call B<start_multipart_form()> instead of 57840Sstevel@tonic-gateB<start_form()>. 57850Sstevel@tonic-gate 57860Sstevel@tonic-gateJAVASCRIPTING: The B<-name> and B<-onSubmit> parameters are provided 57870Sstevel@tonic-gatefor use with JavaScript. The -name parameter gives the 57880Sstevel@tonic-gateform a name so that it can be identified and manipulated by 57890Sstevel@tonic-gateJavaScript functions. -onSubmit should point to a JavaScript 57900Sstevel@tonic-gatefunction that will be executed just before the form is submitted to your 57910Sstevel@tonic-gateserver. You can use this opportunity to check the contents of the form 57920Sstevel@tonic-gatefor consistency and completeness. If you find something wrong, you 57930Sstevel@tonic-gatecan put up an alert box or maybe fix things up yourself. You can 57940Sstevel@tonic-gateabort the submission by returning false from this function. 57950Sstevel@tonic-gate 57960Sstevel@tonic-gateUsually the bulk of JavaScript functions are defined in a <script> 57970Sstevel@tonic-gateblock in the HTML header and -onSubmit points to one of these function 57980Sstevel@tonic-gatecall. See start_html() for details. 57990Sstevel@tonic-gate 5800667Sps156622=head2 FORM ELEMENTS 5801667Sps156622 5802667Sps156622After starting a form, you will typically create one or more 5803667Sps156622textfields, popup menus, radio groups and other form elements. Each 5804667Sps156622of these elements takes a standard set of named arguments. Some 5805667Sps156622elements also have optional arguments. The standard arguments are as 5806667Sps156622follows: 5807667Sps156622 5808667Sps156622=over 4 5809667Sps156622 5810667Sps156622=item B<-name> 5811667Sps156622 5812667Sps156622The name of the field. After submission this name can be used to 5813667Sps156622retrieve the field's value using the param() method. 5814667Sps156622 5815667Sps156622=item B<-value>, B<-values> 5816667Sps156622 5817667Sps156622The initial value of the field which will be returned to the script 5818667Sps156622after form submission. Some form elements, such as text fields, take 5819667Sps156622a single scalar -value argument. Others, such as popup menus, take a 5820667Sps156622reference to an array of values. The two arguments are synonyms. 5821667Sps156622 5822667Sps156622=item B<-tabindex> 5823667Sps156622 5824667Sps156622A numeric value that sets the order in which the form element receives 5825667Sps156622focus when the user presses the tab key. Elements with lower values 5826667Sps156622receive focus first. 5827667Sps156622 5828667Sps156622=item B<-id> 5829667Sps156622 5830667Sps156622A string identifier that can be used to identify this element to 5831667Sps156622JavaScript and DHTML. 5832667Sps156622 5833667Sps156622=item B<-override> 5834667Sps156622 5835667Sps156622A boolean, which, if true, forces the element to take on the value 5836667Sps156622specified by B<-value>, overriding the sticky behavior described 5837667Sps156622earlier for the B<-no_sticky> pragma. 5838667Sps156622 5839667Sps156622=item B<-onChange>, B<-onFocus>, B<-onBlur>, B<-onMouseOver>, B<-onMouseOut>, B<-onSelect> 5840667Sps156622 5841667Sps156622These are used to assign JavaScript event handlers. See the 5842667Sps156622JavaScripting section for more details. 5843667Sps156622 5844667Sps156622=back 5845667Sps156622 5846667Sps156622Other common arguments are described in the next section. In addition 5847667Sps156622to these, all attributes described in the HTML specifications are 5848667Sps156622supported. 5849667Sps156622 58500Sstevel@tonic-gate=head2 CREATING A TEXT FIELD 58510Sstevel@tonic-gate 5852667Sps156622 print textfield(-name=>'field_name', 5853667Sps156622 -value=>'starting value', 5854667Sps156622 -size=>50, 5855667Sps156622 -maxlength=>80); 58560Sstevel@tonic-gate -or- 58570Sstevel@tonic-gate 5858667Sps156622 print textfield('field_name','starting value',50,80); 5859667Sps156622 5860667Sps156622textfield() will return a text input field. 58610Sstevel@tonic-gate 58620Sstevel@tonic-gate=over 4 58630Sstevel@tonic-gate 58640Sstevel@tonic-gate=item B<Parameters> 58650Sstevel@tonic-gate 58660Sstevel@tonic-gate=item 1. 58670Sstevel@tonic-gate 5868667Sps156622The first parameter is the required name for the field (-name). 58690Sstevel@tonic-gate 58700Sstevel@tonic-gate=item 2. 58710Sstevel@tonic-gate 58720Sstevel@tonic-gateThe optional second parameter is the default starting value for the field 5873667Sps156622contents (-value, formerly known as -default). 58740Sstevel@tonic-gate 58750Sstevel@tonic-gate=item 3. 58760Sstevel@tonic-gate 58770Sstevel@tonic-gateThe optional third parameter is the size of the field in 58780Sstevel@tonic-gate characters (-size). 58790Sstevel@tonic-gate 58800Sstevel@tonic-gate=item 4. 58810Sstevel@tonic-gate 58820Sstevel@tonic-gateThe optional fourth parameter is the maximum number of characters the 58830Sstevel@tonic-gate field will accept (-maxlength). 58840Sstevel@tonic-gate 58850Sstevel@tonic-gate=back 58860Sstevel@tonic-gate 58870Sstevel@tonic-gateAs with all these methods, the field will be initialized with its 58880Sstevel@tonic-gateprevious contents from earlier invocations of the script. 58890Sstevel@tonic-gateWhen the form is processed, the value of the text field can be 58900Sstevel@tonic-gateretrieved with: 58910Sstevel@tonic-gate 5892667Sps156622 $value = param('foo'); 58930Sstevel@tonic-gate 58940Sstevel@tonic-gateIf you want to reset it from its initial value after the script has been 58950Sstevel@tonic-gatecalled once, you can do so like this: 58960Sstevel@tonic-gate 5897667Sps156622 param('foo',"I'm taking over this value!"); 58980Sstevel@tonic-gate 58990Sstevel@tonic-gate=head2 CREATING A BIG TEXT FIELD 59000Sstevel@tonic-gate 5901667Sps156622 print textarea(-name=>'foo', 59020Sstevel@tonic-gate -default=>'starting value', 59030Sstevel@tonic-gate -rows=>10, 59040Sstevel@tonic-gate -columns=>50); 59050Sstevel@tonic-gate 59060Sstevel@tonic-gate -or 59070Sstevel@tonic-gate 5908667Sps156622 print textarea('foo','starting value',10,50); 59090Sstevel@tonic-gate 59100Sstevel@tonic-gatetextarea() is just like textfield, but it allows you to specify 59110Sstevel@tonic-gaterows and columns for a multiline text entry box. You can provide 59120Sstevel@tonic-gatea starting value for the field, which can be long and contain 59130Sstevel@tonic-gatemultiple lines. 59140Sstevel@tonic-gate 59150Sstevel@tonic-gate=head2 CREATING A PASSWORD FIELD 59160Sstevel@tonic-gate 5917667Sps156622 print password_field(-name=>'secret', 59180Sstevel@tonic-gate -value=>'starting value', 59190Sstevel@tonic-gate -size=>50, 59200Sstevel@tonic-gate -maxlength=>80); 59210Sstevel@tonic-gate -or- 59220Sstevel@tonic-gate 5923667Sps156622 print password_field('secret','starting value',50,80); 59240Sstevel@tonic-gate 59250Sstevel@tonic-gatepassword_field() is identical to textfield(), except that its contents 59260Sstevel@tonic-gatewill be starred out on the web page. 59270Sstevel@tonic-gate 59280Sstevel@tonic-gate=head2 CREATING A FILE UPLOAD FIELD 59290Sstevel@tonic-gate 5930667Sps156622 print filefield(-name=>'uploaded_file', 59310Sstevel@tonic-gate -default=>'starting value', 59320Sstevel@tonic-gate -size=>50, 59330Sstevel@tonic-gate -maxlength=>80); 59340Sstevel@tonic-gate -or- 59350Sstevel@tonic-gate 5936667Sps156622 print filefield('uploaded_file','starting value',50,80); 59370Sstevel@tonic-gate 59380Sstevel@tonic-gatefilefield() will return a file upload field for Netscape 2.0 browsers. 59390Sstevel@tonic-gateIn order to take full advantage of this I<you must use the new 59400Sstevel@tonic-gatemultipart encoding scheme> for the form. You can do this either 59410Sstevel@tonic-gateby calling B<start_form()> with an encoding type of B<&CGI::MULTIPART>, 59420Sstevel@tonic-gateor by calling the new method B<start_multipart_form()> instead of 59430Sstevel@tonic-gatevanilla B<start_form()>. 59440Sstevel@tonic-gate 59450Sstevel@tonic-gate=over 4 59460Sstevel@tonic-gate 59470Sstevel@tonic-gate=item B<Parameters> 59480Sstevel@tonic-gate 59490Sstevel@tonic-gate=item 1. 59500Sstevel@tonic-gate 59510Sstevel@tonic-gateThe first parameter is the required name for the field (-name). 59520Sstevel@tonic-gate 59530Sstevel@tonic-gate=item 2. 59540Sstevel@tonic-gate 59550Sstevel@tonic-gateThe optional second parameter is the starting value for the field contents 59560Sstevel@tonic-gateto be used as the default file name (-default). 59570Sstevel@tonic-gate 59580Sstevel@tonic-gateFor security reasons, browsers don't pay any attention to this field, 59590Sstevel@tonic-gateand so the starting value will always be blank. Worse, the field 59600Sstevel@tonic-gateloses its "sticky" behavior and forgets its previous contents. The 59610Sstevel@tonic-gatestarting value field is called for in the HTML specification, however, 59620Sstevel@tonic-gateand possibly some browser will eventually provide support for it. 59630Sstevel@tonic-gate 59640Sstevel@tonic-gate=item 3. 59650Sstevel@tonic-gate 59660Sstevel@tonic-gateThe optional third parameter is the size of the field in 59670Sstevel@tonic-gatecharacters (-size). 59680Sstevel@tonic-gate 59690Sstevel@tonic-gate=item 4. 59700Sstevel@tonic-gate 59710Sstevel@tonic-gateThe optional fourth parameter is the maximum number of characters the 59720Sstevel@tonic-gatefield will accept (-maxlength). 59730Sstevel@tonic-gate 59740Sstevel@tonic-gate=back 59750Sstevel@tonic-gate 59760Sstevel@tonic-gateWhen the form is processed, you can retrieve the entered filename 59770Sstevel@tonic-gateby calling param(): 59780Sstevel@tonic-gate 5979667Sps156622 $filename = param('uploaded_file'); 59800Sstevel@tonic-gate 59810Sstevel@tonic-gateDifferent browsers will return slightly different things for the 59820Sstevel@tonic-gatename. Some browsers return the filename only. Others return the full 59830Sstevel@tonic-gatepath to the file, using the path conventions of the user's machine. 59840Sstevel@tonic-gateRegardless, the name returned is always the name of the file on the 59850Sstevel@tonic-gateI<user's> machine, and is unrelated to the name of the temporary file 59860Sstevel@tonic-gatethat CGI.pm creates during upload spooling (see below). 59870Sstevel@tonic-gate 59880Sstevel@tonic-gateThe filename returned is also a file handle. You can read the contents 59890Sstevel@tonic-gateof the file using standard Perl file reading calls: 59900Sstevel@tonic-gate 59910Sstevel@tonic-gate # Read a text file and print it out 59920Sstevel@tonic-gate while (<$filename>) { 59930Sstevel@tonic-gate print; 59940Sstevel@tonic-gate } 59950Sstevel@tonic-gate 59960Sstevel@tonic-gate # Copy a binary file to somewhere safe 59970Sstevel@tonic-gate open (OUTFILE,">>/usr/local/web/users/feedback"); 59980Sstevel@tonic-gate while ($bytesread=read($filename,$buffer,1024)) { 59990Sstevel@tonic-gate print OUTFILE $buffer; 60000Sstevel@tonic-gate } 60010Sstevel@tonic-gate 60020Sstevel@tonic-gateHowever, there are problems with the dual nature of the upload fields. 60030Sstevel@tonic-gateIf you C<use strict>, then Perl will complain when you try to use a 60040Sstevel@tonic-gatestring as a filehandle. You can get around this by placing the file 60050Sstevel@tonic-gatereading code in a block containing the C<no strict> pragma. More 60060Sstevel@tonic-gateseriously, it is possible for the remote user to type garbage into the 60070Sstevel@tonic-gateupload field, in which case what you get from param() is not a 60080Sstevel@tonic-gatefilehandle at all, but a string. 60090Sstevel@tonic-gate 60100Sstevel@tonic-gateTo be safe, use the I<upload()> function (new in version 2.47). When 60110Sstevel@tonic-gatecalled with the name of an upload field, I<upload()> returns a 60120Sstevel@tonic-gatefilehandle, or undef if the parameter is not a valid filehandle. 60130Sstevel@tonic-gate 6014667Sps156622 $fh = upload('uploaded_file'); 60150Sstevel@tonic-gate while (<$fh>) { 60160Sstevel@tonic-gate print; 60170Sstevel@tonic-gate } 60180Sstevel@tonic-gate 6019667Sps156622In an list context, upload() will return an array of filehandles. 60200Sstevel@tonic-gateThis makes it possible to create forms that use the same name for 60210Sstevel@tonic-gatemultiple upload fields. 60220Sstevel@tonic-gate 60230Sstevel@tonic-gateThis is the recommended idiom. 60240Sstevel@tonic-gate 6025*6287Sps156622For robust code, consider reseting the file handle position to beginning of the 6026*6287Sps156622file. Inside of larger frameworks, other code may have already used the query 6027*6287Sps156622object and changed the filehandle postion: 6028*6287Sps156622 6029*6287Sps156622 seek($fh,0,0); # reset postion to beginning of file. 6030*6287Sps156622 60310Sstevel@tonic-gateWhen a file is uploaded the browser usually sends along some 60320Sstevel@tonic-gateinformation along with it in the format of headers. The information 60330Sstevel@tonic-gateusually includes the MIME content type. Future browsers may send 60340Sstevel@tonic-gateother information as well (such as modification date and size). To 60350Sstevel@tonic-gateretrieve this information, call uploadInfo(). It returns a reference to 60360Sstevel@tonic-gatean associative array containing all the document headers. 60370Sstevel@tonic-gate 6038667Sps156622 $filename = param('uploaded_file'); 6039667Sps156622 $type = uploadInfo($filename)->{'Content-Type'}; 60400Sstevel@tonic-gate unless ($type eq 'text/html') { 60410Sstevel@tonic-gate die "HTML FILES ONLY!"; 60420Sstevel@tonic-gate } 60430Sstevel@tonic-gate 60440Sstevel@tonic-gateIf you are using a machine that recognizes "text" and "binary" data 60450Sstevel@tonic-gatemodes, be sure to understand when and how to use them (see the Camel book). 60460Sstevel@tonic-gateOtherwise you may find that binary files are corrupted during file 60470Sstevel@tonic-gateuploads. 60480Sstevel@tonic-gate 60490Sstevel@tonic-gateThere are occasionally problems involving parsing the uploaded file. 60500Sstevel@tonic-gateThis usually happens when the user presses "Stop" before the upload is 60510Sstevel@tonic-gatefinished. In this case, CGI.pm will return undef for the name of the 60520Sstevel@tonic-gateuploaded file and set I<cgi_error()> to the string "400 Bad request 60530Sstevel@tonic-gate(malformed multipart POST)". This error message is designed so that 60540Sstevel@tonic-gateyou can incorporate it into a status code to be sent to the browser. 60550Sstevel@tonic-gateExample: 60560Sstevel@tonic-gate 6057667Sps156622 $file = upload('uploaded_file'); 6058667Sps156622 if (!$file && cgi_error) { 6059667Sps156622 print header(-status=>cgi_error); 60600Sstevel@tonic-gate exit 0; 60610Sstevel@tonic-gate } 60620Sstevel@tonic-gate 60630Sstevel@tonic-gateYou are free to create a custom HTML page to complain about the error, 60640Sstevel@tonic-gateif you wish. 60650Sstevel@tonic-gate 60660Sstevel@tonic-gateYou can set up a callback that will be called whenever a file upload 60670Sstevel@tonic-gateis being read during the form processing. This is much like the 60680Sstevel@tonic-gateUPLOAD_HOOK facility available in Apache::Request, with the exception 60690Sstevel@tonic-gatethat the first argument to the callback is an Apache::Upload object, 60700Sstevel@tonic-gatehere it's the remote filename. 60710Sstevel@tonic-gate 6072*6287Sps156622 $q = CGI->new(\&hook [,$data [,$use_tempfile]]); 60730Sstevel@tonic-gate 60740Sstevel@tonic-gate sub hook 60750Sstevel@tonic-gate { 60760Sstevel@tonic-gate my ($filename, $buffer, $bytes_read, $data) = @_; 60770Sstevel@tonic-gate print "Read $bytes_read bytes of $filename\n"; 60780Sstevel@tonic-gate } 60790Sstevel@tonic-gate 6080*6287Sps156622The $data field is optional; it lets you pass configuration 6081*6287Sps156622information (e.g. a database handle) to your hook callback. 6082*6287Sps156622 6083*6287Sps156622The $use_tempfile field is a flag that lets you turn on and off 6084*6287Sps156622CGI.pm's use of a temporary disk-based file during file upload. If you 6085*6287Sps156622set this to a FALSE value (default true) then param('uploaded_file') 6086*6287Sps156622will no longer work, and the only way to get at the uploaded data is 6087*6287Sps156622via the hook you provide. 6088*6287Sps156622 60890Sstevel@tonic-gateIf using the function-oriented interface, call the CGI::upload_hook() 60900Sstevel@tonic-gatemethod before calling param() or any other CGI functions: 60910Sstevel@tonic-gate 6092*6287Sps156622 CGI::upload_hook(\&hook [,$data [,$use_tempfile]]); 60930Sstevel@tonic-gate 60940Sstevel@tonic-gateThis method is not exported by default. You will have to import it 60950Sstevel@tonic-gateexplicitly if you wish to use it without the CGI:: prefix. 60960Sstevel@tonic-gate 60970Sstevel@tonic-gateIf you are using CGI.pm on a Windows platform and find that binary 60980Sstevel@tonic-gatefiles get slightly larger when uploaded but that text files remain the 60990Sstevel@tonic-gatesame, then you have forgotten to activate binary mode on the output 61000Sstevel@tonic-gatefilehandle. Be sure to call binmode() on any handle that you create 61010Sstevel@tonic-gateto write the uploaded file to disk. 61020Sstevel@tonic-gate 61030Sstevel@tonic-gateJAVASCRIPTING: The B<-onChange>, B<-onFocus>, B<-onBlur>, 61040Sstevel@tonic-gateB<-onMouseOver>, B<-onMouseOut> and B<-onSelect> parameters are 61050Sstevel@tonic-gaterecognized. See textfield() for details. 61060Sstevel@tonic-gate 61070Sstevel@tonic-gate=head2 CREATING A POPUP MENU 61080Sstevel@tonic-gate 6109667Sps156622 print popup_menu('menu_name', 61100Sstevel@tonic-gate ['eenie','meenie','minie'], 61110Sstevel@tonic-gate 'meenie'); 61120Sstevel@tonic-gate 61130Sstevel@tonic-gate -or- 61140Sstevel@tonic-gate 61150Sstevel@tonic-gate %labels = ('eenie'=>'your first choice', 61160Sstevel@tonic-gate 'meenie'=>'your second choice', 61170Sstevel@tonic-gate 'minie'=>'your third choice'); 61180Sstevel@tonic-gate %attributes = ('eenie'=>{'class'=>'class of first choice'}); 6119667Sps156622 print popup_menu('menu_name', 61200Sstevel@tonic-gate ['eenie','meenie','minie'], 61210Sstevel@tonic-gate 'meenie',\%labels,\%attributes); 61220Sstevel@tonic-gate 61230Sstevel@tonic-gate -or (named parameter style)- 61240Sstevel@tonic-gate 6125667Sps156622 print popup_menu(-name=>'menu_name', 61260Sstevel@tonic-gate -values=>['eenie','meenie','minie'], 61270Sstevel@tonic-gate -default=>'meenie', 61280Sstevel@tonic-gate -labels=>\%labels, 61290Sstevel@tonic-gate -attributes=>\%attributes); 61300Sstevel@tonic-gate 61310Sstevel@tonic-gatepopup_menu() creates a menu. 61320Sstevel@tonic-gate 61330Sstevel@tonic-gate=over 4 61340Sstevel@tonic-gate 61350Sstevel@tonic-gate=item 1. 61360Sstevel@tonic-gate 61370Sstevel@tonic-gateThe required first argument is the menu's name (-name). 61380Sstevel@tonic-gate 61390Sstevel@tonic-gate=item 2. 61400Sstevel@tonic-gate 61410Sstevel@tonic-gateThe required second argument (-values) is an array B<reference> 61420Sstevel@tonic-gatecontaining the list of menu items in the menu. You can pass the 61430Sstevel@tonic-gatemethod an anonymous array, as shown in the example, or a reference to 61440Sstevel@tonic-gatea named array, such as "\@foo". 61450Sstevel@tonic-gate 61460Sstevel@tonic-gate=item 3. 61470Sstevel@tonic-gate 61480Sstevel@tonic-gateThe optional third parameter (-default) is the name of the default 61490Sstevel@tonic-gatemenu choice. If not specified, the first item will be the default. 61500Sstevel@tonic-gateThe values of the previous choice will be maintained across queries. 61510Sstevel@tonic-gate 61520Sstevel@tonic-gate=item 4. 61530Sstevel@tonic-gate 61540Sstevel@tonic-gateThe optional fourth parameter (-labels) is provided for people who 61550Sstevel@tonic-gatewant to use different values for the user-visible label inside the 61560Sstevel@tonic-gatepopup menu and the value returned to your script. It's a pointer to an 61570Sstevel@tonic-gateassociative array relating menu values to user-visible labels. If you 61580Sstevel@tonic-gateleave this parameter blank, the menu values will be displayed by 61590Sstevel@tonic-gatedefault. (You can also leave a label undefined if you want to). 61600Sstevel@tonic-gate 61610Sstevel@tonic-gate=item 5. 61620Sstevel@tonic-gate 61630Sstevel@tonic-gateThe optional fifth parameter (-attributes) is provided to assign 61640Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's 61650Sstevel@tonic-gatea pointer to an associative array relating menu values to another 61660Sstevel@tonic-gateassociative array with the attribute's name as the key and the 61670Sstevel@tonic-gateattribute's value as the value. 61680Sstevel@tonic-gate 61690Sstevel@tonic-gate=back 61700Sstevel@tonic-gate 61710Sstevel@tonic-gateWhen the form is processed, the selected value of the popup menu can 61720Sstevel@tonic-gatebe retrieved using: 61730Sstevel@tonic-gate 6174667Sps156622 $popup_menu_value = param('menu_name'); 61750Sstevel@tonic-gate 61760Sstevel@tonic-gate=head2 CREATING AN OPTION GROUP 61770Sstevel@tonic-gate 61780Sstevel@tonic-gateNamed parameter style 61790Sstevel@tonic-gate 6180667Sps156622 print popup_menu(-name=>'menu_name', 61810Sstevel@tonic-gate -values=>[qw/eenie meenie minie/, 6182667Sps156622 optgroup(-name=>'optgroup_name', 6183667Sps156622 -values => ['moe','catch'], 6184667Sps156622 -attributes=>{'catch'=>{'class'=>'red'}})], 61850Sstevel@tonic-gate -labels=>{'eenie'=>'one', 61860Sstevel@tonic-gate 'meenie'=>'two', 61870Sstevel@tonic-gate 'minie'=>'three'}, 61880Sstevel@tonic-gate -default=>'meenie'); 61890Sstevel@tonic-gate 61900Sstevel@tonic-gate Old style 6191667Sps156622 print popup_menu('menu_name', 61920Sstevel@tonic-gate ['eenie','meenie','minie', 6193667Sps156622 optgroup('optgroup_name', ['moe', 'catch'], 6194667Sps156622 {'catch'=>{'class'=>'red'}})],'meenie', 61950Sstevel@tonic-gate {'eenie'=>'one','meenie'=>'two','minie'=>'three'}); 61960Sstevel@tonic-gate 6197667Sps156622optgroup() creates an option group within a popup menu. 61980Sstevel@tonic-gate 61990Sstevel@tonic-gate=over 4 62000Sstevel@tonic-gate 62010Sstevel@tonic-gate=item 1. 62020Sstevel@tonic-gate 62030Sstevel@tonic-gateThe required first argument (B<-name>) is the label attribute of the 62040Sstevel@tonic-gateoptgroup and is B<not> inserted in the parameter list of the query. 62050Sstevel@tonic-gate 62060Sstevel@tonic-gate=item 2. 62070Sstevel@tonic-gate 62080Sstevel@tonic-gateThe required second argument (B<-values>) is an array reference 62090Sstevel@tonic-gatecontaining the list of menu items in the menu. You can pass the 62100Sstevel@tonic-gatemethod an anonymous array, as shown in the example, or a reference 62110Sstevel@tonic-gateto a named array, such as \@foo. If you pass a HASH reference, 62120Sstevel@tonic-gatethe keys will be used for the menu values, and the values will be 62130Sstevel@tonic-gateused for the menu labels (see -labels below). 62140Sstevel@tonic-gate 62150Sstevel@tonic-gate=item 3. 62160Sstevel@tonic-gate 62170Sstevel@tonic-gateThe optional third parameter (B<-labels>) allows you to pass a reference 62180Sstevel@tonic-gateto an associative array containing user-visible labels for one or more 62190Sstevel@tonic-gateof the menu items. You can use this when you want the user to see one 62200Sstevel@tonic-gatemenu string, but have the browser return your program a different one. 62210Sstevel@tonic-gateIf you don't specify this, the value string will be used instead 62220Sstevel@tonic-gate("eenie", "meenie" and "minie" in this example). This is equivalent 62230Sstevel@tonic-gateto using a hash reference for the -values parameter. 62240Sstevel@tonic-gate 62250Sstevel@tonic-gate=item 4. 62260Sstevel@tonic-gate 62270Sstevel@tonic-gateAn optional fourth parameter (B<-labeled>) can be set to a true value 62280Sstevel@tonic-gateand indicates that the values should be used as the label attribute 62290Sstevel@tonic-gatefor each option element within the optgroup. 62300Sstevel@tonic-gate 62310Sstevel@tonic-gate=item 5. 62320Sstevel@tonic-gate 62330Sstevel@tonic-gateAn optional fifth parameter (-novals) can be set to a true value and 6234*6287Sps156622indicates to suppress the val attribute in each option element within 62350Sstevel@tonic-gatethe optgroup. 62360Sstevel@tonic-gate 62370Sstevel@tonic-gateSee the discussion on optgroup at W3C 62380Sstevel@tonic-gate(http://www.w3.org/TR/REC-html40/interact/forms.html#edef-OPTGROUP) 62390Sstevel@tonic-gatefor details. 62400Sstevel@tonic-gate 62410Sstevel@tonic-gate=item 6. 62420Sstevel@tonic-gate 62430Sstevel@tonic-gateAn optional sixth parameter (-attributes) is provided to assign 62440Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's 62450Sstevel@tonic-gatea pointer to an associative array relating menu values to another 62460Sstevel@tonic-gateassociative array with the attribute's name as the key and the 62470Sstevel@tonic-gateattribute's value as the value. 62480Sstevel@tonic-gate 62490Sstevel@tonic-gate=back 62500Sstevel@tonic-gate 62510Sstevel@tonic-gate=head2 CREATING A SCROLLING LIST 62520Sstevel@tonic-gate 6253667Sps156622 print scrolling_list('list_name', 62540Sstevel@tonic-gate ['eenie','meenie','minie','moe'], 62550Sstevel@tonic-gate ['eenie','moe'],5,'true',{'moe'=>{'class'=>'red'}}); 62560Sstevel@tonic-gate -or- 62570Sstevel@tonic-gate 6258667Sps156622 print scrolling_list('list_name', 62590Sstevel@tonic-gate ['eenie','meenie','minie','moe'], 62600Sstevel@tonic-gate ['eenie','moe'],5,'true', 62610Sstevel@tonic-gate \%labels,%attributes); 62620Sstevel@tonic-gate 62630Sstevel@tonic-gate -or- 62640Sstevel@tonic-gate 6265667Sps156622 print scrolling_list(-name=>'list_name', 62660Sstevel@tonic-gate -values=>['eenie','meenie','minie','moe'], 62670Sstevel@tonic-gate -default=>['eenie','moe'], 62680Sstevel@tonic-gate -size=>5, 62690Sstevel@tonic-gate -multiple=>'true', 62700Sstevel@tonic-gate -labels=>\%labels, 62710Sstevel@tonic-gate -attributes=>\%attributes); 62720Sstevel@tonic-gate 62730Sstevel@tonic-gatescrolling_list() creates a scrolling list. 62740Sstevel@tonic-gate 62750Sstevel@tonic-gate=over 4 62760Sstevel@tonic-gate 62770Sstevel@tonic-gate=item B<Parameters:> 62780Sstevel@tonic-gate 62790Sstevel@tonic-gate=item 1. 62800Sstevel@tonic-gate 62810Sstevel@tonic-gateThe first and second arguments are the list name (-name) and values 62820Sstevel@tonic-gate(-values). As in the popup menu, the second argument should be an 62830Sstevel@tonic-gatearray reference. 62840Sstevel@tonic-gate 62850Sstevel@tonic-gate=item 2. 62860Sstevel@tonic-gate 62870Sstevel@tonic-gateThe optional third argument (-default) can be either a reference to a 62880Sstevel@tonic-gatelist containing the values to be selected by default, or can be a 62890Sstevel@tonic-gatesingle value to select. If this argument is missing or undefined, 62900Sstevel@tonic-gatethen nothing is selected when the list first appears. In the named 62910Sstevel@tonic-gateparameter version, you can use the synonym "-defaults" for this 62920Sstevel@tonic-gateparameter. 62930Sstevel@tonic-gate 62940Sstevel@tonic-gate=item 3. 62950Sstevel@tonic-gate 62960Sstevel@tonic-gateThe optional fourth argument is the size of the list (-size). 62970Sstevel@tonic-gate 62980Sstevel@tonic-gate=item 4. 62990Sstevel@tonic-gate 63000Sstevel@tonic-gateThe optional fifth argument can be set to true to allow multiple 63010Sstevel@tonic-gatesimultaneous selections (-multiple). Otherwise only one selection 63020Sstevel@tonic-gatewill be allowed at a time. 63030Sstevel@tonic-gate 63040Sstevel@tonic-gate=item 5. 63050Sstevel@tonic-gate 63060Sstevel@tonic-gateThe optional sixth argument is a pointer to an associative array 63070Sstevel@tonic-gatecontaining long user-visible labels for the list items (-labels). 63080Sstevel@tonic-gateIf not provided, the values will be displayed. 63090Sstevel@tonic-gate 63100Sstevel@tonic-gate=item 6. 63110Sstevel@tonic-gate 63120Sstevel@tonic-gateThe optional sixth parameter (-attributes) is provided to assign 63130Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's 63140Sstevel@tonic-gatea pointer to an associative array relating menu values to another 63150Sstevel@tonic-gateassociative array with the attribute's name as the key and the 63160Sstevel@tonic-gateattribute's value as the value. 63170Sstevel@tonic-gate 63180Sstevel@tonic-gateWhen this form is processed, all selected list items will be returned as 63190Sstevel@tonic-gatea list under the parameter name 'list_name'. The values of the 63200Sstevel@tonic-gateselected items can be retrieved with: 63210Sstevel@tonic-gate 6322667Sps156622 @selected = param('list_name'); 63230Sstevel@tonic-gate 63240Sstevel@tonic-gate=back 63250Sstevel@tonic-gate 63260Sstevel@tonic-gate=head2 CREATING A GROUP OF RELATED CHECKBOXES 63270Sstevel@tonic-gate 6328667Sps156622 print checkbox_group(-name=>'group_name', 63290Sstevel@tonic-gate -values=>['eenie','meenie','minie','moe'], 63300Sstevel@tonic-gate -default=>['eenie','moe'], 63310Sstevel@tonic-gate -linebreak=>'true', 6332*6287Sps156622 -disabled => ['moe'], 63330Sstevel@tonic-gate -labels=>\%labels, 63340Sstevel@tonic-gate -attributes=>\%attributes); 63350Sstevel@tonic-gate 6336667Sps156622 print checkbox_group('group_name', 63370Sstevel@tonic-gate ['eenie','meenie','minie','moe'], 63380Sstevel@tonic-gate ['eenie','moe'],'true',\%labels, 63390Sstevel@tonic-gate {'moe'=>{'class'=>'red'}}); 63400Sstevel@tonic-gate 63410Sstevel@tonic-gate HTML3-COMPATIBLE BROWSERS ONLY: 63420Sstevel@tonic-gate 6343667Sps156622 print checkbox_group(-name=>'group_name', 63440Sstevel@tonic-gate -values=>['eenie','meenie','minie','moe'], 63450Sstevel@tonic-gate -rows=2,-columns=>2); 63460Sstevel@tonic-gate 63470Sstevel@tonic-gate 63480Sstevel@tonic-gatecheckbox_group() creates a list of checkboxes that are related 63490Sstevel@tonic-gateby the same name. 63500Sstevel@tonic-gate 63510Sstevel@tonic-gate=over 4 63520Sstevel@tonic-gate 63530Sstevel@tonic-gate=item B<Parameters:> 63540Sstevel@tonic-gate 63550Sstevel@tonic-gate=item 1. 63560Sstevel@tonic-gate 63570Sstevel@tonic-gateThe first and second arguments are the checkbox name and values, 63580Sstevel@tonic-gaterespectively (-name and -values). As in the popup menu, the second 63590Sstevel@tonic-gateargument should be an array reference. These values are used for the 63600Sstevel@tonic-gateuser-readable labels printed next to the checkboxes as well as for the 63610Sstevel@tonic-gatevalues passed to your script in the query string. 63620Sstevel@tonic-gate 63630Sstevel@tonic-gate=item 2. 63640Sstevel@tonic-gate 63650Sstevel@tonic-gateThe optional third argument (-default) can be either a reference to a 63660Sstevel@tonic-gatelist containing the values to be checked by default, or can be a 63670Sstevel@tonic-gatesingle value to checked. If this argument is missing or undefined, 63680Sstevel@tonic-gatethen nothing is selected when the list first appears. 63690Sstevel@tonic-gate 63700Sstevel@tonic-gate=item 3. 63710Sstevel@tonic-gate 63720Sstevel@tonic-gateThe optional fourth argument (-linebreak) can be set to true to place 63730Sstevel@tonic-gateline breaks between the checkboxes so that they appear as a vertical 63740Sstevel@tonic-gatelist. Otherwise, they will be strung together on a horizontal line. 63750Sstevel@tonic-gate 63760Sstevel@tonic-gate=back 63770Sstevel@tonic-gate 6378667Sps156622 6379667Sps156622The optional b<-labels> argument is a pointer to an associative array 6380667Sps156622relating the checkbox values to the user-visible labels that will be 6381667Sps156622printed next to them. If not provided, the values will be used as the 6382667Sps156622default. 6383667Sps156622 6384667Sps156622 6385*6287Sps156622The optional parameters B<-rows>, and B<-columns> cause 6386*6287Sps156622checkbox_group() to return an HTML3 compatible table containing the 6387*6287Sps156622checkbox group formatted with the specified number of rows and 6388*6287Sps156622columns. You can provide just the -columns parameter if you wish; 6389*6287Sps156622checkbox_group will calculate the correct number of rows for you. 6390*6287Sps156622 6391*6287Sps156622The option b<-disabled> takes an array of checkbox values and disables 6392*6287Sps156622them by greying them out (this may not be supported by all browsers). 6393667Sps156622 6394667Sps156622The optional B<-attributes> argument is provided to assign any of the 6395667Sps156622common HTML attributes to an individual menu item. It's a pointer to 6396667Sps156622an associative array relating menu values to another associative array 6397667Sps156622with the attribute's name as the key and the attribute's value as the 6398667Sps156622value. 6399667Sps156622 6400667Sps156622The optional B<-tabindex> argument can be used to control the order in which 6401667Sps156622radio buttons receive focus when the user presses the tab button. If 6402667Sps156622passed a scalar numeric value, the first element in the group will 6403667Sps156622receive this tab index and subsequent elements will be incremented by 6404667Sps156622one. If given a reference to an array of radio button values, then 6405667Sps156622the indexes will be jiggered so that the order specified in the array 6406667Sps156622will correspond to the tab order. You can also pass a reference to a 6407667Sps156622hash in which the hash keys are the radio button values and the values 6408667Sps156622are the tab indexes of each button. Examples: 6409667Sps156622 6410667Sps156622 -tabindex => 100 # this group starts at index 100 and counts up 6411667Sps156622 -tabindex => ['moe','minie','eenie','meenie'] # tab in this order 6412667Sps156622 -tabindex => {meenie=>100,moe=>101,minie=>102,eenie=>200} # tab in this order 6413667Sps156622 6414*6287Sps156622The optional B<-labelattributes> argument will contain attributes 6415*6287Sps156622attached to the <label> element that surrounds each button. 6416*6287Sps156622 64170Sstevel@tonic-gateWhen the form is processed, all checked boxes will be returned as 64180Sstevel@tonic-gatea list under the parameter name 'group_name'. The values of the 64190Sstevel@tonic-gate"on" checkboxes can be retrieved with: 64200Sstevel@tonic-gate 6421667Sps156622 @turned_on = param('group_name'); 64220Sstevel@tonic-gate 64230Sstevel@tonic-gateThe value returned by checkbox_group() is actually an array of button 64240Sstevel@tonic-gateelements. You can capture them and use them within tables, lists, 64250Sstevel@tonic-gateor in other creative ways: 64260Sstevel@tonic-gate 6427667Sps156622 @h = checkbox_group(-name=>'group_name',-values=>\@values); 64280Sstevel@tonic-gate &use_in_creative_way(@h); 64290Sstevel@tonic-gate 64300Sstevel@tonic-gate=head2 CREATING A STANDALONE CHECKBOX 64310Sstevel@tonic-gate 6432667Sps156622 print checkbox(-name=>'checkbox_name', 64330Sstevel@tonic-gate -checked=>1, 64340Sstevel@tonic-gate -value=>'ON', 64350Sstevel@tonic-gate -label=>'CLICK ME'); 64360Sstevel@tonic-gate 64370Sstevel@tonic-gate -or- 64380Sstevel@tonic-gate 6439667Sps156622 print checkbox('checkbox_name','checked','ON','CLICK ME'); 64400Sstevel@tonic-gate 64410Sstevel@tonic-gatecheckbox() is used to create an isolated checkbox that isn't logically 64420Sstevel@tonic-gaterelated to any others. 64430Sstevel@tonic-gate 64440Sstevel@tonic-gate=over 4 64450Sstevel@tonic-gate 64460Sstevel@tonic-gate=item B<Parameters:> 64470Sstevel@tonic-gate 64480Sstevel@tonic-gate=item 1. 64490Sstevel@tonic-gate 64500Sstevel@tonic-gateThe first parameter is the required name for the checkbox (-name). It 64510Sstevel@tonic-gatewill also be used for the user-readable label printed next to the 64520Sstevel@tonic-gatecheckbox. 64530Sstevel@tonic-gate 64540Sstevel@tonic-gate=item 2. 64550Sstevel@tonic-gate 64560Sstevel@tonic-gateThe optional second parameter (-checked) specifies that the checkbox 64570Sstevel@tonic-gateis turned on by default. Synonyms are -selected and -on. 64580Sstevel@tonic-gate 64590Sstevel@tonic-gate=item 3. 64600Sstevel@tonic-gate 64610Sstevel@tonic-gateThe optional third parameter (-value) specifies the value of the 64620Sstevel@tonic-gatecheckbox when it is checked. If not provided, the word "on" is 64630Sstevel@tonic-gateassumed. 64640Sstevel@tonic-gate 64650Sstevel@tonic-gate=item 4. 64660Sstevel@tonic-gate 64670Sstevel@tonic-gateThe optional fourth parameter (-label) is the user-readable label to 64680Sstevel@tonic-gatebe attached to the checkbox. If not provided, the checkbox name is 64690Sstevel@tonic-gateused. 64700Sstevel@tonic-gate 64710Sstevel@tonic-gate=back 64720Sstevel@tonic-gate 64730Sstevel@tonic-gateThe value of the checkbox can be retrieved using: 64740Sstevel@tonic-gate 6475667Sps156622 $turned_on = param('checkbox_name'); 64760Sstevel@tonic-gate 64770Sstevel@tonic-gate=head2 CREATING A RADIO BUTTON GROUP 64780Sstevel@tonic-gate 6479667Sps156622 print radio_group(-name=>'group_name', 64800Sstevel@tonic-gate -values=>['eenie','meenie','minie'], 64810Sstevel@tonic-gate -default=>'meenie', 64820Sstevel@tonic-gate -linebreak=>'true', 64830Sstevel@tonic-gate -labels=>\%labels, 64840Sstevel@tonic-gate -attributes=>\%attributes); 64850Sstevel@tonic-gate 64860Sstevel@tonic-gate -or- 64870Sstevel@tonic-gate 6488667Sps156622 print radio_group('group_name',['eenie','meenie','minie'], 64890Sstevel@tonic-gate 'meenie','true',\%labels,\%attributes); 64900Sstevel@tonic-gate 64910Sstevel@tonic-gate 64920Sstevel@tonic-gate HTML3-COMPATIBLE BROWSERS ONLY: 64930Sstevel@tonic-gate 6494667Sps156622 print radio_group(-name=>'group_name', 64950Sstevel@tonic-gate -values=>['eenie','meenie','minie','moe'], 64960Sstevel@tonic-gate -rows=2,-columns=>2); 64970Sstevel@tonic-gate 64980Sstevel@tonic-gateradio_group() creates a set of logically-related radio buttons 64990Sstevel@tonic-gate(turning one member of the group on turns the others off) 65000Sstevel@tonic-gate 65010Sstevel@tonic-gate=over 4 65020Sstevel@tonic-gate 65030Sstevel@tonic-gate=item B<Parameters:> 65040Sstevel@tonic-gate 65050Sstevel@tonic-gate=item 1. 65060Sstevel@tonic-gate 65070Sstevel@tonic-gateThe first argument is the name of the group and is required (-name). 65080Sstevel@tonic-gate 65090Sstevel@tonic-gate=item 2. 65100Sstevel@tonic-gate 65110Sstevel@tonic-gateThe second argument (-values) is the list of values for the radio 65120Sstevel@tonic-gatebuttons. The values and the labels that appear on the page are 65130Sstevel@tonic-gateidentical. Pass an array I<reference> in the second argument, either 65140Sstevel@tonic-gateusing an anonymous array, as shown, or by referencing a named array as 65150Sstevel@tonic-gatein "\@foo". 65160Sstevel@tonic-gate 65170Sstevel@tonic-gate=item 3. 65180Sstevel@tonic-gate 65190Sstevel@tonic-gateThe optional third parameter (-default) is the name of the default 65200Sstevel@tonic-gatebutton to turn on. If not specified, the first item will be the 65210Sstevel@tonic-gatedefault. You can provide a nonexistent button name, such as "-" to 65220Sstevel@tonic-gatestart up with no buttons selected. 65230Sstevel@tonic-gate 65240Sstevel@tonic-gate=item 4. 65250Sstevel@tonic-gate 65260Sstevel@tonic-gateThe optional fourth parameter (-linebreak) can be set to 'true' to put 65270Sstevel@tonic-gateline breaks between the buttons, creating a vertical list. 65280Sstevel@tonic-gate 65290Sstevel@tonic-gate=item 5. 65300Sstevel@tonic-gate 65310Sstevel@tonic-gateThe optional fifth parameter (-labels) is a pointer to an associative 65320Sstevel@tonic-gatearray relating the radio button values to user-visible labels to be 65330Sstevel@tonic-gateused in the display. If not provided, the values themselves are 65340Sstevel@tonic-gatedisplayed. 65350Sstevel@tonic-gate 6536667Sps156622=back 6537667Sps156622 6538667Sps156622 6539667Sps156622All modern browsers can take advantage of the optional parameters 6540667Sps156622B<-rows>, and B<-columns>. These parameters cause radio_group() to 6541667Sps156622return an HTML3 compatible table containing the radio group formatted 6542667Sps156622with the specified number of rows and columns. You can provide just 6543667Sps156622the -columns parameter if you wish; radio_group will calculate the 6544667Sps156622correct number of rows for you. 65450Sstevel@tonic-gate 65460Sstevel@tonic-gateTo include row and column headings in the returned table, you 6547*6287Sps156622can use the B<-rowheaders> and B<-colheaders> parameters. Both 65480Sstevel@tonic-gateof these accept a pointer to an array of headings to use. 65490Sstevel@tonic-gateThe headings are just decorative. They don't reorganize the 65500Sstevel@tonic-gateinterpretation of the radio buttons -- they're still a single named 65510Sstevel@tonic-gateunit. 65520Sstevel@tonic-gate 6553667Sps156622The optional B<-tabindex> argument can be used to control the order in which 6554667Sps156622radio buttons receive focus when the user presses the tab button. If 6555667Sps156622passed a scalar numeric value, the first element in the group will 6556667Sps156622receive this tab index and subsequent elements will be incremented by 6557667Sps156622one. If given a reference to an array of radio button values, then 6558667Sps156622the indexes will be jiggered so that the order specified in the array 6559667Sps156622will correspond to the tab order. You can also pass a reference to a 6560667Sps156622hash in which the hash keys are the radio button values and the values 6561667Sps156622are the tab indexes of each button. Examples: 6562667Sps156622 6563667Sps156622 -tabindex => 100 # this group starts at index 100 and counts up 6564667Sps156622 -tabindex => ['moe','minie','eenie','meenie'] # tab in this order 6565667Sps156622 -tabindex => {meenie=>100,moe=>101,minie=>102,eenie=>200} # tab in this order 6566667Sps156622 6567667Sps156622 6568667Sps156622The optional B<-attributes> argument is provided to assign any of the 6569667Sps156622common HTML attributes to an individual menu item. It's a pointer to 6570667Sps156622an associative array relating menu values to another associative array 6571667Sps156622with the attribute's name as the key and the attribute's value as the 6572667Sps156622value. 65730Sstevel@tonic-gate 6574*6287Sps156622The optional B<-labelattributes> argument will contain attributes 6575*6287Sps156622attached to the <label> element that surrounds each button. 6576*6287Sps156622 65770Sstevel@tonic-gateWhen the form is processed, the selected radio button can 65780Sstevel@tonic-gatebe retrieved using: 65790Sstevel@tonic-gate 6580667Sps156622 $which_radio_button = param('group_name'); 65810Sstevel@tonic-gate 65820Sstevel@tonic-gateThe value returned by radio_group() is actually an array of button 65830Sstevel@tonic-gateelements. You can capture them and use them within tables, lists, 65840Sstevel@tonic-gateor in other creative ways: 65850Sstevel@tonic-gate 6586667Sps156622 @h = radio_group(-name=>'group_name',-values=>\@values); 65870Sstevel@tonic-gate &use_in_creative_way(@h); 65880Sstevel@tonic-gate 65890Sstevel@tonic-gate=head2 CREATING A SUBMIT BUTTON 65900Sstevel@tonic-gate 6591667Sps156622 print submit(-name=>'button_name', 65920Sstevel@tonic-gate -value=>'value'); 65930Sstevel@tonic-gate 65940Sstevel@tonic-gate -or- 65950Sstevel@tonic-gate 6596667Sps156622 print submit('button_name','value'); 65970Sstevel@tonic-gate 65980Sstevel@tonic-gatesubmit() will create the query submission button. Every form 65990Sstevel@tonic-gateshould have one of these. 66000Sstevel@tonic-gate 66010Sstevel@tonic-gate=over 4 66020Sstevel@tonic-gate 66030Sstevel@tonic-gate=item B<Parameters:> 66040Sstevel@tonic-gate 66050Sstevel@tonic-gate=item 1. 66060Sstevel@tonic-gate 66070Sstevel@tonic-gateThe first argument (-name) is optional. You can give the button a 66080Sstevel@tonic-gatename if you have several submission buttons in your form and you want 6609667Sps156622to distinguish between them. 66100Sstevel@tonic-gate 66110Sstevel@tonic-gate=item 2. 66120Sstevel@tonic-gate 66130Sstevel@tonic-gateThe second argument (-value) is also optional. This gives the button 6614667Sps156622a value that will be passed to your script in the query string. The 6615667Sps156622name will also be used as the user-visible label. 6616667Sps156622 6617667Sps156622=item 3. 6618667Sps156622 6619667Sps156622You can use -label as an alias for -value. I always get confused 6620667Sps156622about which of -name and -value changes the user-visible label on the 6621667Sps156622button. 66220Sstevel@tonic-gate 66230Sstevel@tonic-gate=back 66240Sstevel@tonic-gate 66250Sstevel@tonic-gateYou can figure out which button was pressed by using different 66260Sstevel@tonic-gatevalues for each one: 66270Sstevel@tonic-gate 6628667Sps156622 $which_one = param('button_name'); 66290Sstevel@tonic-gate 66300Sstevel@tonic-gate=head2 CREATING A RESET BUTTON 66310Sstevel@tonic-gate 6632667Sps156622 print reset 66330Sstevel@tonic-gate 66340Sstevel@tonic-gatereset() creates the "reset" button. Note that it restores the 66350Sstevel@tonic-gateform to its value from the last time the script was called, 66360Sstevel@tonic-gateNOT necessarily to the defaults. 66370Sstevel@tonic-gate 66380Sstevel@tonic-gateNote that this conflicts with the Perl reset() built-in. Use 66390Sstevel@tonic-gateCORE::reset() to get the original reset function. 66400Sstevel@tonic-gate 66410Sstevel@tonic-gate=head2 CREATING A DEFAULT BUTTON 66420Sstevel@tonic-gate 6643667Sps156622 print defaults('button_label') 66440Sstevel@tonic-gate 66450Sstevel@tonic-gatedefaults() creates a button that, when invoked, will cause the 66460Sstevel@tonic-gateform to be completely reset to its defaults, wiping out all the 66470Sstevel@tonic-gatechanges the user ever made. 66480Sstevel@tonic-gate 66490Sstevel@tonic-gate=head2 CREATING A HIDDEN FIELD 66500Sstevel@tonic-gate 6651667Sps156622 print hidden(-name=>'hidden_name', 66520Sstevel@tonic-gate -default=>['value1','value2'...]); 66530Sstevel@tonic-gate 66540Sstevel@tonic-gate -or- 66550Sstevel@tonic-gate 6656667Sps156622 print hidden('hidden_name','value1','value2'...); 66570Sstevel@tonic-gate 66580Sstevel@tonic-gatehidden() produces a text field that can't be seen by the user. It 66590Sstevel@tonic-gateis useful for passing state variable information from one invocation 66600Sstevel@tonic-gateof the script to the next. 66610Sstevel@tonic-gate 66620Sstevel@tonic-gate=over 4 66630Sstevel@tonic-gate 66640Sstevel@tonic-gate=item B<Parameters:> 66650Sstevel@tonic-gate 66660Sstevel@tonic-gate=item 1. 66670Sstevel@tonic-gate 66680Sstevel@tonic-gateThe first argument is required and specifies the name of this 66690Sstevel@tonic-gatefield (-name). 66700Sstevel@tonic-gate 66710Sstevel@tonic-gate=item 2. 66720Sstevel@tonic-gate 66730Sstevel@tonic-gateThe second argument is also required and specifies its value 66740Sstevel@tonic-gate(-default). In the named parameter style of calling, you can provide 66750Sstevel@tonic-gatea single value here or a reference to a whole list 66760Sstevel@tonic-gate 66770Sstevel@tonic-gate=back 66780Sstevel@tonic-gate 66790Sstevel@tonic-gateFetch the value of a hidden field this way: 66800Sstevel@tonic-gate 6681667Sps156622 $hidden_value = param('hidden_name'); 66820Sstevel@tonic-gate 66830Sstevel@tonic-gateNote, that just like all the other form elements, the value of a 66840Sstevel@tonic-gatehidden field is "sticky". If you want to replace a hidden field with 66850Sstevel@tonic-gatesome other values after the script has been called once you'll have to 66860Sstevel@tonic-gatedo it manually: 66870Sstevel@tonic-gate 6688667Sps156622 param('hidden_name','new','values','here'); 66890Sstevel@tonic-gate 66900Sstevel@tonic-gate=head2 CREATING A CLICKABLE IMAGE BUTTON 66910Sstevel@tonic-gate 6692667Sps156622 print image_button(-name=>'button_name', 66930Sstevel@tonic-gate -src=>'/source/URL', 66940Sstevel@tonic-gate -align=>'MIDDLE'); 66950Sstevel@tonic-gate 66960Sstevel@tonic-gate -or- 66970Sstevel@tonic-gate 6698667Sps156622 print image_button('button_name','/source/URL','MIDDLE'); 66990Sstevel@tonic-gate 67000Sstevel@tonic-gateimage_button() produces a clickable image. When it's clicked on the 67010Sstevel@tonic-gateposition of the click is returned to your script as "button_name.x" 67020Sstevel@tonic-gateand "button_name.y", where "button_name" is the name you've assigned 67030Sstevel@tonic-gateto it. 67040Sstevel@tonic-gate 67050Sstevel@tonic-gate=over 4 67060Sstevel@tonic-gate 67070Sstevel@tonic-gate=item B<Parameters:> 67080Sstevel@tonic-gate 67090Sstevel@tonic-gate=item 1. 67100Sstevel@tonic-gate 67110Sstevel@tonic-gateThe first argument (-name) is required and specifies the name of this 67120Sstevel@tonic-gatefield. 67130Sstevel@tonic-gate 67140Sstevel@tonic-gate=item 2. 67150Sstevel@tonic-gate 67160Sstevel@tonic-gateThe second argument (-src) is also required and specifies the URL 67170Sstevel@tonic-gate 67180Sstevel@tonic-gate=item 3. 67190Sstevel@tonic-gateThe third option (-align, optional) is an alignment type, and may be 67200Sstevel@tonic-gateTOP, BOTTOM or MIDDLE 67210Sstevel@tonic-gate 67220Sstevel@tonic-gate=back 67230Sstevel@tonic-gate 67240Sstevel@tonic-gateFetch the value of the button this way: 6725667Sps156622 $x = param('button_name.x'); 6726667Sps156622 $y = param('button_name.y'); 67270Sstevel@tonic-gate 67280Sstevel@tonic-gate=head2 CREATING A JAVASCRIPT ACTION BUTTON 67290Sstevel@tonic-gate 6730667Sps156622 print button(-name=>'button_name', 67310Sstevel@tonic-gate -value=>'user visible label', 67320Sstevel@tonic-gate -onClick=>"do_something()"); 67330Sstevel@tonic-gate 67340Sstevel@tonic-gate -or- 67350Sstevel@tonic-gate 6736667Sps156622 print button('button_name',"do_something()"); 67370Sstevel@tonic-gate 67380Sstevel@tonic-gatebutton() produces a button that is compatible with Netscape 2.0's 67390Sstevel@tonic-gateJavaScript. When it's pressed the fragment of JavaScript code 67400Sstevel@tonic-gatepointed to by the B<-onClick> parameter will be executed. On 67410Sstevel@tonic-gatenon-Netscape browsers this form element will probably not even 67420Sstevel@tonic-gatedisplay. 67430Sstevel@tonic-gate 67440Sstevel@tonic-gate=head1 HTTP COOKIES 67450Sstevel@tonic-gate 67460Sstevel@tonic-gateNetscape browsers versions 1.1 and higher, and all versions of 67470Sstevel@tonic-gateInternet Explorer, support a so-called "cookie" designed to help 67480Sstevel@tonic-gatemaintain state within a browser session. CGI.pm has several methods 67490Sstevel@tonic-gatethat support cookies. 67500Sstevel@tonic-gate 67510Sstevel@tonic-gateA cookie is a name=value pair much like the named parameters in a CGI 67520Sstevel@tonic-gatequery string. CGI scripts create one or more cookies and send 67530Sstevel@tonic-gatethem to the browser in the HTTP header. The browser maintains a list 67540Sstevel@tonic-gateof cookies that belong to a particular Web server, and returns them 67550Sstevel@tonic-gateto the CGI script during subsequent interactions. 67560Sstevel@tonic-gate 67570Sstevel@tonic-gateIn addition to the required name=value pair, each cookie has several 67580Sstevel@tonic-gateoptional attributes: 67590Sstevel@tonic-gate 67600Sstevel@tonic-gate=over 4 67610Sstevel@tonic-gate 67620Sstevel@tonic-gate=item 1. an expiration time 67630Sstevel@tonic-gate 67640Sstevel@tonic-gateThis is a time/date string (in a special GMT format) that indicates 67650Sstevel@tonic-gatewhen a cookie expires. The cookie will be saved and returned to your 67660Sstevel@tonic-gatescript until this expiration date is reached if the user exits 67670Sstevel@tonic-gatethe browser and restarts it. If an expiration date isn't specified, the cookie 67680Sstevel@tonic-gatewill remain active until the user quits the browser. 67690Sstevel@tonic-gate 67700Sstevel@tonic-gate=item 2. a domain 67710Sstevel@tonic-gate 67720Sstevel@tonic-gateThis is a partial or complete domain name for which the cookie is 67730Sstevel@tonic-gatevalid. The browser will return the cookie to any host that matches 67740Sstevel@tonic-gatethe partial domain name. For example, if you specify a domain name 67750Sstevel@tonic-gateof ".capricorn.com", then the browser will return the cookie to 67760Sstevel@tonic-gateWeb servers running on any of the machines "www.capricorn.com", 67770Sstevel@tonic-gate"www2.capricorn.com", "feckless.capricorn.com", etc. Domain names 67780Sstevel@tonic-gatemust contain at least two periods to prevent attempts to match 67790Sstevel@tonic-gateon top level domains like ".edu". If no domain is specified, then 67800Sstevel@tonic-gatethe browser will only return the cookie to servers on the host the 67810Sstevel@tonic-gatecookie originated from. 67820Sstevel@tonic-gate 67830Sstevel@tonic-gate=item 3. a path 67840Sstevel@tonic-gate 67850Sstevel@tonic-gateIf you provide a cookie path attribute, the browser will check it 67860Sstevel@tonic-gateagainst your script's URL before returning the cookie. For example, 67870Sstevel@tonic-gateif you specify the path "/cgi-bin", then the cookie will be returned 67880Sstevel@tonic-gateto each of the scripts "/cgi-bin/tally.pl", "/cgi-bin/order.pl", 67890Sstevel@tonic-gateand "/cgi-bin/customer_service/complain.pl", but not to the script 67900Sstevel@tonic-gate"/cgi-private/site_admin.pl". By default, path is set to "/", which 67910Sstevel@tonic-gatecauses the cookie to be sent to any CGI script on your site. 67920Sstevel@tonic-gate 67930Sstevel@tonic-gate=item 4. a "secure" flag 67940Sstevel@tonic-gate 67950Sstevel@tonic-gateIf the "secure" attribute is set, the cookie will only be sent to your 67960Sstevel@tonic-gatescript if the CGI request is occurring on a secure channel, such as SSL. 67970Sstevel@tonic-gate 67980Sstevel@tonic-gate=back 67990Sstevel@tonic-gate 68000Sstevel@tonic-gateThe interface to HTTP cookies is the B<cookie()> method: 68010Sstevel@tonic-gate 6802667Sps156622 $cookie = cookie(-name=>'sessionID', 68030Sstevel@tonic-gate -value=>'xyzzy', 68040Sstevel@tonic-gate -expires=>'+1h', 68050Sstevel@tonic-gate -path=>'/cgi-bin/database', 68060Sstevel@tonic-gate -domain=>'.capricorn.org', 68070Sstevel@tonic-gate -secure=>1); 6808667Sps156622 print header(-cookie=>$cookie); 68090Sstevel@tonic-gate 68100Sstevel@tonic-gateB<cookie()> creates a new cookie. Its parameters include: 68110Sstevel@tonic-gate 68120Sstevel@tonic-gate=over 4 68130Sstevel@tonic-gate 68140Sstevel@tonic-gate=item B<-name> 68150Sstevel@tonic-gate 68160Sstevel@tonic-gateThe name of the cookie (required). This can be any string at all. 68170Sstevel@tonic-gateAlthough browsers limit their cookie names to non-whitespace 68180Sstevel@tonic-gatealphanumeric characters, CGI.pm removes this restriction by escaping 68190Sstevel@tonic-gateand unescaping cookies behind the scenes. 68200Sstevel@tonic-gate 68210Sstevel@tonic-gate=item B<-value> 68220Sstevel@tonic-gate 68230Sstevel@tonic-gateThe value of the cookie. This can be any scalar value, 68240Sstevel@tonic-gatearray reference, or even associative array reference. For example, 68250Sstevel@tonic-gateyou can store an entire associative array into a cookie this way: 68260Sstevel@tonic-gate 6827667Sps156622 $cookie=cookie(-name=>'family information', 68280Sstevel@tonic-gate -value=>\%childrens_ages); 68290Sstevel@tonic-gate 68300Sstevel@tonic-gate=item B<-path> 68310Sstevel@tonic-gate 68320Sstevel@tonic-gateThe optional partial path for which this cookie will be valid, as described 68330Sstevel@tonic-gateabove. 68340Sstevel@tonic-gate 68350Sstevel@tonic-gate=item B<-domain> 68360Sstevel@tonic-gate 68370Sstevel@tonic-gateThe optional partial domain for which this cookie will be valid, as described 68380Sstevel@tonic-gateabove. 68390Sstevel@tonic-gate 68400Sstevel@tonic-gate=item B<-expires> 68410Sstevel@tonic-gate 68420Sstevel@tonic-gateThe optional expiration date for this cookie. The format is as described 68430Sstevel@tonic-gatein the section on the B<header()> method: 68440Sstevel@tonic-gate 68450Sstevel@tonic-gate "+1h" one hour from now 68460Sstevel@tonic-gate 68470Sstevel@tonic-gate=item B<-secure> 68480Sstevel@tonic-gate 68490Sstevel@tonic-gateIf set to true, this cookie will only be used within a secure 68500Sstevel@tonic-gateSSL session. 68510Sstevel@tonic-gate 68520Sstevel@tonic-gate=back 68530Sstevel@tonic-gate 68540Sstevel@tonic-gateThe cookie created by cookie() must be incorporated into the HTTP 68550Sstevel@tonic-gateheader within the string returned by the header() method: 68560Sstevel@tonic-gate 6857*6287Sps156622 use CGI ':standard'; 6858667Sps156622 print header(-cookie=>$my_cookie); 68590Sstevel@tonic-gate 68600Sstevel@tonic-gateTo create multiple cookies, give header() an array reference: 68610Sstevel@tonic-gate 6862667Sps156622 $cookie1 = cookie(-name=>'riddle_name', 68630Sstevel@tonic-gate -value=>"The Sphynx's Question"); 6864667Sps156622 $cookie2 = cookie(-name=>'answers', 68650Sstevel@tonic-gate -value=>\%answers); 6866667Sps156622 print header(-cookie=>[$cookie1,$cookie2]); 68670Sstevel@tonic-gate 68680Sstevel@tonic-gateTo retrieve a cookie, request it by name by calling cookie() method 6869*6287Sps156622without the B<-value> parameter. This example uses the object-oriented 6870*6287Sps156622form: 68710Sstevel@tonic-gate 68720Sstevel@tonic-gate use CGI; 68730Sstevel@tonic-gate $query = new CGI; 6874*6287Sps156622 $riddle = $query->cookie('riddle_name'); 6875*6287Sps156622 %answers = $query->cookie('answers'); 68760Sstevel@tonic-gate 68770Sstevel@tonic-gateCookies created with a single scalar value, such as the "riddle_name" 68780Sstevel@tonic-gatecookie, will be returned in that form. Cookies with array and hash 68790Sstevel@tonic-gatevalues can also be retrieved. 68800Sstevel@tonic-gate 68810Sstevel@tonic-gateThe cookie and CGI namespaces are separate. If you have a parameter 68820Sstevel@tonic-gatenamed 'answers' and a cookie named 'answers', the values retrieved by 68830Sstevel@tonic-gateparam() and cookie() are independent of each other. However, it's 68840Sstevel@tonic-gatesimple to turn a CGI parameter into a cookie, and vice-versa: 68850Sstevel@tonic-gate 68860Sstevel@tonic-gate # turn a CGI parameter into a cookie 6887667Sps156622 $c=cookie(-name=>'answers',-value=>[param('answers')]); 68880Sstevel@tonic-gate # vice-versa 6889667Sps156622 param(-name=>'answers',-value=>[cookie('answers')]); 68900Sstevel@tonic-gate 6891*6287Sps156622If you call cookie() without any parameters, it will return a list of 6892*6287Sps156622the names of all cookies passed to your script: 6893*6287Sps156622 6894*6287Sps156622 @cookies = cookie(); 6895*6287Sps156622 68960Sstevel@tonic-gateSee the B<cookie.cgi> example script for some ideas on how to use 68970Sstevel@tonic-gatecookies effectively. 68980Sstevel@tonic-gate 68990Sstevel@tonic-gate=head1 WORKING WITH FRAMES 69000Sstevel@tonic-gate 69010Sstevel@tonic-gateIt's possible for CGI.pm scripts to write into several browser panels 69020Sstevel@tonic-gateand windows using the HTML 4 frame mechanism. There are three 69030Sstevel@tonic-gatetechniques for defining new frames programmatically: 69040Sstevel@tonic-gate 69050Sstevel@tonic-gate=over 4 69060Sstevel@tonic-gate 69070Sstevel@tonic-gate=item 1. Create a <Frameset> document 69080Sstevel@tonic-gate 69090Sstevel@tonic-gateAfter writing out the HTTP header, instead of creating a standard 69100Sstevel@tonic-gateHTML document using the start_html() call, create a <frameset> 69110Sstevel@tonic-gatedocument that defines the frames on the page. Specify your script(s) 69120Sstevel@tonic-gate(with appropriate parameters) as the SRC for each of the frames. 69130Sstevel@tonic-gate 69140Sstevel@tonic-gateThere is no specific support for creating <frameset> sections 69150Sstevel@tonic-gatein CGI.pm, but the HTML is very simple to write. See the frame 69160Sstevel@tonic-gatedocumentation in Netscape's home pages for details 69170Sstevel@tonic-gate 6918*6287Sps156622 http://wp.netscape.com/assist/net_sites/frames.html 69190Sstevel@tonic-gate 69200Sstevel@tonic-gate=item 2. Specify the destination for the document in the HTTP header 69210Sstevel@tonic-gate 69220Sstevel@tonic-gateYou may provide a B<-target> parameter to the header() method: 69230Sstevel@tonic-gate 6924667Sps156622 print header(-target=>'ResultsWindow'); 69250Sstevel@tonic-gate 69260Sstevel@tonic-gateThis will tell the browser to load the output of your script into the 69270Sstevel@tonic-gateframe named "ResultsWindow". If a frame of that name doesn't already 69280Sstevel@tonic-gateexist, the browser will pop up a new window and load your script's 69290Sstevel@tonic-gatedocument into that. There are a number of magic names that you can 69300Sstevel@tonic-gateuse for targets. See the frame documents on Netscape's home pages for 69310Sstevel@tonic-gatedetails. 69320Sstevel@tonic-gate 69330Sstevel@tonic-gate=item 3. Specify the destination for the document in the <form> tag 69340Sstevel@tonic-gate 69350Sstevel@tonic-gateYou can specify the frame to load in the FORM tag itself. With 69360Sstevel@tonic-gateCGI.pm it looks like this: 69370Sstevel@tonic-gate 6938667Sps156622 print start_form(-target=>'ResultsWindow'); 69390Sstevel@tonic-gate 69400Sstevel@tonic-gateWhen your script is reinvoked by the form, its output will be loaded 69410Sstevel@tonic-gateinto the frame named "ResultsWindow". If one doesn't already exist 69420Sstevel@tonic-gatea new window will be created. 69430Sstevel@tonic-gate 69440Sstevel@tonic-gate=back 69450Sstevel@tonic-gate 69460Sstevel@tonic-gateThe script "frameset.cgi" in the examples directory shows one way to 69470Sstevel@tonic-gatecreate pages in which the fill-out form and the response live in 69480Sstevel@tonic-gateside-by-side frames. 69490Sstevel@tonic-gate 6950667Sps156622=head1 SUPPORT FOR JAVASCRIPT 6951667Sps156622 6952667Sps156622Netscape versions 2.0 and higher incorporate an interpreted language 6953667Sps156622called JavaScript. Internet Explorer, 3.0 and higher, supports a 6954667Sps156622closely-related dialect called JScript. JavaScript isn't the same as 6955667Sps156622Java, and certainly isn't at all the same as Perl, which is a great 6956*6287Sps156622pity. JavaScript allows you to programmatically change the contents of 6957667Sps156622fill-out forms, create new windows, and pop up dialog box from within 6958667Sps156622Netscape itself. From the point of view of CGI scripting, JavaScript 6959667Sps156622is quite useful for validating fill-out forms prior to submitting 6960667Sps156622them. 6961667Sps156622 6962667Sps156622You'll need to know JavaScript in order to use it. There are many good 6963667Sps156622sources in bookstores and on the web. 6964667Sps156622 6965667Sps156622The usual way to use JavaScript is to define a set of functions in a 6966667Sps156622<SCRIPT> block inside the HTML header and then to register event 6967667Sps156622handlers in the various elements of the page. Events include such 6968667Sps156622things as the mouse passing over a form element, a button being 6969667Sps156622clicked, the contents of a text field changing, or a form being 6970667Sps156622submitted. When an event occurs that involves an element that has 6971667Sps156622registered an event handler, its associated JavaScript code gets 6972667Sps156622called. 6973667Sps156622 6974667Sps156622The elements that can register event handlers include the <BODY> of an 6975667Sps156622HTML document, hypertext links, all the various elements of a fill-out 6976667Sps156622form, and the form itself. There are a large number of events, and 6977667Sps156622each applies only to the elements for which it is relevant. Here is a 6978667Sps156622partial list: 6979667Sps156622 6980667Sps156622=over 4 6981667Sps156622 6982667Sps156622=item B<onLoad> 6983667Sps156622 6984667Sps156622The browser is loading the current document. Valid in: 6985667Sps156622 6986667Sps156622 + The HTML <BODY> section only. 6987667Sps156622 6988667Sps156622=item B<onUnload> 6989667Sps156622 6990667Sps156622The browser is closing the current page or frame. Valid for: 6991667Sps156622 6992667Sps156622 + The HTML <BODY> section only. 6993667Sps156622 6994667Sps156622=item B<onSubmit> 6995667Sps156622 6996667Sps156622The user has pressed the submit button of a form. This event happens 6997667Sps156622just before the form is submitted, and your function can return a 6998667Sps156622value of false in order to abort the submission. Valid for: 6999667Sps156622 7000667Sps156622 + Forms only. 7001667Sps156622 7002667Sps156622=item B<onClick> 7003667Sps156622 7004667Sps156622The mouse has clicked on an item in a fill-out form. Valid for: 7005667Sps156622 7006667Sps156622 + Buttons (including submit, reset, and image buttons) 7007667Sps156622 + Checkboxes 7008667Sps156622 + Radio buttons 7009667Sps156622 7010667Sps156622=item B<onChange> 7011667Sps156622 7012667Sps156622The user has changed the contents of a field. Valid for: 7013667Sps156622 7014667Sps156622 + Text fields 7015667Sps156622 + Text areas 7016667Sps156622 + Password fields 7017667Sps156622 + File fields 7018667Sps156622 + Popup Menus 7019667Sps156622 + Scrolling lists 7020667Sps156622 7021667Sps156622=item B<onFocus> 7022667Sps156622 7023667Sps156622The user has selected a field to work with. Valid for: 7024667Sps156622 7025667Sps156622 + Text fields 7026667Sps156622 + Text areas 7027667Sps156622 + Password fields 7028667Sps156622 + File fields 7029667Sps156622 + Popup Menus 7030667Sps156622 + Scrolling lists 7031667Sps156622 7032667Sps156622=item B<onBlur> 7033667Sps156622 7034667Sps156622The user has deselected a field (gone to work somewhere else). Valid 7035667Sps156622for: 7036667Sps156622 7037667Sps156622 + Text fields 7038667Sps156622 + Text areas 7039667Sps156622 + Password fields 7040667Sps156622 + File fields 7041667Sps156622 + Popup Menus 7042667Sps156622 + Scrolling lists 7043667Sps156622 7044667Sps156622=item B<onSelect> 7045667Sps156622 7046667Sps156622The user has changed the part of a text field that is selected. Valid 7047667Sps156622for: 7048667Sps156622 7049667Sps156622 + Text fields 7050667Sps156622 + Text areas 7051667Sps156622 + Password fields 7052667Sps156622 + File fields 7053667Sps156622 7054667Sps156622=item B<onMouseOver> 7055667Sps156622 7056667Sps156622The mouse has moved over an element. 7057667Sps156622 7058667Sps156622 + Text fields 7059667Sps156622 + Text areas 7060667Sps156622 + Password fields 7061667Sps156622 + File fields 7062667Sps156622 + Popup Menus 7063667Sps156622 + Scrolling lists 7064667Sps156622 7065667Sps156622=item B<onMouseOut> 7066667Sps156622 7067667Sps156622The mouse has moved off an element. 7068667Sps156622 7069667Sps156622 + Text fields 7070667Sps156622 + Text areas 7071667Sps156622 + Password fields 7072667Sps156622 + File fields 7073667Sps156622 + Popup Menus 7074667Sps156622 + Scrolling lists 7075667Sps156622 7076667Sps156622=back 7077667Sps156622 7078667Sps156622In order to register a JavaScript event handler with an HTML element, 7079667Sps156622just use the event name as a parameter when you call the corresponding 7080667Sps156622CGI method. For example, to have your validateAge() JavaScript code 7081667Sps156622executed every time the textfield named "age" changes, generate the 7082667Sps156622field like this: 7083667Sps156622 7084667Sps156622 print textfield(-name=>'age',-onChange=>"validateAge(this)"); 7085667Sps156622 7086667Sps156622This example assumes that you've already declared the validateAge() 7087667Sps156622function by incorporating it into a <SCRIPT> block. The CGI.pm 7088667Sps156622start_html() method provides a convenient way to create this section. 7089667Sps156622 7090667Sps156622Similarly, you can create a form that checks itself over for 7091667Sps156622consistency and alerts the user if some essential value is missing by 7092667Sps156622creating it this way: 7093667Sps156622 print startform(-onSubmit=>"validateMe(this)"); 7094667Sps156622 7095667Sps156622See the javascript.cgi script for a demonstration of how this all 7096667Sps156622works. 7097667Sps156622 7098667Sps156622 70990Sstevel@tonic-gate=head1 LIMITED SUPPORT FOR CASCADING STYLE SHEETS 71000Sstevel@tonic-gate 71010Sstevel@tonic-gateCGI.pm has limited support for HTML3's cascading style sheets (css). 71020Sstevel@tonic-gateTo incorporate a stylesheet into your document, pass the 71030Sstevel@tonic-gatestart_html() method a B<-style> parameter. The value of this 71040Sstevel@tonic-gateparameter may be a scalar, in which case it is treated as the source 71050Sstevel@tonic-gateURL for the stylesheet, or it may be a hash reference. In the latter 71060Sstevel@tonic-gatecase you should provide the hash with one or more of B<-src> or 71070Sstevel@tonic-gateB<-code>. B<-src> points to a URL where an externally-defined 71080Sstevel@tonic-gatestylesheet can be found. B<-code> points to a scalar value to be 71090Sstevel@tonic-gateincorporated into a <style> section. Style definitions in B<-code> 71100Sstevel@tonic-gateoverride similarly-named ones in B<-src>, hence the name "cascading." 71110Sstevel@tonic-gate 71120Sstevel@tonic-gateYou may also specify the type of the stylesheet by adding the optional 71130Sstevel@tonic-gateB<-type> parameter to the hash pointed to by B<-style>. If not 71140Sstevel@tonic-gatespecified, the style defaults to 'text/css'. 71150Sstevel@tonic-gate 71160Sstevel@tonic-gateTo refer to a style within the body of your document, add the 71170Sstevel@tonic-gateB<-class> parameter to any HTML element: 71180Sstevel@tonic-gate 71190Sstevel@tonic-gate print h1({-class=>'Fancy'},'Welcome to the Party'); 71200Sstevel@tonic-gate 71210Sstevel@tonic-gateOr define styles on the fly with the B<-style> parameter: 71220Sstevel@tonic-gate 71230Sstevel@tonic-gate print h1({-style=>'Color: red;'},'Welcome to Hell'); 71240Sstevel@tonic-gate 71250Sstevel@tonic-gateYou may also use the new B<span()> element to apply a style to a 71260Sstevel@tonic-gatesection of text: 71270Sstevel@tonic-gate 71280Sstevel@tonic-gate print span({-style=>'Color: red;'}, 71290Sstevel@tonic-gate h1('Welcome to Hell'), 71300Sstevel@tonic-gate "Where did that handbasket get to?" 71310Sstevel@tonic-gate ); 71320Sstevel@tonic-gate 71330Sstevel@tonic-gateNote that you must import the ":html3" definitions to have the 71340Sstevel@tonic-gateB<span()> method available. Here's a quick and dirty example of using 71350Sstevel@tonic-gateCSS's. See the CSS specification at 71360Sstevel@tonic-gatehttp://www.w3.org/pub/WWW/TR/Wd-css-1.html for more information. 71370Sstevel@tonic-gate 71380Sstevel@tonic-gate use CGI qw/:standard :html3/; 71390Sstevel@tonic-gate 71400Sstevel@tonic-gate #here's a stylesheet incorporated directly into the page 71410Sstevel@tonic-gate $newStyle=<<END; 71420Sstevel@tonic-gate <!-- 71430Sstevel@tonic-gate P.Tip { 71440Sstevel@tonic-gate margin-right: 50pt; 71450Sstevel@tonic-gate margin-left: 50pt; 71460Sstevel@tonic-gate color: red; 71470Sstevel@tonic-gate } 71480Sstevel@tonic-gate P.Alert { 71490Sstevel@tonic-gate font-size: 30pt; 71500Sstevel@tonic-gate font-family: sans-serif; 71510Sstevel@tonic-gate color: red; 71520Sstevel@tonic-gate } 71530Sstevel@tonic-gate --> 71540Sstevel@tonic-gate END 71550Sstevel@tonic-gate print header(); 71560Sstevel@tonic-gate print start_html( -title=>'CGI with Style', 71570Sstevel@tonic-gate -style=>{-src=>'http://www.capricorn.com/style/st1.css', 71580Sstevel@tonic-gate -code=>$newStyle} 71590Sstevel@tonic-gate ); 71600Sstevel@tonic-gate print h1('CGI with Style'), 71610Sstevel@tonic-gate p({-class=>'Tip'}, 71620Sstevel@tonic-gate "Better read the cascading style sheet spec before playing with this!"), 71630Sstevel@tonic-gate span({-style=>'color: magenta'}, 71640Sstevel@tonic-gate "Look Mom, no hands!", 71650Sstevel@tonic-gate p(), 71660Sstevel@tonic-gate "Whooo wee!" 71670Sstevel@tonic-gate ); 71680Sstevel@tonic-gate print end_html; 71690Sstevel@tonic-gate 7170667Sps156622Pass an array reference to B<-code> or B<-src> in order to incorporate 7171667Sps156622multiple stylesheets into your document. 71720Sstevel@tonic-gate 71730Sstevel@tonic-gateShould you wish to incorporate a verbatim stylesheet that includes 71740Sstevel@tonic-gatearbitrary formatting in the header, you may pass a -verbatim tag to 71750Sstevel@tonic-gatethe -style hash, as follows: 71760Sstevel@tonic-gate 7177*6287Sps156622print start_html (-style => {-verbatim => '@import url("/server-common/css/'.$cssFile.'");', 7178*6287Sps156622 -src => '/server-common/css/core.css'}); 71790Sstevel@tonic-gate 71800Sstevel@tonic-gate 71810Sstevel@tonic-gateThis will generate an HTML header that contains this: 71820Sstevel@tonic-gate 71830Sstevel@tonic-gate <link rel="stylesheet" type="text/css" href="/server-common/css/core.css"> 71840Sstevel@tonic-gate <style type="text/css"> 71850Sstevel@tonic-gate @import url("/server-common/css/main.css"); 71860Sstevel@tonic-gate </style> 71870Sstevel@tonic-gate 71880Sstevel@tonic-gateAny additional arguments passed in the -style value will be 71890Sstevel@tonic-gateincorporated into the <link> tag. For example: 71900Sstevel@tonic-gate 71910Sstevel@tonic-gate start_html(-style=>{-src=>['/styles/print.css','/styles/layout.css'], 71920Sstevel@tonic-gate -media => 'all'}); 71930Sstevel@tonic-gate 71940Sstevel@tonic-gateThis will give: 71950Sstevel@tonic-gate 71960Sstevel@tonic-gate <link rel="stylesheet" type="text/css" href="/styles/print.css" media="all"/> 71970Sstevel@tonic-gate <link rel="stylesheet" type="text/css" href="/styles/layout.css" media="all"/> 71980Sstevel@tonic-gate 71990Sstevel@tonic-gate<p> 72000Sstevel@tonic-gate 72010Sstevel@tonic-gateTo make more complicated <link> tags, use the Link() function 72020Sstevel@tonic-gateand pass it to start_html() in the -head argument, as in: 72030Sstevel@tonic-gate 72040Sstevel@tonic-gate @h = (Link({-rel=>'stylesheet',-type=>'text/css',-src=>'/ss/ss.css',-media=>'all'}), 72050Sstevel@tonic-gate Link({-rel=>'stylesheet',-type=>'text/css',-src=>'/ss/fred.css',-media=>'paper'})); 72060Sstevel@tonic-gate print start_html({-head=>\@h}) 72070Sstevel@tonic-gate 7208*6287Sps156622To create primary and "alternate" stylesheet, use the B<-alternate> option: 7209*6287Sps156622 7210*6287Sps156622 start_html(-style=>{-src=>[ 7211*6287Sps156622 {-src=>'/styles/print.css'}, 7212*6287Sps156622 {-src=>'/styles/alt.css',-alternate=>1} 7213*6287Sps156622 ] 7214*6287Sps156622 }); 7215*6287Sps156622 72160Sstevel@tonic-gate=head1 DEBUGGING 72170Sstevel@tonic-gate 72180Sstevel@tonic-gateIf you are running the script from the command line or in the perl 72190Sstevel@tonic-gatedebugger, you can pass the script a list of keywords or 72200Sstevel@tonic-gateparameter=value pairs on the command line or from standard input (you 72210Sstevel@tonic-gatedon't have to worry about tricking your script into reading from 72220Sstevel@tonic-gateenvironment variables). You can pass keywords like this: 72230Sstevel@tonic-gate 72240Sstevel@tonic-gate your_script.pl keyword1 keyword2 keyword3 72250Sstevel@tonic-gate 72260Sstevel@tonic-gateor this: 72270Sstevel@tonic-gate 72280Sstevel@tonic-gate your_script.pl keyword1+keyword2+keyword3 72290Sstevel@tonic-gate 72300Sstevel@tonic-gateor this: 72310Sstevel@tonic-gate 72320Sstevel@tonic-gate your_script.pl name1=value1 name2=value2 72330Sstevel@tonic-gate 72340Sstevel@tonic-gateor this: 72350Sstevel@tonic-gate 72360Sstevel@tonic-gate your_script.pl name1=value1&name2=value2 72370Sstevel@tonic-gate 72380Sstevel@tonic-gateTo turn off this feature, use the -no_debug pragma. 72390Sstevel@tonic-gate 72400Sstevel@tonic-gateTo test the POST method, you may enable full debugging with the -debug 72410Sstevel@tonic-gatepragma. This will allow you to feed newline-delimited name=value 72420Sstevel@tonic-gatepairs to the script on standard input. 72430Sstevel@tonic-gate 72440Sstevel@tonic-gateWhen debugging, you can use quotes and backslashes to escape 72450Sstevel@tonic-gatecharacters in the familiar shell manner, letting you place 72460Sstevel@tonic-gatespaces and other funny characters in your parameter=value 72470Sstevel@tonic-gatepairs: 72480Sstevel@tonic-gate 72490Sstevel@tonic-gate your_script.pl "name1='I am a long value'" "name2=two\ words" 72500Sstevel@tonic-gate 72510Sstevel@tonic-gateFinally, you can set the path info for the script by prefixing the first 72520Sstevel@tonic-gatename/value parameter with the path followed by a question mark (?): 72530Sstevel@tonic-gate 72540Sstevel@tonic-gate your_script.pl /your/path/here?name1=value1&name2=value2 72550Sstevel@tonic-gate 72560Sstevel@tonic-gate=head2 DUMPING OUT ALL THE NAME/VALUE PAIRS 72570Sstevel@tonic-gate 72580Sstevel@tonic-gateThe Dump() method produces a string consisting of all the query's 72590Sstevel@tonic-gatename/value pairs formatted nicely as a nested list. This is useful 72600Sstevel@tonic-gatefor debugging purposes: 72610Sstevel@tonic-gate 7262667Sps156622 print Dump 72630Sstevel@tonic-gate 72640Sstevel@tonic-gate 72650Sstevel@tonic-gateProduces something that looks like: 72660Sstevel@tonic-gate 72670Sstevel@tonic-gate <ul> 72680Sstevel@tonic-gate <li>name1 72690Sstevel@tonic-gate <ul> 72700Sstevel@tonic-gate <li>value1 72710Sstevel@tonic-gate <li>value2 72720Sstevel@tonic-gate </ul> 72730Sstevel@tonic-gate <li>name2 72740Sstevel@tonic-gate <ul> 72750Sstevel@tonic-gate <li>value1 72760Sstevel@tonic-gate </ul> 72770Sstevel@tonic-gate </ul> 72780Sstevel@tonic-gate 72790Sstevel@tonic-gateAs a shortcut, you can interpolate the entire CGI object into a string 72800Sstevel@tonic-gateand it will be replaced with the a nice HTML dump shown above: 72810Sstevel@tonic-gate 72820Sstevel@tonic-gate $query=new CGI; 72830Sstevel@tonic-gate print "<h2>Current Values</h2> $query\n"; 72840Sstevel@tonic-gate 72850Sstevel@tonic-gate=head1 FETCHING ENVIRONMENT VARIABLES 72860Sstevel@tonic-gate 72870Sstevel@tonic-gateSome of the more useful environment variables can be fetched 72880Sstevel@tonic-gatethrough this interface. The methods are as follows: 72890Sstevel@tonic-gate 72900Sstevel@tonic-gate=over 4 72910Sstevel@tonic-gate 72920Sstevel@tonic-gate=item B<Accept()> 72930Sstevel@tonic-gate 72940Sstevel@tonic-gateReturn a list of MIME types that the remote browser accepts. If you 72950Sstevel@tonic-gategive this method a single argument corresponding to a MIME type, as in 7296667Sps156622Accept('text/html'), it will return a floating point value 72970Sstevel@tonic-gatecorresponding to the browser's preference for this type from 0.0 72980Sstevel@tonic-gate(don't want) to 1.0. Glob types (e.g. text/*) in the browser's accept 72990Sstevel@tonic-gatelist are handled correctly. 73000Sstevel@tonic-gate 73010Sstevel@tonic-gateNote that the capitalization changed between version 2.43 and 2.44 in 73020Sstevel@tonic-gateorder to avoid conflict with Perl's accept() function. 73030Sstevel@tonic-gate 73040Sstevel@tonic-gate=item B<raw_cookie()> 73050Sstevel@tonic-gate 73060Sstevel@tonic-gateReturns the HTTP_COOKIE variable, an HTTP extension implemented by 73070Sstevel@tonic-gateNetscape browsers version 1.1 and higher, and all versions of Internet 73080Sstevel@tonic-gateExplorer. Cookies have a special format, and this method call just 73090Sstevel@tonic-gatereturns the raw form (?cookie dough). See cookie() for ways of 73100Sstevel@tonic-gatesetting and retrieving cooked cookies. 73110Sstevel@tonic-gate 73120Sstevel@tonic-gateCalled with no parameters, raw_cookie() returns the packed cookie 73130Sstevel@tonic-gatestructure. You can separate it into individual cookies by splitting 73140Sstevel@tonic-gateon the character sequence "; ". Called with the name of a cookie, 73150Sstevel@tonic-gateretrieves the B<unescaped> form of the cookie. You can use the 73160Sstevel@tonic-gateregular cookie() method to get the names, or use the raw_fetch() 73170Sstevel@tonic-gatemethod from the CGI::Cookie module. 73180Sstevel@tonic-gate 73190Sstevel@tonic-gate=item B<user_agent()> 73200Sstevel@tonic-gate 73210Sstevel@tonic-gateReturns the HTTP_USER_AGENT variable. If you give 73220Sstevel@tonic-gatethis method a single argument, it will attempt to 73230Sstevel@tonic-gatepattern match on it, allowing you to do something 7324667Sps156622like user_agent(netscape); 73250Sstevel@tonic-gate 73260Sstevel@tonic-gate=item B<path_info()> 73270Sstevel@tonic-gate 73280Sstevel@tonic-gateReturns additional path information from the script URL. 73290Sstevel@tonic-gateE.G. fetching /cgi-bin/your_script/additional/stuff will result in 7330667Sps156622path_info() returning "/additional/stuff". 73310Sstevel@tonic-gate 73320Sstevel@tonic-gateNOTE: The Microsoft Internet Information Server 73330Sstevel@tonic-gateis broken with respect to additional path information. If 73340Sstevel@tonic-gateyou use the Perl DLL library, the IIS server will attempt to 73350Sstevel@tonic-gateexecute the additional path information as a Perl script. 73360Sstevel@tonic-gateIf you use the ordinary file associations mapping, the 73370Sstevel@tonic-gatepath information will be present in the environment, 73380Sstevel@tonic-gatebut incorrect. The best thing to do is to avoid using additional 73390Sstevel@tonic-gatepath information in CGI scripts destined for use with IIS. 73400Sstevel@tonic-gate 73410Sstevel@tonic-gate=item B<path_translated()> 73420Sstevel@tonic-gate 73430Sstevel@tonic-gateAs per path_info() but returns the additional 73440Sstevel@tonic-gatepath information translated into a physical path, e.g. 73450Sstevel@tonic-gate"/usr/local/etc/httpd/htdocs/additional/stuff". 73460Sstevel@tonic-gate 73470Sstevel@tonic-gateThe Microsoft IIS is broken with respect to the translated 73480Sstevel@tonic-gatepath as well. 73490Sstevel@tonic-gate 73500Sstevel@tonic-gate=item B<remote_host()> 73510Sstevel@tonic-gate 73520Sstevel@tonic-gateReturns either the remote host name or IP address. 73530Sstevel@tonic-gateif the former is unavailable. 73540Sstevel@tonic-gate 73550Sstevel@tonic-gate=item B<script_name()> 73560Sstevel@tonic-gateReturn the script name as a partial URL, for self-refering 73570Sstevel@tonic-gatescripts. 73580Sstevel@tonic-gate 73590Sstevel@tonic-gate=item B<referer()> 73600Sstevel@tonic-gate 73610Sstevel@tonic-gateReturn the URL of the page the browser was viewing 73620Sstevel@tonic-gateprior to fetching your script. Not available for all 73630Sstevel@tonic-gatebrowsers. 73640Sstevel@tonic-gate 73650Sstevel@tonic-gate=item B<auth_type ()> 73660Sstevel@tonic-gate 73670Sstevel@tonic-gateReturn the authorization/verification method in use for this 73680Sstevel@tonic-gatescript, if any. 73690Sstevel@tonic-gate 73700Sstevel@tonic-gate=item B<server_name ()> 73710Sstevel@tonic-gate 73720Sstevel@tonic-gateReturns the name of the server, usually the machine's host 73730Sstevel@tonic-gatename. 73740Sstevel@tonic-gate 73750Sstevel@tonic-gate=item B<virtual_host ()> 73760Sstevel@tonic-gate 73770Sstevel@tonic-gateWhen using virtual hosts, returns the name of the host that 73780Sstevel@tonic-gatethe browser attempted to contact 73790Sstevel@tonic-gate 73800Sstevel@tonic-gate=item B<server_port ()> 73810Sstevel@tonic-gate 73820Sstevel@tonic-gateReturn the port that the server is listening on. 73830Sstevel@tonic-gate 73840Sstevel@tonic-gate=item B<virtual_port ()> 73850Sstevel@tonic-gate 73860Sstevel@tonic-gateLike server_port() except that it takes virtual hosts into account. 73870Sstevel@tonic-gateUse this when running with virtual hosts. 73880Sstevel@tonic-gate 73890Sstevel@tonic-gate=item B<server_software ()> 73900Sstevel@tonic-gate 73910Sstevel@tonic-gateReturns the server software and version number. 73920Sstevel@tonic-gate 73930Sstevel@tonic-gate=item B<remote_user ()> 73940Sstevel@tonic-gate 73950Sstevel@tonic-gateReturn the authorization/verification name used for user 73960Sstevel@tonic-gateverification, if this script is protected. 73970Sstevel@tonic-gate 73980Sstevel@tonic-gate=item B<user_name ()> 73990Sstevel@tonic-gate 74000Sstevel@tonic-gateAttempt to obtain the remote user's name, using a variety of different 74010Sstevel@tonic-gatetechniques. This only works with older browsers such as Mosaic. 74020Sstevel@tonic-gateNewer browsers do not report the user name for privacy reasons! 74030Sstevel@tonic-gate 74040Sstevel@tonic-gate=item B<request_method()> 74050Sstevel@tonic-gate 74060Sstevel@tonic-gateReturns the method used to access your script, usually 74070Sstevel@tonic-gateone of 'POST', 'GET' or 'HEAD'. 74080Sstevel@tonic-gate 74090Sstevel@tonic-gate=item B<content_type()> 74100Sstevel@tonic-gate 74110Sstevel@tonic-gateReturns the content_type of data submitted in a POST, generally 74120Sstevel@tonic-gatemultipart/form-data or application/x-www-form-urlencoded 74130Sstevel@tonic-gate 74140Sstevel@tonic-gate=item B<http()> 74150Sstevel@tonic-gate 74160Sstevel@tonic-gateCalled with no arguments returns the list of HTTP environment 74170Sstevel@tonic-gatevariables, including such things as HTTP_USER_AGENT, 74180Sstevel@tonic-gateHTTP_ACCEPT_LANGUAGE, and HTTP_ACCEPT_CHARSET, corresponding to the 74190Sstevel@tonic-gatelike-named HTTP header fields in the request. Called with the name of 74200Sstevel@tonic-gatean HTTP header field, returns its value. Capitalization and the use 74210Sstevel@tonic-gateof hyphens versus underscores are not significant. 74220Sstevel@tonic-gate 74230Sstevel@tonic-gateFor example, all three of these examples are equivalent: 74240Sstevel@tonic-gate 7425667Sps156622 $requested_language = http('Accept-language'); 7426667Sps156622 $requested_language = http('Accept_language'); 7427667Sps156622 $requested_language = http('HTTP_ACCEPT_LANGUAGE'); 74280Sstevel@tonic-gate 74290Sstevel@tonic-gate=item B<https()> 74300Sstevel@tonic-gate 74310Sstevel@tonic-gateThe same as I<http()>, but operates on the HTTPS environment variables 74320Sstevel@tonic-gatepresent when the SSL protocol is in effect. Can be used to determine 74330Sstevel@tonic-gatewhether SSL is turned on. 74340Sstevel@tonic-gate 74350Sstevel@tonic-gate=back 74360Sstevel@tonic-gate 74370Sstevel@tonic-gate=head1 USING NPH SCRIPTS 74380Sstevel@tonic-gate 74390Sstevel@tonic-gateNPH, or "no-parsed-header", scripts bypass the server completely by 74400Sstevel@tonic-gatesending the complete HTTP header directly to the browser. This has 74410Sstevel@tonic-gateslight performance benefits, but is of most use for taking advantage 74420Sstevel@tonic-gateof HTTP extensions that are not directly supported by your server, 74430Sstevel@tonic-gatesuch as server push and PICS headers. 74440Sstevel@tonic-gate 74450Sstevel@tonic-gateServers use a variety of conventions for designating CGI scripts as 74460Sstevel@tonic-gateNPH. Many Unix servers look at the beginning of the script's name for 74470Sstevel@tonic-gatethe prefix "nph-". The Macintosh WebSTAR server and Microsoft's 74480Sstevel@tonic-gateInternet Information Server, in contrast, try to decide whether a 74490Sstevel@tonic-gateprogram is an NPH script by examining the first line of script output. 74500Sstevel@tonic-gate 74510Sstevel@tonic-gate 74520Sstevel@tonic-gateCGI.pm supports NPH scripts with a special NPH mode. When in this 74530Sstevel@tonic-gatemode, CGI.pm will output the necessary extra header information when 74540Sstevel@tonic-gatethe header() and redirect() methods are 74550Sstevel@tonic-gatecalled. 74560Sstevel@tonic-gate 74570Sstevel@tonic-gateThe Microsoft Internet Information Server requires NPH mode. As of 74580Sstevel@tonic-gateversion 2.30, CGI.pm will automatically detect when the script is 74590Sstevel@tonic-gaterunning under IIS and put itself into this mode. You do not need to 74600Sstevel@tonic-gatedo this manually, although it won't hurt anything if you do. However, 74610Sstevel@tonic-gatenote that if you have applied Service Pack 6, much of the 74620Sstevel@tonic-gatefunctionality of NPH scripts, including the ability to redirect while 74630Sstevel@tonic-gatesetting a cookie, b<do not work at all> on IIS without a special patch 74640Sstevel@tonic-gatefrom Microsoft. See 74650Sstevel@tonic-gatehttp://support.microsoft.com/support/kb/articles/Q280/3/41.ASP: 74660Sstevel@tonic-gateNon-Parsed Headers Stripped From CGI Applications That Have nph- 74670Sstevel@tonic-gatePrefix in Name. 74680Sstevel@tonic-gate 74690Sstevel@tonic-gate=over 4 74700Sstevel@tonic-gate 74710Sstevel@tonic-gate=item In the B<use> statement 74720Sstevel@tonic-gate 74730Sstevel@tonic-gateSimply add the "-nph" pragmato the list of symbols to be imported into 74740Sstevel@tonic-gateyour script: 74750Sstevel@tonic-gate 74760Sstevel@tonic-gate use CGI qw(:standard -nph) 74770Sstevel@tonic-gate 74780Sstevel@tonic-gate=item By calling the B<nph()> method: 74790Sstevel@tonic-gate 74800Sstevel@tonic-gateCall B<nph()> with a non-zero parameter at any point after using CGI.pm in your program. 74810Sstevel@tonic-gate 74820Sstevel@tonic-gate CGI->nph(1) 74830Sstevel@tonic-gate 74840Sstevel@tonic-gate=item By using B<-nph> parameters 74850Sstevel@tonic-gate 74860Sstevel@tonic-gatein the B<header()> and B<redirect()> statements: 74870Sstevel@tonic-gate 7488667Sps156622 print header(-nph=>1); 74890Sstevel@tonic-gate 74900Sstevel@tonic-gate=back 74910Sstevel@tonic-gate 74920Sstevel@tonic-gate=head1 Server Push 74930Sstevel@tonic-gate 74940Sstevel@tonic-gateCGI.pm provides four simple functions for producing multipart 74950Sstevel@tonic-gatedocuments of the type needed to implement server push. These 74960Sstevel@tonic-gatefunctions were graciously provided by Ed Jordan <ed@fidalgo.net>. To 74970Sstevel@tonic-gateimport these into your namespace, you must import the ":push" set. 74980Sstevel@tonic-gateYou are also advised to put the script into NPH mode and to set $| to 74990Sstevel@tonic-gate1 to avoid buffering problems. 75000Sstevel@tonic-gate 75010Sstevel@tonic-gateHere is a simple script that demonstrates server push: 75020Sstevel@tonic-gate 75030Sstevel@tonic-gate #!/usr/local/bin/perl 75040Sstevel@tonic-gate use CGI qw/:push -nph/; 75050Sstevel@tonic-gate $| = 1; 75060Sstevel@tonic-gate print multipart_init(-boundary=>'----here we go!'); 75070Sstevel@tonic-gate foreach (0 .. 4) { 75080Sstevel@tonic-gate print multipart_start(-type=>'text/plain'), 75090Sstevel@tonic-gate "The current time is ",scalar(localtime),"\n"; 75100Sstevel@tonic-gate if ($_ < 4) { 75110Sstevel@tonic-gate print multipart_end; 75120Sstevel@tonic-gate } else { 75130Sstevel@tonic-gate print multipart_final; 75140Sstevel@tonic-gate } 75150Sstevel@tonic-gate sleep 1; 75160Sstevel@tonic-gate } 75170Sstevel@tonic-gate 75180Sstevel@tonic-gateThis script initializes server push by calling B<multipart_init()>. 75190Sstevel@tonic-gateIt then enters a loop in which it begins a new multipart section by 75200Sstevel@tonic-gatecalling B<multipart_start()>, prints the current local time, 75210Sstevel@tonic-gateand ends a multipart section with B<multipart_end()>. It then sleeps 75220Sstevel@tonic-gatea second, and begins again. On the final iteration, it ends the 75230Sstevel@tonic-gatemultipart section with B<multipart_final()> rather than with 75240Sstevel@tonic-gateB<multipart_end()>. 75250Sstevel@tonic-gate 75260Sstevel@tonic-gate=over 4 75270Sstevel@tonic-gate 75280Sstevel@tonic-gate=item multipart_init() 75290Sstevel@tonic-gate 75300Sstevel@tonic-gate multipart_init(-boundary=>$boundary); 75310Sstevel@tonic-gate 75320Sstevel@tonic-gateInitialize the multipart system. The -boundary argument specifies 75330Sstevel@tonic-gatewhat MIME boundary string to use to separate parts of the document. 75340Sstevel@tonic-gateIf not provided, CGI.pm chooses a reasonable boundary for you. 75350Sstevel@tonic-gate 75360Sstevel@tonic-gate=item multipart_start() 75370Sstevel@tonic-gate 75380Sstevel@tonic-gate multipart_start(-type=>$type) 75390Sstevel@tonic-gate 75400Sstevel@tonic-gateStart a new part of the multipart document using the specified MIME 75410Sstevel@tonic-gatetype. If not specified, text/html is assumed. 75420Sstevel@tonic-gate 75430Sstevel@tonic-gate=item multipart_end() 75440Sstevel@tonic-gate 75450Sstevel@tonic-gate multipart_end() 75460Sstevel@tonic-gate 75470Sstevel@tonic-gateEnd a part. You must remember to call multipart_end() once for each 75480Sstevel@tonic-gatemultipart_start(), except at the end of the last part of the multipart 75490Sstevel@tonic-gatedocument when multipart_final() should be called instead of multipart_end(). 75500Sstevel@tonic-gate 75510Sstevel@tonic-gate=item multipart_final() 75520Sstevel@tonic-gate 75530Sstevel@tonic-gate multipart_final() 75540Sstevel@tonic-gate 75550Sstevel@tonic-gateEnd all parts. You should call multipart_final() rather than 75560Sstevel@tonic-gatemultipart_end() at the end of the last part of the multipart document. 75570Sstevel@tonic-gate 75580Sstevel@tonic-gate=back 75590Sstevel@tonic-gate 75600Sstevel@tonic-gateUsers interested in server push applications should also have a look 75610Sstevel@tonic-gateat the CGI::Push module. 75620Sstevel@tonic-gate 75630Sstevel@tonic-gateOnly Netscape Navigator supports server push. Internet Explorer 75640Sstevel@tonic-gatebrowsers do not. 75650Sstevel@tonic-gate 75660Sstevel@tonic-gate=head1 Avoiding Denial of Service Attacks 75670Sstevel@tonic-gate 75680Sstevel@tonic-gateA potential problem with CGI.pm is that, by default, it attempts to 75690Sstevel@tonic-gateprocess form POSTings no matter how large they are. A wily hacker 75700Sstevel@tonic-gatecould attack your site by sending a CGI script a huge POST of many 75710Sstevel@tonic-gatemegabytes. CGI.pm will attempt to read the entire POST into a 75720Sstevel@tonic-gatevariable, growing hugely in size until it runs out of memory. While 75730Sstevel@tonic-gatethe script attempts to allocate the memory the system may slow down 75740Sstevel@tonic-gatedramatically. This is a form of denial of service attack. 75750Sstevel@tonic-gate 75760Sstevel@tonic-gateAnother possible attack is for the remote user to force CGI.pm to 75770Sstevel@tonic-gateaccept a huge file upload. CGI.pm will accept the upload and store it 75780Sstevel@tonic-gatein a temporary directory even if your script doesn't expect to receive 75790Sstevel@tonic-gatean uploaded file. CGI.pm will delete the file automatically when it 75800Sstevel@tonic-gateterminates, but in the meantime the remote user may have filled up the 75810Sstevel@tonic-gateserver's disk space, causing problems for other programs. 75820Sstevel@tonic-gate 75830Sstevel@tonic-gateThe best way to avoid denial of service attacks is to limit the amount 75840Sstevel@tonic-gateof memory, CPU time and disk space that CGI scripts can use. Some Web 75850Sstevel@tonic-gateservers come with built-in facilities to accomplish this. In other 75860Sstevel@tonic-gatecases, you can use the shell I<limit> or I<ulimit> 75870Sstevel@tonic-gatecommands to put ceilings on CGI resource usage. 75880Sstevel@tonic-gate 75890Sstevel@tonic-gate 75900Sstevel@tonic-gateCGI.pm also has some simple built-in protections against denial of 75910Sstevel@tonic-gateservice attacks, but you must activate them before you can use them. 75920Sstevel@tonic-gateThese take the form of two global variables in the CGI name space: 75930Sstevel@tonic-gate 75940Sstevel@tonic-gate=over 4 75950Sstevel@tonic-gate 75960Sstevel@tonic-gate=item B<$CGI::POST_MAX> 75970Sstevel@tonic-gate 75980Sstevel@tonic-gateIf set to a non-negative integer, this variable puts a ceiling 75990Sstevel@tonic-gateon the size of POSTings, in bytes. If CGI.pm detects a POST 76000Sstevel@tonic-gatethat is greater than the ceiling, it will immediately exit with an error 76010Sstevel@tonic-gatemessage. This value will affect both ordinary POSTs and 76020Sstevel@tonic-gatemultipart POSTs, meaning that it limits the maximum size of file 76030Sstevel@tonic-gateuploads as well. You should set this to a reasonably high 76040Sstevel@tonic-gatevalue, such as 1 megabyte. 76050Sstevel@tonic-gate 76060Sstevel@tonic-gate=item B<$CGI::DISABLE_UPLOADS> 76070Sstevel@tonic-gate 76080Sstevel@tonic-gateIf set to a non-zero value, this will disable file uploads 76090Sstevel@tonic-gatecompletely. Other fill-out form values will work as usual. 76100Sstevel@tonic-gate 76110Sstevel@tonic-gate=back 76120Sstevel@tonic-gate 76130Sstevel@tonic-gateYou can use these variables in either of two ways. 76140Sstevel@tonic-gate 76150Sstevel@tonic-gate=over 4 76160Sstevel@tonic-gate 76170Sstevel@tonic-gate=item B<1. On a script-by-script basis> 76180Sstevel@tonic-gate 76190Sstevel@tonic-gateSet the variable at the top of the script, right after the "use" statement: 76200Sstevel@tonic-gate 76210Sstevel@tonic-gate use CGI qw/:standard/; 76220Sstevel@tonic-gate use CGI::Carp 'fatalsToBrowser'; 76230Sstevel@tonic-gate $CGI::POST_MAX=1024 * 100; # max 100K posts 76240Sstevel@tonic-gate $CGI::DISABLE_UPLOADS = 1; # no uploads 76250Sstevel@tonic-gate 76260Sstevel@tonic-gate=item B<2. Globally for all scripts> 76270Sstevel@tonic-gate 76280Sstevel@tonic-gateOpen up CGI.pm, find the definitions for $POST_MAX and 76290Sstevel@tonic-gate$DISABLE_UPLOADS, and set them to the desired values. You'll 76300Sstevel@tonic-gatefind them towards the top of the file in a subroutine named 76310Sstevel@tonic-gateinitialize_globals(). 76320Sstevel@tonic-gate 76330Sstevel@tonic-gate=back 76340Sstevel@tonic-gate 76350Sstevel@tonic-gateAn attempt to send a POST larger than $POST_MAX bytes will cause 76360Sstevel@tonic-gateI<param()> to return an empty CGI parameter list. You can test for 76370Sstevel@tonic-gatethis event by checking I<cgi_error()>, either after you create the CGI 76380Sstevel@tonic-gateobject or, if you are using the function-oriented interface, call 76390Sstevel@tonic-gate<param()> for the first time. If the POST was intercepted, then 76400Sstevel@tonic-gatecgi_error() will return the message "413 POST too large". 76410Sstevel@tonic-gate 76420Sstevel@tonic-gateThis error message is actually defined by the HTTP protocol, and is 76430Sstevel@tonic-gatedesigned to be returned to the browser as the CGI script's status 76440Sstevel@tonic-gate code. For example: 76450Sstevel@tonic-gate 76460Sstevel@tonic-gate $uploaded_file = param('upload'); 76470Sstevel@tonic-gate if (!$uploaded_file && cgi_error()) { 76480Sstevel@tonic-gate print header(-status=>cgi_error()); 76490Sstevel@tonic-gate exit 0; 76500Sstevel@tonic-gate } 76510Sstevel@tonic-gate 76520Sstevel@tonic-gateHowever it isn't clear that any browser currently knows what to do 76530Sstevel@tonic-gatewith this status code. It might be better just to create an 76540Sstevel@tonic-gateHTML page that warns the user of the problem. 76550Sstevel@tonic-gate 76560Sstevel@tonic-gate=head1 COMPATIBILITY WITH CGI-LIB.PL 76570Sstevel@tonic-gate 76580Sstevel@tonic-gateTo make it easier to port existing programs that use cgi-lib.pl the 76590Sstevel@tonic-gatecompatibility routine "ReadParse" is provided. Porting is simple: 76600Sstevel@tonic-gate 76610Sstevel@tonic-gateOLD VERSION 76620Sstevel@tonic-gate require "cgi-lib.pl"; 76630Sstevel@tonic-gate &ReadParse; 76640Sstevel@tonic-gate print "The value of the antique is $in{antique}.\n"; 76650Sstevel@tonic-gate 76660Sstevel@tonic-gateNEW VERSION 76670Sstevel@tonic-gate use CGI; 7668*6287Sps156622 CGI::ReadParse(); 76690Sstevel@tonic-gate print "The value of the antique is $in{antique}.\n"; 76700Sstevel@tonic-gate 76710Sstevel@tonic-gateCGI.pm's ReadParse() routine creates a tied variable named %in, 76720Sstevel@tonic-gatewhich can be accessed to obtain the query variables. Like 76730Sstevel@tonic-gateReadParse, you can also provide your own variable. Infrequently 76740Sstevel@tonic-gateused features of ReadParse, such as the creation of @in and $in 76750Sstevel@tonic-gatevariables, are not supported. 76760Sstevel@tonic-gate 76770Sstevel@tonic-gateOnce you use ReadParse, you can retrieve the query object itself 76780Sstevel@tonic-gatethis way: 76790Sstevel@tonic-gate 76800Sstevel@tonic-gate $q = $in{CGI}; 7681667Sps156622 print textfield(-name=>'wow', 76820Sstevel@tonic-gate -value=>'does this really work?'); 76830Sstevel@tonic-gate 76840Sstevel@tonic-gateThis allows you to start using the more interesting features 76850Sstevel@tonic-gateof CGI.pm without rewriting your old scripts from scratch. 76860Sstevel@tonic-gate 76870Sstevel@tonic-gate=head1 AUTHOR INFORMATION 76880Sstevel@tonic-gate 76890Sstevel@tonic-gateCopyright 1995-1998, Lincoln D. Stein. All rights reserved. 76900Sstevel@tonic-gate 76910Sstevel@tonic-gateThis library is free software; you can redistribute it and/or modify 76920Sstevel@tonic-gateit under the same terms as Perl itself. 76930Sstevel@tonic-gate 76940Sstevel@tonic-gateAddress bug reports and comments to: lstein@cshl.org. When sending 76950Sstevel@tonic-gatebug reports, please provide the version of CGI.pm, the version of 76960Sstevel@tonic-gatePerl, the name and version of your Web server, and the name and 76970Sstevel@tonic-gateversion of the operating system you are using. If the problem is even 76980Sstevel@tonic-gateremotely browser dependent, please provide information about the 76990Sstevel@tonic-gateaffected browers as well. 77000Sstevel@tonic-gate 77010Sstevel@tonic-gate=head1 CREDITS 77020Sstevel@tonic-gate 77030Sstevel@tonic-gateThanks very much to: 77040Sstevel@tonic-gate 77050Sstevel@tonic-gate=over 4 77060Sstevel@tonic-gate 77070Sstevel@tonic-gate=item Matt Heffron (heffron@falstaff.css.beckman.com) 77080Sstevel@tonic-gate 77090Sstevel@tonic-gate=item James Taylor (james.taylor@srs.gov) 77100Sstevel@tonic-gate 77110Sstevel@tonic-gate=item Scott Anguish <sanguish@digifix.com> 77120Sstevel@tonic-gate 77130Sstevel@tonic-gate=item Mike Jewell (mlj3u@virginia.edu) 77140Sstevel@tonic-gate 77150Sstevel@tonic-gate=item Timothy Shimmin (tes@kbs.citri.edu.au) 77160Sstevel@tonic-gate 77170Sstevel@tonic-gate=item Joergen Haegg (jh@axis.se) 77180Sstevel@tonic-gate 77190Sstevel@tonic-gate=item Laurent Delfosse (delfosse@delfosse.com) 77200Sstevel@tonic-gate 77210Sstevel@tonic-gate=item Richard Resnick (applepi1@aol.com) 77220Sstevel@tonic-gate 77230Sstevel@tonic-gate=item Craig Bishop (csb@barwonwater.vic.gov.au) 77240Sstevel@tonic-gate 77250Sstevel@tonic-gate=item Tony Curtis (tc@vcpc.univie.ac.at) 77260Sstevel@tonic-gate 77270Sstevel@tonic-gate=item Tim Bunce (Tim.Bunce@ig.co.uk) 77280Sstevel@tonic-gate 77290Sstevel@tonic-gate=item Tom Christiansen (tchrist@convex.com) 77300Sstevel@tonic-gate 77310Sstevel@tonic-gate=item Andreas Koenig (k@franz.ww.TU-Berlin.DE) 77320Sstevel@tonic-gate 77330Sstevel@tonic-gate=item Tim MacKenzie (Tim.MacKenzie@fulcrum.com.au) 77340Sstevel@tonic-gate 77350Sstevel@tonic-gate=item Kevin B. Hendricks (kbhend@dogwood.tyler.wm.edu) 77360Sstevel@tonic-gate 77370Sstevel@tonic-gate=item Stephen Dahmen (joyfire@inxpress.net) 77380Sstevel@tonic-gate 77390Sstevel@tonic-gate=item Ed Jordan (ed@fidalgo.net) 77400Sstevel@tonic-gate 77410Sstevel@tonic-gate=item David Alan Pisoni (david@cnation.com) 77420Sstevel@tonic-gate 77430Sstevel@tonic-gate=item Doug MacEachern (dougm@opengroup.org) 77440Sstevel@tonic-gate 77450Sstevel@tonic-gate=item Robin Houston (robin@oneworld.org) 77460Sstevel@tonic-gate 77470Sstevel@tonic-gate=item ...and many many more... 77480Sstevel@tonic-gate 77490Sstevel@tonic-gatefor suggestions and bug fixes. 77500Sstevel@tonic-gate 77510Sstevel@tonic-gate=back 77520Sstevel@tonic-gate 77530Sstevel@tonic-gate=head1 A COMPLETE EXAMPLE OF A SIMPLE FORM-BASED SCRIPT 77540Sstevel@tonic-gate 77550Sstevel@tonic-gate 77560Sstevel@tonic-gate #!/usr/local/bin/perl 77570Sstevel@tonic-gate 7758667Sps156622 use CGI ':standard'; 7759667Sps156622 7760667Sps156622 print header; 7761667Sps156622 print start_html("Example CGI.pm Form"); 77620Sstevel@tonic-gate print "<h1> Example CGI.pm Form</h1>\n"; 7763667Sps156622 print_prompt(); 7764667Sps156622 do_work(); 7765667Sps156622 print_tail(); 7766667Sps156622 print end_html; 77670Sstevel@tonic-gate 77680Sstevel@tonic-gate sub print_prompt { 7769667Sps156622 print start_form; 77700Sstevel@tonic-gate print "<em>What's your name?</em><br>"; 7771667Sps156622 print textfield('name'); 7772667Sps156622 print checkbox('Not my real name'); 77730Sstevel@tonic-gate 77740Sstevel@tonic-gate print "<p><em>Where can you find English Sparrows?</em><br>"; 7775667Sps156622 print checkbox_group( 77760Sstevel@tonic-gate -name=>'Sparrow locations', 77770Sstevel@tonic-gate -values=>[England,France,Spain,Asia,Hoboken], 77780Sstevel@tonic-gate -linebreak=>'yes', 77790Sstevel@tonic-gate -defaults=>[England,Asia]); 77800Sstevel@tonic-gate 77810Sstevel@tonic-gate print "<p><em>How far can they fly?</em><br>", 7782667Sps156622 radio_group( 77830Sstevel@tonic-gate -name=>'how far', 77840Sstevel@tonic-gate -values=>['10 ft','1 mile','10 miles','real far'], 77850Sstevel@tonic-gate -default=>'1 mile'); 77860Sstevel@tonic-gate 77870Sstevel@tonic-gate print "<p><em>What's your favorite color?</em> "; 7788667Sps156622 print popup_menu(-name=>'Color', 77890Sstevel@tonic-gate -values=>['black','brown','red','yellow'], 77900Sstevel@tonic-gate -default=>'red'); 77910Sstevel@tonic-gate 7792667Sps156622 print hidden('Reference','Monty Python and the Holy Grail'); 77930Sstevel@tonic-gate 77940Sstevel@tonic-gate print "<p><em>What have you got there?</em><br>"; 7795667Sps156622 print scrolling_list( 77960Sstevel@tonic-gate -name=>'possessions', 77970Sstevel@tonic-gate -values=>['A Coconut','A Grail','An Icon', 77980Sstevel@tonic-gate 'A Sword','A Ticket'], 77990Sstevel@tonic-gate -size=>5, 78000Sstevel@tonic-gate -multiple=>'true'); 78010Sstevel@tonic-gate 78020Sstevel@tonic-gate print "<p><em>Any parting comments?</em><br>"; 7803667Sps156622 print textarea(-name=>'Comments', 78040Sstevel@tonic-gate -rows=>10, 78050Sstevel@tonic-gate -columns=>50); 78060Sstevel@tonic-gate 7807667Sps156622 print "<p>",reset; 7808667Sps156622 print submit('Action','Shout'); 7809667Sps156622 print submit('Action','Scream'); 7810667Sps156622 print endform; 78110Sstevel@tonic-gate print "<hr>\n"; 78120Sstevel@tonic-gate } 78130Sstevel@tonic-gate 78140Sstevel@tonic-gate sub do_work { 78150Sstevel@tonic-gate my(@values,$key); 78160Sstevel@tonic-gate 78170Sstevel@tonic-gate print "<h2>Here are the current settings in this form</h2>"; 78180Sstevel@tonic-gate 7819667Sps156622 foreach $key (param) { 78200Sstevel@tonic-gate print "<strong>$key</strong> -> "; 7821667Sps156622 @values = param($key); 78220Sstevel@tonic-gate print join(", ",@values),"<br>\n"; 78230Sstevel@tonic-gate } 78240Sstevel@tonic-gate } 78250Sstevel@tonic-gate 78260Sstevel@tonic-gate sub print_tail { 78270Sstevel@tonic-gate print <<END; 78280Sstevel@tonic-gate <hr> 78290Sstevel@tonic-gate <address>Lincoln D. Stein</address><br> 78300Sstevel@tonic-gate <a href="/">Home Page</a> 78310Sstevel@tonic-gate END 78320Sstevel@tonic-gate } 78330Sstevel@tonic-gate 78340Sstevel@tonic-gate=head1 BUGS 78350Sstevel@tonic-gate 78360Sstevel@tonic-gatePlease report them. 78370Sstevel@tonic-gate 78380Sstevel@tonic-gate=head1 SEE ALSO 78390Sstevel@tonic-gate 78400Sstevel@tonic-gateL<CGI::Carp>, L<CGI::Fast>, L<CGI::Pretty> 78410Sstevel@tonic-gate 78420Sstevel@tonic-gate=cut 78430Sstevel@tonic-gate 7844