X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCGI.pm;h=4d5742b9c949b34e223ef24b4aced3dd6b740db4;hb=2b37efcc2bc957549bbeb5c71adf3fced634e4c9;hp=08adf4fae6912175ecdbcd62ed7415ed0dc4a02a;hpb=976c4ade930645f3b8c72758f0dca6062c93eb42;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/CGI.pm b/lib/CGI.pm index 08adf4f..4d5742b 100644 --- a/lib/CGI.pm +++ b/lib/CGI.pm @@ -18,8 +18,8 @@ use Carp 'croak'; # The most recent version and complete docs are available at: # http://stein.cshl.org/WWW/software/CGI/ -$CGI::revision = '$Id: CGI.pm,v 1.178 2005/03/14 16:30:20 lstein Exp $'; -$CGI::VERSION=3.07; +$CGI::revision = '$Id: CGI.pm,v 1.194 2005/12/06 22:12:56 lstein Exp $'; +$CGI::VERSION='3.15_01'; # HARD-CODED LOCATION FOR FILE UPLOAD TEMPORARY FILES. # UNCOMMENT THIS ONLY IF YOU KNOW WHAT YOU'RE DOING. @@ -77,6 +77,9 @@ sub initialize_globals { # 2) CGI::private_tempfiles(1); $PRIVATE_TEMPFILES = 0; + # Set this to 1 to generate automatic tab indexes + $TABINDEX = 0; + # Set this to 1 to cause files uploaded in multipart documents # to be closed, instead of caching the file handle # or: @@ -177,20 +180,18 @@ $IIS++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/; # Turn on special checking for Doug MacEachern's modperl if (exists $ENV{MOD_PERL}) { - eval "require mod_perl"; # mod_perl handlers may run system() on scripts using CGI.pm; # Make sure so we don't get fooled by inherited $ENV{MOD_PERL} - if (defined $mod_perl::VERSION) { - if ($mod_perl::VERSION >= 1.99) { - $MOD_PERL = 2; - require Apache::Response; - require Apache::RequestRec; - require Apache::RequestUtil; - require APR::Pool; - } else { - $MOD_PERL = 1; - require Apache; - } + if (exists $ENV{MOD_PERL_API_VERSION} && $ENV{MOD_PERL_API_VERSION} == 2) { + $MOD_PERL = 2; + require Apache2::Response; + require Apache2::RequestRec; + require Apache2::RequestUtil; + require Apache2::RequestIO; + require APR::Pool; + } else { + $MOD_PERL = 1; + require Apache; } } @@ -233,7 +234,8 @@ if ($needs_binmode) { submit reset defaults radio_group popup_menu button autoEscape scrolling_list image_button start_form end_form startform endform start_multipart_form end_multipart_form isindex tmpFileName uploadInfo URL_ENCODED MULTIPART/], - ':cgi'=>[qw/param upload path_info path_translated url self_url script_name cookie Dump + ':cgi'=>[qw/param upload path_info path_translated request_uri url self_url script_name + cookie Dump raw_cookie request_method query_string Accept user_agent remote_host content_type remote_addr referer server_name server_software server_port server_protocol virtual_port virtual_host remote_ident auth_type http append @@ -330,7 +332,7 @@ sub new { if (ref($initializer[0]) && (UNIVERSAL::isa($initializer[0],'Apache') || - UNIVERSAL::isa($initializer[0],'Apache::RequestRec') + UNIVERSAL::isa($initializer[0],'Apache2::RequestRec') )) { $self->r(shift @initializer); } @@ -339,14 +341,16 @@ sub new { $self->upload_hook(shift @initializer, shift @initializer); } if ($MOD_PERL) { - $self->r(Apache->request) unless $self->r; - my $r = $self->r; if ($MOD_PERL == 1) { + $self->r(Apache->request) unless $self->r; + my $r = $self->r; $r->register_cleanup(\&CGI::_reset_globals); } else { # XXX: once we have the new API # will do a real PerlOptions -SetupEnv check + $self->r(Apache2::RequestUtil->request) unless $self->r; + my $r = $self->r; $r->subprocess_env unless exists $ENV{REQUEST_METHOD}; $r->pool->cleanup_register(\&CGI::_reset_globals); } @@ -366,9 +370,11 @@ sub new { # user is still holding any reference to them as well. sub DESTROY { my $self = shift; - foreach my $href (values %{$self->{'.tmpfiles'}}) { - $href->{hndl}->DESTROY if defined $href->{hndl}; - $href->{name}->DESTROY if defined $href->{name}; + if ($OS eq 'WINDOWS') { + foreach my $href (values %{$self->{'.tmpfiles'}}) { + $href->{hndl}->DESTROY if defined $href->{hndl}; + $href->{name}->DESTROY if defined $href->{name}; + } } } @@ -380,7 +386,13 @@ sub r { } sub upload_hook { - my ($self,$hook,$data) = self_or_default(@_); + my $self; + if (ref $_[0] eq 'CODE') { + $CGI::Q = $self = $CGI::DefaultClass->new(@_); + } else { + $self = shift; + } + my ($hook,$data) = @_; $self->{'.upload_hook'} = $hook; $self->{'.upload_data'} = $data; } @@ -498,16 +510,15 @@ sub init { if (($POST_MAX > 0) && ($content_length > $POST_MAX)) { # quietly read and discard the post my $buffer; - my $max = $content_length; - while ($max > 0 && - (my $bytes = $MOD_PERL - ? $self->r->read($buffer,$max < 10000 ? $max : 10000) - : read(STDIN,$buffer,$max < 10000 ? $max : 10000) - )) { - $self->cgi_error("413 Request entity too large"); - last METHOD; - } - } + my $tmplength = $content_length; + while($tmplength > 0) { + my $maxbuffer = ($tmplength < 10000)?$tmplength:10000; + my $bytesread = $MOD_PERL ? $self->r->read($buffer,$maxbuffer) : read(STDIN,$buffer,$maxbuffer); + $tmplength -= $bytesread; + } + $self->cgi_error("413 Request entity too large"); + last METHOD; + } # Process multipart postings, but only if the initializer is # not defined. @@ -820,14 +831,14 @@ sub _selected { my $self = shift; my $value = shift; return '' unless $value; - return $XHTML ? qq( selected="selected") : qq( selected); + return $XHTML ? qq(selected="selected" ) : qq(selected ); } sub _checked { my $self = shift; my $value = shift; return '' unless $value; - return $XHTML ? qq( checked="checked") : qq( checked); + return $XHTML ? qq(checked="checked" ) : qq(checked ); } sub _reset_globals { initialize_globals(); } @@ -850,6 +861,7 @@ sub _setup_symbols { $XHTML=0, next if /^[:-]no_?xhtml$/; $USE_PARAM_SEMICOLONS=0, next if /^[:-]oldstyle_urls$/; $PRIVATE_TEMPFILES++, next if /^[:-]private_tempfiles$/; + $TABINDEX++, next if /^[:-]tabindex$/; $CLOSE_UPLOAD_FILES++, next if /^[:-]close_upload_files$/; $EXPORT{$_}++, next if /^[:-]any$/; $compile++, next if /^[:-]compile$/; @@ -889,8 +901,11 @@ sub element_id { sub element_tab { my ($self,$new_value) = self_or_default(@_); + $self->{'.etab'} ||= 1; $self->{'.etab'} = $new_value if defined $new_value; - $self->{'.etab'}++; + my $tab = $self->{'.etab'}++; + return '' unless $TABINDEX or defined $new_value; + return qq(tabindex="$tab" ); } ############################################################################### @@ -1133,7 +1148,7 @@ END_OF_FUNC #### 'append' => <<'EOF', sub append { - my($self,@p) = @_; + my($self,@p) = self_or_default(@_); my($name,$value) = rearrange([NAME,[VALUE,VALUES]],@p); my(@values) = defined($value) ? (ref($value) ? @{$value} : $value) : (); if (@values) { @@ -1767,10 +1782,7 @@ sub startform { $action = $self->escapeHTML($action); } else { - $action = $self->escapeHTML($self->url(-absolute=>1,-path=>1)); - if (exists $ENV{QUERY_STRING} && length($ENV{QUERY_STRING})>0) { - $action .= "?".$self->escapeHTML($ENV{QUERY_STRING},1); - } + $action = $self->escapeHTML($self->request_uri); } $action = qq(action="$action"); my($other) = @other ? " @other" : ''; @@ -1799,7 +1811,7 @@ END_OF_FUNC 'start_multipart_form' => <<'END_OF_FUNC', sub start_multipart_form { my($self,@p) = self_or_default(@_); - if (defined($param[0]) && substr($param[0],0,1) eq '-') { + if (defined($p[0]) && substr($p[0],0,1) eq '-') { my(%p) = @p; $p{'-enctype'}=&MULTIPART; return $self->startform(%p); @@ -1816,12 +1828,16 @@ END_OF_FUNC # End a form 'endform' => <<'END_OF_FUNC', sub endform { - my($self,@p) = self_or_default(@_); + my($self,@p) = self_or_default(@_); if ( $NOSTICKY ) { return wantarray ? ("") : "\n"; } else { - return wantarray ? ("
",$self->get_fields,"
","") : - "
".$self->get_fields ."
\n"; + if (my @fields = $self->get_fields) { + return wantarray ? ("
",@fields,"
","") + : "
".(join '',@fields)."
\n"; + } else { + return ""; + } } } END_OF_FUNC @@ -1845,7 +1861,7 @@ sub _textfield { # and WebTV -- not sure it won't break stuff my($value) = $current ne '' ? qq(value="$current") : ''; $tabindex = $self->element_tab($tabindex); - return $XHTML ? qq() + return $XHTML ? qq() : qq(); } END_OF_FUNC @@ -1927,7 +1943,7 @@ sub textarea { my($c) = $cols ? qq/ cols="$cols"/ : ''; my($other) = @other ? " @other" : ''; $tabindex = $self->element_tab($tabindex); - return qq{}; + return qq{}; } END_OF_FUNC @@ -1961,7 +1977,7 @@ sub button { $script = qq/ onclick="$script"/ if $script; my($other) = @other ? " @other" : ''; $tabindex = $self->element_tab($tabindex); - return $XHTML ? qq() + return $XHTML ? qq() : qq(); } END_OF_FUNC @@ -1985,15 +2001,15 @@ sub submit { $label=$self->escapeHTML($label); $value=$self->escapeHTML($value,1); - my $name = $NOSTICKY ? '' : ' name=".submit"'; - $name = qq/ name="$label"/ if defined($label); + my $name = $NOSTICKY ? '' : 'name=".submit" '; + $name = qq/name="$label" / if defined($label); $value = defined($value) ? $value : $label; my $val = ''; - $val = qq/ value="$value"/ if defined($value); + $val = qq/value="$value" / if defined($value); $tabindex = $self->element_tab($tabindex); - my($other) = @other ? " @other" : ''; - return $XHTML ? qq() - : qq(); + my($other) = @other ? "@other " : ''; + return $XHTML ? qq() + : qq(); } END_OF_FUNC @@ -2018,7 +2034,7 @@ sub reset { $val = qq/ value="$value"/ if defined($value); my($other) = @other ? " @other" : ''; $tabindex = $self->element_tab($tabindex); - return $XHTML ? qq() + return $XHTML ? qq() : qq(); } END_OF_FUNC @@ -2046,7 +2062,7 @@ sub defaults { my($value) = qq/ value="$label"/; my($other) = @other ? " @other" : ''; $tabindex = $self->element_tab($tabindex); - return $XHTML ? qq() + return $XHTML ? qq() : qq//; } END_OF_FUNC @@ -2093,10 +2109,10 @@ sub checkbox { $name = $self->escapeHTML($name); $value = $self->escapeHTML($value,1); $the_label = $self->escapeHTML($the_label); - my($other) = @other ? " @other" : ''; + my($other) = @other ? "@other " : ''; $tabindex = $self->element_tab($tabindex); $self->register_parameter($name); - return $XHTML ? CGI::label(qq{$the_label}) + return $XHTML ? CGI::label(qq{$the_label}) : qq{$the_label}; } END_OF_FUNC @@ -2278,7 +2294,7 @@ sub _box_group { $name=$self->escapeHTML($name); my %tabs = (); - if ($tabindex) { + if ($TABINDEX && $tabindex) { if (!ref $tabindex) { $self->element_tab($tabindex); } elsif (ref $tabindex eq 'ARRAY') { @@ -2289,7 +2305,7 @@ sub _box_group { } %tabs = map {$_=>$self->element_tab} @values unless %tabs; - my $other = @other ? " @other" : ''; + my $other = @other ? "@other " : ''; my $radio_checked; foreach (@values) { my $checkit = $self->_checked($box_type eq 'radio' ? ($checked{$_} && !$radio_checked++) @@ -2308,12 +2324,12 @@ sub _box_group { $label = $self->escapeHTML($label,1); } my $attribs = $self->_set_attributes($_, $attributes); - my $tab = qq( tabindex="$tabs{$_}") if exists $tabs{$_}; + my $tab = $tabs{$_}; $_=$self->escapeHTML($_); if ($XHTML) { push @elements, CGI::label( - qq($label)).${break}; + qq($label)).${break}; } else { push(@elements,qq/${label}${break}/); } @@ -2360,7 +2376,7 @@ sub popup_menu { my(@values); @values = $self->_set_values_and_labels($values,\$labels,$name); $tabindex = $self->element_tab($tabindex); - $result = qq/\n/; foreach (@values) { if (/{$_} if defined($labels) && defined($labels->{$_}); my($value) = $self->escapeHTML($_); $label=$self->escapeHTML($label,1); - $result .= "$label\n"; + $result .= "\n"; } } @@ -2485,7 +2501,7 @@ sub scrolling_list { $name=$self->escapeHTML($name); $tabindex = $self->element_tab($tabindex); - $result = qq/\n/; foreach (@values) { my($selectit) = $self->_selected($selected{$_}); my($label) = $_; @@ -2493,7 +2509,7 @@ sub scrolling_list { $label=$self->escapeHTML($label); my($value)=$self->escapeHTML($_,1); my $attribs = $self->_set_attributes($_, $attributes); - $result .= "$label\n"; + $result .= "\n"; } $result .= ""; $self->register_parameter($name); @@ -2600,25 +2616,23 @@ END_OF_FUNC 'url' => <<'END_OF_FUNC', sub url { my($self,@p) = self_or_default(@_); - my ($relative,$absolute,$full,$path_info,$query,$base) = - rearrange(['RELATIVE','ABSOLUTE','FULL',['PATH','PATH_INFO'],['QUERY','QUERY_STRING'],'BASE'],@p); - my $url; + my ($relative,$absolute,$full,$path_info,$query,$base,$rewrite) = + rearrange(['RELATIVE','ABSOLUTE','FULL',['PATH','PATH_INFO'],['QUERY','QUERY_STRING'],'BASE','REWRITE'],@p); + my $url = ''; $full++ if $base || !($relative || $absolute); + $rewrite++ unless defined $rewrite; - my $path = $self->path_info; - my $script_name = $self->script_name; - - # for compatibility with Apache's MultiViews - if (exists($ENV{REQUEST_URI})) { - my $index; - $script_name = unescape($ENV{REQUEST_URI}); - $script_name =~ s/\?.+$//s; # strip query string - # and path - if (exists($ENV{PATH_INFO})) { - my $encoded_path = unescape($ENV{PATH_INFO}); - $script_name =~ s/\Q$encoded_path\E$//i; - } - } + my $path = $self->path_info; + my $script_name = $self->script_name; + my $request_uri = $self->request_uri || ''; + my $query_str = $self->query_string; + + my $rewrite_in_use = $request_uri && $request_uri !~ /^$script_name/; + undef $path if $rewrite_in_use && $rewrite; # path not valid when rewriting active + + my $uri = $rewrite && $request_uri ? $request_uri : $script_name; + $uri =~ s/\?.*$//; # remove query string + $uri =~ s/$path$// if defined $path; # remove path if ($full) { my $protocol = $self->protocol(); @@ -2634,16 +2648,15 @@ sub url { || (lc($protocol) eq 'https' && $port == 443); } return $url if $base; - $url .= $script_name; + $url .= $uri; } elsif ($relative) { ($url) = $script_name =~ m!([^/]+)$!; } elsif ($absolute) { - $url = $script_name; + $url = $uri; } - $url .= $path if $path_info and defined $path; - $url .= "?" . $self->query_string if $query and $self->query_string; - $url = '' unless defined $url; + $url .= $path if $path_info and defined $path; + $url .= "?$query_str" if $query and $query_str ne ''; $url =~ s/([^a-zA-Z0-9_.%;&?\/\\:+=~-])/sprintf("%%%02X",ord($1))/eg; return $url; } @@ -2737,9 +2750,8 @@ sub path_info { $info = "/$info" if $info ne '' && substr($info,0,1) ne '/'; $self->{'.path_info'} = $info; } elsif (! defined($self->{'.path_info'}) ) { - $self->{'.path_info'} = defined($ENV{'PATH_INFO'}) ? - $ENV{'PATH_INFO'} : ''; - + my (undef,$path_info) = $self->_name_and_path_from_env; + $self->{'.path_info'} = $path_info || ''; # hack to fix broken path info in IIS $self->{'.path_info'} =~ s/^\Q$ENV{'SCRIPT_NAME'}\E// if $IIS; @@ -2748,6 +2760,37 @@ sub path_info { } END_OF_FUNC +# WE USE THIS TO COMPENSATE FOR A BUG IN APACHE 2 PRESENT AT LEAST UP THROUGH 2.0.54 +'_name_and_path_from_env' => <<'END_OF_FUNC', +sub _name_and_path_from_env { + my $self = shift; + my $raw_script_name = $ENV{SCRIPT_NAME} || ''; + my $raw_path_info = $ENV{PATH_INFO} || ''; + my $uri = $ENV{REQUEST_URI} || ''; + + if ($raw_script_name =~ m/$raw_path_info$/) { + $raw_script_name =~ s/$raw_path_info$//; + } + + my @uri_double_slashes = $uri =~ m^(/{2,}?)^g; + my @path_double_slashes = "$raw_script_name $raw_path_info" =~ m^(/{2,}?)^g; + + my $apache_bug = @uri_double_slashes != @path_double_slashes; + return ($raw_script_name,$raw_path_info) unless $apache_bug; + + my $path_info_search = $raw_path_info; + # these characters will not (necessarily) be escaped + $path_info_search =~ s/([^a-zA-Z0-9$()':_.,+*\/;?=&-])/uc sprintf("%%%02x",ord($1))/eg; + $path_info_search = quotemeta($path_info_search); + $path_info_search =~ s!/!/+!g; + if ($uri =~ m/^(.+)($path_info_search)/) { + return ($1,$2); + } else { + return ($raw_script_name,$raw_path_info); + } +} +END_OF_FUNC + #### Method: request_method # Returns 'POST', 'GET', 'PUT' or 'HEAD' @@ -2778,6 +2821,16 @@ sub path_translated { END_OF_FUNC +#### Method: request_uri +# Return the literal request URI +#### +'request_uri' => <<'END_OF_FUNC', +sub request_uri { + return $ENV{'REQUEST_URI'}; +} +END_OF_FUNC + + #### Method: query_string # Synthesize a query string from our current # parameters @@ -2933,10 +2986,14 @@ END_OF_FUNC #### 'script_name' => <<'END_OF_FUNC', sub script_name { - return $ENV{'SCRIPT_NAME'} if defined($ENV{'SCRIPT_NAME'}); - # These are for debugging - return "/$0" unless $0=~/^\//; - return $0; + my ($self,@p) = self_or_default(@_); + if (@p) { + $self->{'.script_name'} = shift; + } elsif (!exists $self->{'.script_name'}) { + my ($script_name,$path_info) = $self->_name_and_path_from_env(); + $self->{'.script_name'} = $script_name; + } + return $self->{'.script_name'}; } END_OF_FUNC @@ -2978,8 +3035,9 @@ END_OF_FUNC sub virtual_port { my($self) = self_or_default(@_); my $vh = $self->http('x_forwarded_host') || $self->http('host'); + my $protocol = $self->protocol; if ($vh) { - return ($vh =~ /:(\d+)$/)[0] || '80'; + return ($vh =~ /:(\d+)$/)[0] || ($protocol eq 'https' ? 443 : 80); } else { return $self->server_port(); } @@ -3335,7 +3393,11 @@ sub read_multipart { # Save some information about the uploaded file where we can get # at it later. - $self->{'.tmpfiles'}->{fileno($filehandle)}= { + # Use the typeglob as the key, as this is guaranteed to be + # unique for each filehandle. Don't use the file descriptor as + # this will be re-used for each filehandle if the + # close_upload_files feature is used. + $self->{'.tmpfiles'}->{$$filehandle}= { hndl => $filehandle, name => $tmpfile, info => {%header}, @@ -3358,8 +3420,8 @@ END_OF_FUNC 'tmpFileName' => <<'END_OF_FUNC', sub tmpFileName { my($self,$filename) = self_or_default(@_); - return $self->{'.tmpfiles'}->{fileno($filename)}->{name} ? - $self->{'.tmpfiles'}->{fileno($filename)}->{name}->as_string + return $self->{'.tmpfiles'}->{$$filename}->{name} ? + $self->{'.tmpfiles'}->{$$filename}->{name}->as_string : ''; } END_OF_FUNC @@ -3367,7 +3429,7 @@ END_OF_FUNC 'uploadInfo' => <<'END_OF_FUNC', sub uploadInfo { my($self,$filename) = self_or_default(@_); - return $self->{'.tmpfiles'}->{fileno($filename)}->{info}; + return $self->{'.tmpfiles'}->{$$filename}->{info}; } END_OF_FUNC @@ -3751,11 +3813,10 @@ END_OF_AUTOLOAD package CGITempFile; sub find_tempdir { - undef $TMPDIRECTORY; $SL = $CGI::SL; $MAC = $CGI::OS eq 'MACINTOSH'; my ($vol) = $MAC ? MacPerl::Volumes() =~ /:(.*)/ : ""; - unless ($TMPDIRECTORY) { + unless (defined $TMPDIRECTORY) { @TEMP=("${SL}usr${SL}tmp","${SL}var${SL}tmp", "C:${SL}temp","${SL}tmp","${SL}temp", "${vol}${SL}Temporary Items", @@ -3875,9 +3936,12 @@ CGI - Simple Common Gateway Interface Class hr; if (param()) { - print "Your name is",em(param('name')),p, - "The keywords are: ",em(join(", ",param('words'))),p, - "Your favorite color is ",em(param('color')), + my $name = param('name'); + my $keywords = join ', ',param('words'); + my $color = param('color'); + print "Your name is",em(escapeHTML($name)),p, + "The keywords are: ",em(escapeHTML($keywords)),p, + "Your favorite color is ",em(escapeHTML($color)), hr; } @@ -4236,6 +4300,21 @@ that all the defaults are taken when you create a fill-out form. Use Delete_all() instead if you are using the function call interface. +=head2 HANDLING NON-URLENCODED ARGUMENTS + + +If POSTed data is not of type application/x-www-form-urlencoded or +multipart/form-data, then the POSTed data will not be processed, but +instead be returned as-is in a parameter named POSTDATA. To retrieve +it, use code like this: + + my $data = $query->param('POSTDATA'); + +(If you don't know what the preceding means, don't worry about it. It +only affects people trying to use CGI for XML processing and other +specialized tasks.) + + =head2 DIRECT ACCESS TO THE PARAMETER LIST: $q->param_fetch('address')->[1] = '1313 Mockingbird Lane'; @@ -4545,6 +4624,12 @@ Sometimes this isn't what you want. The B<-nosticky> pragma prevents this behavior. You can also selectively change the sticky behavior in each element that you generate. +=item -tabindex + +Automatically add tab index attributes to each form field. With this +option turned off, you can still add tab indexes manually by passing a +-tabindex option to each field-generating method. + =item -no_undef_params This keeps CGI.pm from including undef params in the parameter list. @@ -5136,6 +5221,16 @@ as a synonym. Generate just the protocol and net location, as in http://www.foo.com:8000 +=item B<-rewrite> + +If Apache's mod_rewrite is turned on, then the script name and path +info probably won't match the request that the user sent. Set +-rewrite=>1 (default) to return URLs that match what the user sent +(the original request URI). Set -rewrite->0 to return URLs that match +the URL after mod_rewrite's rules have run. Because the additional +path information only makes sense in the context of the rewritten URL, +-rewrite is set to false when you request path info in the URL. + =back =head2 MIXING POST AND URL PARAMETERS @@ -5784,8 +5879,7 @@ UPLOAD_HOOK facility available in Apache::Request, with the exception that the first argument to the callback is an Apache::Upload object, here it's the remote filename. - $q = CGI->new(); - $q->upload_hook(\&hook,$data); + $q = CGI->new(\&hook,$data); sub hook { @@ -5938,7 +6032,7 @@ for each option element within the optgroup. =item 5. An optional fifth parameter (-novals) can be set to a true value and -indicates to suppress the val attribut in each option element within +indicates to suppress the val attribute in each option element within the optgroup. See the discussion on optgroup at W3C @@ -6645,7 +6739,7 @@ Netscape versions 2.0 and higher incorporate an interpreted language called JavaScript. Internet Explorer, 3.0 and higher, supports a closely-related dialect called JScript. JavaScript isn't the same as Java, and certainly isn't at all the same as Perl, which is a great -pity. JavaScript allows you to programatically change the contents of +pity. JavaScript allows you to programmatically change the contents of fill-out forms, create new windows, and pop up dialog box from within Netscape itself. From the point of view of CGI scripting, JavaScript is quite useful for validating fill-out forms prior to submitting @@ -7351,7 +7445,7 @@ OLD VERSION NEW VERSION use CGI; - CGI::ReadParse; + CGI::ReadParse(); print "The value of the antique is $in{antique}.\n"; CGI.pm's ReadParse() routine creates a tied variable named %in,