diff -cNr CGI-modules-2.75.orig/CGI/Carp.pm CGI-modules-2.75/CGI/Carp.pm *** CGI-modules-2.75.orig/CGI/Carp.pm Thu Feb 15 02:54:02 1996 --- CGI-modules-2.75/CGI/Carp.pm Mon Apr 29 23:52:56 1996 *************** *** 172,180 **** --- 172,188 ---- realdie $message; } + # Avoid generating "subroutine redefined" warnings with the following + # hack: + { + local $^W=0; + eval <param(-name=>'foo',-values=>['an','array','of','values']); --- 299,306 ---- the \-override parameter accepted by all methods that generate form elements.) .PP ! \fIparam()\fR also recognizes a named parameter style of calling described ! in more detail later: .PP .Vb 1 \& $query->param(-name=>'foo',-values=>['an','array','of','values']); *************** *** 349,356 **** .IX Subsection "\s-1CREATING\s0 A \s-1SELF\s0\-\s-1REFERENCING\s0 \s-1URL\s0 \s-1THAT\s0 \s-1PRESERVES\s0 \s-1STATE\s0 \s-1INFORMATION\s0:" .PP .Vb 2 ! \& $myself = $query->self_url ! \& print "I'm talking to myself. .Ve \fIself_url()\fR will return a \s-1URL\s0, that, when selected, will reinvoke this script with all its state information intact. This is most --- 349,356 ---- .IX Subsection "\s-1CREATING\s0 A \s-1SELF\s0\-\s-1REFERENCING\s0 \s-1URL\s0 \s-1THAT\s0 \s-1PRESERVES\s0 \s-1STATE\s0 \s-1INFORMATION\s0:" .PP .Vb 2 ! \& $myself = $query->self_url; ! \& print "I'm talking to myself."; .Ve \fIself_url()\fR will return a \s-1URL\s0, that, when selected, will reinvoke this script with all its state information intact. This is most *************** *** 359,376 **** of the \fIform\fR\|(s). Something like this will do the trick. .PP .Vb 4 ! \& $myself = $query->self_url ! \& print "See table 1 ! \& print "See table 2 ! \& print "See for yourself .Ve If you don't want to get the whole query string, call the method \fIurl()\fR to return just the \s-1URL\s0 for the script: .PP .Vb 2 ! \& $myself = $query->url ! \& print "No query string in this baby! .Ve .Sh "\s-1CALLING\s0 \s-1CGI\s0 \s-1FUNCTIONS\s0 \s-1THAT\s0 \s-1TAKE\s0 \s-1MULTIPLE\s0 \s-1ARGUMENTS\s0" .IX Subsection "\s-1CALLING\s0 \s-1CGI\s0 \s-1FUNCTIONS\s0 \s-1THAT\s0 \s-1TAKE\s0 \s-1MULTIPLE\s0 \s-1ARGUMENTS\s0" In versions of \s-1CGI\s0.pm prior to 2.0, it could get difficult to remember --- 359,413 ---- of the \fIform\fR\|(s). Something like this will do the trick. .PP .Vb 4 ! \& $myself = $query->self_url; ! \& print "See table 1"; ! \& print "See table 2"; ! \& print "See for yourself"; .Ve If you don't want to get the whole query string, call the method \fIurl()\fR to return just the \s-1URL\s0 for the script: .PP .Vb 2 ! \& $myself = $query->url; ! \& print "No query string in this baby!\en"; .Ve + You can also retrieve the unprocessed query string with \fIquery_string()\fR: + .PP + .Vb 1 + \& $the_string = $query->query_string; + .Ve + .Sh "\s-1COMPATABILITY\s0 \s-1WITH\s0 \s-1CGI\s0\-\s-1LIB\s0.\s-1PL\s0" + .IX Subsection "\s-1COMPATABILITY\s0 \s-1WITH\s0 \s-1CGI\s0\-\s-1LIB\s0.\s-1PL\s0" + To make it easier to port existing programs that use cgi-lib.pl + the compatability routine \*(L"ReadParse\*(R" is provided. Porting is + simple: + .PP + \s-1OLD\s0 \s-1VERSION\s0 + require \*(L"cgi-lib.pl\*(R"; + &ReadParse; + print \*(L"The value of the antique is \f(CW$in\fR{antique}.\en\*(R"; + .PP + \s-1NEW\s0 \s-1VERSION\s0 + use \s-1CGI\s0; + \s-1CGI::\s0ReadParse + print \*(L"The value of the antique is \f(CW$in\fR{antique}.\en\*(R"; + .PP + \s-1CGI\s0.pm's \fIReadParse()\fR routine creates a tied variable named \f(CW%in\fR, + which can be accessed to obtain the query variables. Like + ReadParse, you can also provide your own variable. Infrequently + used features of ReadParse, such as the creation of \f(CW@in\fR and \f(CW$in\fR + variables, are not supported. + .PP + Once you use ReadParse, you can retrieve the query object itself + this way: + .PP + .Vb 3 + \& $q = $in{CGI}; + \& print $q->textfield(-name=>'wow', + \& -value=>'does this really work?'); + .Ve + This allows you to start using the more interesting features + of \s-1CGI\s0.pm without rewriting your old scripts from scratch. .Sh "\s-1CALLING\s0 \s-1CGI\s0 \s-1FUNCTIONS\s0 \s-1THAT\s0 \s-1TAKE\s0 \s-1MULTIPLE\s0 \s-1ARGUMENTS\s0" .IX Subsection "\s-1CALLING\s0 \s-1CGI\s0 \s-1FUNCTIONS\s0 \s-1THAT\s0 \s-1TAKE\s0 \s-1MULTIPLE\s0 \s-1ARGUMENTS\s0" In versions of \s-1CGI\s0.pm prior to 2.0, it could get difficult to remember *************** *** 445,454 **** .Vb 1 \& -or- .Ve ! .Vb 4 \& print $query->header(-type=>'image/gif', \& -status=>'402 Payment required', ! \& -cookie=>&get_random_cookie(), \& -Cost=>'$2.00'); .Ve \fIheader()\fR returns the Content-type: header. You can provide your own --- 482,492 ---- .Vb 1 \& -or- .Ve ! .Vb 5 \& print $query->header(-type=>'image/gif', \& -status=>'402 Payment required', ! \& -expires=>'+3d', ! \& -cookie=>$cookie, \& -Cost=>'$2.00'); .Ve \fIheader()\fR returns the Content-type: header. You can provide your own *************** *** 463,483 **** .Ve The last example shows the named argument style for passing arguments to the \s-1CGI\s0 methods using named parameters. Recognized parameters are ! \fB\-type\fR, \fB\-status\fR, and \fB\-cookie\fR. Any other parameters will ! be stripped of their initial hyphens and turned into header fields. .PP ! The cookie parameter generates a header that tells the browser to provide a \*(L"magic cookie\*(R" during all subsequent transactions with your script. ! The value of the cookie can be almost anything you like (I doubt that ! newlines will work though), and can be used as a unique session \s-1ID\s0 ! or even to store a small number of state variables. You can retrieve ! the value of the browser's magic cookie with the \fIcookie()\fR method. .PP As of version 1.56, all \s-1HTTP\s0 headers produced by \s-1CGI\s0.pm contain the Pragma: no-cache instruction. However, as of version 1.57, this is ! turned \s-1OFF\s0 by default because it causes Netscape 2.0 beta to produce ! an annoying warning message every time the \*(L"back\*(R" button is hit. Turn ! it on again with the method \fIcache()\fR. .Sh "\s-1GENERATING\s0 A \s-1REDIRECTION\s0 \s-1INSTRUCTION\s0" .IX Subsection "\s-1GENERATING\s0 A \s-1REDIRECTION\s0 \s-1INSTRUCTION\s0" .PP --- 501,543 ---- .Ve The last example shows the named argument style for passing arguments to the \s-1CGI\s0 methods using named parameters. Recognized parameters are ! \fB\-type\fR, \fB\-status\fR, \fB\-expires\fR, and \fB\-cookie\fR. Any other ! parameters will be stripped of their initial hyphens and turned into ! header fields, allowing you to specify any \s-1HTTP\s0 header you desire. ! .PP ! Most browsers will not cache the output from \s-1CGI\s0 scripts. Every time ! the browser reloads the page, the script is invoked anew. You can ! change this behavior with the \fB\-expires\fR parameter. When you specify ! an absolute or relative expiration interval with this parameter, some ! browsers and proxy servers will cache the script's output until the ! indicated expiration date. The following forms are all valid for the ! \-expires field: ! .PP ! .Vb 8 ! \& +30s 30 seconds from now ! \& +10m ten minutes from now ! \& +1h one hour from now ! \& -1d yesterday (i.e. "ASAP!") ! \& now immediately ! \& +3M in three months ! \& +10y in ten years time ! \& Thursday, 25-Apr-96 00:40:33 GMT at the indicated time & date ! .Ve ! (\fI\s-1CGI::\s0expires()\fR is the static function call used internally that turns ! relative time intervals into \s-1HTTP\s0 dates. You can call it directly if ! you wish.) .PP ! The \fB\-cookie\fR parameter generates a header that tells the browser to provide a \*(L"magic cookie\*(R" during all subsequent transactions with your script. ! Netscape cookies have a special format that includes interesting attributes ! such as expiration time. Use the \fIcookie()\fR method to create and retrieve ! session cookies. .PP As of version 1.56, all \s-1HTTP\s0 headers produced by \s-1CGI\s0.pm contain the Pragma: no-cache instruction. However, as of version 1.57, this is ! turned \s-1OFF\s0 by default because it causes Netscape 2.0 and higher to ! produce an annoying warning message every time the \*(L"back\*(R" button is ! hit. Turn it on again with the method \fIcache()\fR. .Sh "\s-1GENERATING\s0 A \s-1REDIRECTION\s0 \s-1INSTRUCTION\s0" .IX Subsection "\s-1GENERATING\s0 A \s-1REDIRECTION\s0 \s-1INSTRUCTION\s0" .PP *************** *** 1414,1419 **** --- 1474,1609 ---- pointed to by the \fB\-onClick\fR parameter will be executed. On non-Netscape browsers this form element will probably not even display. + .SH "NETSCAPE COOKIES" + .IX Header "NETSCAPE COOKIES" + Netscape browsers versions 1.1 and higher support a so-called + \*(L"cookie\*(R" designed to help maintain state within a browser session. + CGI.pm has several methods that support cookies. + .PP + A cookie is a name=value pair much like the named parameters in a CGI + query string. CGI scripts create one or more cookies and send + them to the browser in the HTTP header. The browser maintains a list + of cookies that belong to a particular Web server, and returns them + to the CGI script during subsequent interactions. + .PP + In addition to the required name=value pair, each cookie has several + optional attributes: + .Ip "1. an expiration time" 4 + .IX Item "1. an expiration time" + This is a time/date string (in a special \s-1GMT\s0 format) that indicates + when a cookie expires. The cookie will be saved and returned to your + script until this expiration date is reached if the user exits + Netscape and restarts it. If an expiration date isn't specified, the cookie + will remain active until the user quits Netscape. + .Ip "2. a domain" 4 + .IX Item "2. a domain" + This is a partial or complete domain name for which the cookie is + valid. The browser will return the cookie to any host that matches + the partial domain name. For example, if you specify a domain name + of \*(L".capricorn.com\*(R", then Netscape will return the cookie to + Web servers running on any of the machines \*(L"www.capricorn.com\*(R", + \*(L"www2.capricorn.com\*(R", \*(L"feckless.capricorn.com\*(R", etc. Domain names + must contain at least two periods to prevent attempts to match + on top level domains like \*(L".edu\*(R". If no domain is specified, then + the browser will only return the cookie to servers on the host the + cookie originated from. + .Ip "3. a path" 4 + .IX Item "3. a path" + If you provide a cookie path attribute, the browser will check it + against your script's \s-1URL\s0 before returning the cookie. For example, + if you specify the path \*(L"/cgi-bin\*(R", then the cookie will be returned + to each of the scripts \*(L"/cgi-bin/tally.pl\*(R", \*(L"/cgi-bin/order.pl\*(R", + and \*(L"/cgi-bin/customer_service/complain.pl\*(R", but not to the script + \*(L"/cgi-private/site_admin.pl\*(R". By default, path is set to \*(L"/\*(R", which + causes the cookie to be sent to any \s-1CGI\s0 script on your site. + .Ip "4. a \*(L"secure\*(R" flag" 4 + .IX Item "4. a \*(L"secure\*(R" flag" + If the \*(L"secure\*(R" attribute is set, the cookie will only be sent to your + script if the \s-1CGI\s0 request is occurring on a secure channel, such as \s-1SSL\s0. + .PP + The interface to Netscape cookies is the \fBcookie()\fR method: + .PP + .Vb 7 + \& $cookie = $query->cookie(-name=>'sessionID', + \& -value=>'xyzzy', + \& -expires=>'+1h', + \& -path=>'/cgi-bin/database', + \& -domain=>'.capricorn.org', + \& -secure=>1); + \& print $query->header(-cookie=>$cookie); + .Ve + \fBcookie()\fR creates a new cookie. Its parameters include: + .Ip "\fB\-name\fR" 4 + .IX Item "\fB\-name\fR" + The name of the cookie (required). This can be any string at all. + Although Netscape limits its cookie names to non-whitespace + alphanumeric characters, \s-1CGI\s0.pm removes this restriction by escaping + and unescaping cookies behind the scenes. + .Ip "\fB\-value\fR" 4 + .IX Item "\fB\-value\fR" + The value of the cookie. This can be any scalar value, + array reference, or even associative array reference. For example, + you can store an entire associative array into a cookie this way: + .Sp + .Vb 2 + \& $cookie=$query->cookie(-name=>'family information', + \& -value=>\e%childrens_ages); + .Ve + .Ip "\fB\-path\fR" 4 + .IX Item "\fB\-path\fR" + The optional partial path for which this cookie will be valid, as described + above. + .Ip "\fB\-domain\fR" 4 + .IX Item "\fB\-domain\fR" + The optional partial domain for which this cookie will be valid, as described + above. + .Ip "\fB\-expires\fR" 4 + .IX Item "\fB\-expires\fR" + The optional expiration date for this cookie. The format is as described + in the section on the \fBheader()\fR method: + .Sp + .Vb 1 + \& "+1h" one hour from now + .Ve + .Ip "\fB\-secure\fR" 4 + .IX Item "\fB\-secure\fR" + If set to true, this cookie will only be used within a secure + \s-1SSL\s0 session. + .PP + The cookie created by \fIcookie()\fR must be incorporated into the \s-1HTTP\s0 + header within the string returned by the \fIheader()\fR method: + .PP + .Vb 1 + \& print $query->header(-cookie=>$my_cookie); + .Ve + To create multiple cookies, give \fIheader()\fR an array reference: + .PP + .Vb 5 + \& $cookie1 = $query->cookie(-name=>'riddle_name', + \& -value=>"The Sphynx's Question"); + \& $cookie2 = $query->cookie(-name=>'answers', + \& -value=>\e%answers); + \& print $query->header(-cookie=>[$cookie1,$cookie2]); + .Ve + To retrieve a cookie, request it by name by calling \fIcookie()\fR + method without the \fB\-value\fR parameter: + .PP + .Vb 4 + \& use CGI; + \& $query = new CGI; + \& %answers = $query->cookie(-name=>'answers'); + \& # $query->cookie('answers') will work too! + .Ve + See the \fBcookie.cgi\fR example script for some ideas on how to use + cookies effectively. + .PP + \fB\s-1NOTE\s0:\fR There appear to be some (undocumented) restrictions on + Netscape cookies. In Netscape 2.01, at least, I haven't been able to + set more than three cookies at a time. There may also be limits on + the length of cookies. If you need to store a lot of information, + it's probably better to create a unique session \s-1ID\s0, store it in a + cookie, and use the session \s-1ID\s0 to locate an external file/database + saved on the server's side of the connection. .SH "WORKING WITH NETSCAPE FRAMES" .IX Header "WORKING WITH NETSCAPE FRAMES" It's possible for CGI.pm scripts to write into several browser *************** *** 1456,1462 **** When your script is reinvoked by the form, its output will be loaded into the frame named \*(L"ResultsWindow\*(R". If one doesn't already exist a new window will be created. ! .Sp The script \*(L"frameset.cgi\*(R" in the examples directory shows one way to create pages in which the fill-out form and the response live in side-by-side frames. --- 1646,1652 ---- When your script is reinvoked by the form, its output will be loaded into the frame named \*(L"ResultsWindow\*(R". If one doesn't already exist a new window will be created. ! .PP The script \*(L"frameset.cgi\*(R" in the examples directory shows one way to create pages in which the fill-out form and the response live in side-by-side frames. *************** *** 1468,1499 **** from standard input (you don't have to worry about tricking your script into reading from environment variables). You can pass keywords like this: ! .Sp .Vb 1 \& your_script.pl keyword1 keyword2 keyword3 .Ve or this: ! .Sp .Vb 1 \& your_script.pl keyword1+keyword2+keyword3 .Ve or this: ! .Sp .Vb 1 \& your_script.pl name1=value1 name2=value2 .Ve or this: ! .Sp .Vb 1 \& your_script.pl name1=value1&name2=value2 .Ve or even as newline-delimited parameters on standard input. ! .Sp When debugging, you can use quotes and backslashes to escape characters in the familiar shell manner, letting you place spaces and other funny characters in your parameter=value pairs: ! .Sp .Vb 1 \& your_script.pl "name1='I am a long value'" "name2=two\e words" .Ve --- 1658,1689 ---- from standard input (you don't have to worry about tricking your script into reading from environment variables). You can pass keywords like this: ! .PP .Vb 1 \& your_script.pl keyword1 keyword2 keyword3 .Ve or this: ! .PP .Vb 1 \& your_script.pl keyword1+keyword2+keyword3 .Ve or this: ! .PP .Vb 1 \& your_script.pl name1=value1 name2=value2 .Ve or this: ! .PP .Vb 1 \& your_script.pl name1=value1&name2=value2 .Ve or even as newline-delimited parameters on standard input. ! .PP When debugging, you can use quotes and backslashes to escape characters in the familiar shell manner, letting you place spaces and other funny characters in your parameter=value pairs: ! .PP .Vb 1 \& your_script.pl "name1='I am a long value'" "name2=two\e words" .Ve *************** *** 1502,1514 **** The \fIdump()\fR method produces a string consisting of all the query's name/value pairs formatted nicely as a nested list. This is useful for debugging purposes: ! .Sp .Vb 2 \& print $query->dump \& .Ve Produces something that looks like: ! .Sp .Vb 11 \& ! [CAUTION] As of version 2.0 I have changed the behavior of hidden fields once again. Read this if you use hidden fields.

*************** *** 1539,1549 **** are handled correctly.

auth_type()
Return the authorization type, if protection is active. Example "Basic". !
cookie() !
Returns the "magic cookie" maintained by Netscape 1.1 and higher. ! In conjunction with the header()-cookie ! parameter, this can be used to keep track of a particular browser. This ! will not work with non-Netscape browsers.
path_info()
Returns additional path information from the script URL. E.G. fetching /cgi-bin/your_script/additional/stuff will --- 1563,1572 ---- are handled correctly.
auth_type()
Return the authorization type, if protection is active. Example "Basic". !
raw_cookie() !
Returns the "magic cookie" maintained by Netscape 1.1 and higher in a raw ! state. You'll probably want to use cookie() instead, ! which gives you a high-level interface to the cookie functions.
path_info()
Returns additional path information from the script URL. E.G. fetching /cgi-bin/your_script/additional/stuff will *************** *** 1553,1558 **** --- 1576,1583 ----
As per path_info() but returns the additional path information translated into a physical path, e.g. "/usr/local/etc/httpd/htdocs/additional/stuff". +
query_string() +
Returns a query string suitable for maintaining state.
referer()
Return the URL of the page the browser was viewing prior to fetching your script. Not available for all *************** *** 1589,1594 **** --- 1614,1753 ---- Table of contents
+ +

Netscape Cookies

+
+ + Netscape browsers versions 1.1 and higher support a so-called + "cookie" designed to help maintain state within a browser session. + CGI.pm has several methods that support cookies. + +

+ + A cookie is a name=value pair much like the named parameters in a CGI + query string. CGI scripts create one or more cookies and send + them to the browser in the HTTP header. The browser maintains a list + of cookies that belong to a particular Web server, and returns them + to the CGI script during subsequent interactions. + +

+ + In addition to the required name=value pair, each cookie has several + optional attributes: + +

+
an expiration time +
This is a time/date string (in a special GMT format) that indicates + when a cookie expires. The cookie will be saved and returned to your + script until this expiration date is reached if the user exits + Netscape and restarts it. If an expiration date isn't specified, the cookie + will remain active until the user quits Netscape.

+

a domain +
This is a partial or complete domain name for which the cookie is + valid. The browser will return the cookie to any host that matches + the partial domain name. For example, if you specify a domain name + of ".capricorn.com", then Netscape will return the cookie to + Web servers running on any of the machines "www.capricorn.com", + "www2.capricorn.com", "feckless.capricorn.com", etc. Domain names + must contain at least two periods to prevent attempts to match + on top level domains like ".edu". If no domain is specified, then + the browser will only return the cookie to servers on the host the + cookie originated from.

+

a path +
If you provide a cookie path attribute, the browser will check it + against your script's URL before returning the cookie. For example, + if you specify the path "/cgi-bin", then the cookie will be returned + to each of the scripts "/cgi-bin/tally.pl", "/cgi-bin/order.pl", + and "/cgi-bin/customer_service/complain.pl", but not to the script + "/cgi-private/site_admin.pl". By default, path is set to "/", which + causes the cookie to be sent to any CGI script on your site. +
a "secure" flag +
If the "secure" attribute is set, the cookie will only be sent to your + script if the CGI request is occurring on a secure channel, such as SSL. +
+ + The interface to Netscape cookies is the cookie() method: +
+     $cookie = $query->cookie(-name=>'sessionID',
+ 			     -value=>'xyzzy',
+ 			     -expires=>'+1h',
+ 			     -path=>'/cgi-bin/database',
+ 			     -domain=>'.capricorn.org',
+ 			     -secure=>1);
+     print $query->header(-cookie=>$cookie);
+ 
+ + cookie() creates a new cookie. Its parameters include: + +
+
-name +
The name of the cookie (required). This can be any string at all. + Although Netscape limits its cookie names to non-whitespace + alphanumeric characters, CGI.pm removes this restriction by escaping + and unescaping cookies behind the scenes.

+

-value +
The value of the cookie. This can be any scalar value, + array reference, or even associative array reference. For example, + you can store an entire associative array into a cookie this way: +
+ 	$cookie=$query->cookie(-name=>'family information',
+                                -value=>\%childrens_ages);
+ 
+ +
-path +
The optional partial path for which this cookie will be valid, as described + above.

+

-domain +
The optional partial domain for which this cookie will be valid, as described + above. +
-expires +
The optional expiration date for this cookie. The format is as described + in the section on the B method: +
+ 	"+1h"  one hour from now
+       
+
-secure +
If set to true, this cookie will only be used within a secure + SSL session. +
+ + The cookie created by cookie() must be incorporated into the HTTP + header within the string returned by the header() method: +
+ 	print $query->header(-cookie=>$my_cookie);
+ 
+ To create multiple cookies, give header() an array reference: +
+ 	$cookie1 = $query->cookie(-name=>'riddle_name',
+                                   -value=>"The Sphynx's Question");
+         $cookie2 = $query->cookie(-name=>'answers',
+                                   -value=>\%answers);
+         print $query->header(-cookie=>[$cookie1,$cookie2]);
+ 
+ To retrieve a cookie, request it by name by calling cookie() + method without the -value parameter: +
+ 	use CGI;
+ 	$query = new CGI;
+ 	%answers = $query->cookie('answers');
+ 	# $query->cookie(-name=>'answers') works too!
+ 
+ See the cookie.cgi example script + for some ideas on how to use cookies effectively. +

+ + NOTE: There appear to be some (undocumented) + restrictions on Netscape cookies. In Netscape 2.01, at least, I + haven't been able to set more than three cookies at a time. There may + also be limits on the length of cookies. If you need to store a lot + of information, it's probably better to create a unique session ID, + store it in a cookie, and use the session ID to locate an external + file/database saved on the server's side of the connection. +

+ Table of contents + +


+

Support for Netscape Frames

*************** *** 1621,1629 **** frame. The third section is responsible for creating the response and directing it into a different frame.

! The examples directory contains a script called ! popup.cgi that demonstrates a simple ! popup window. frameset.cgi provides a skeleton script for creating side-by-side query/result frame sets.


--- 1780,1788 ---- frame. The third section is responsible for creating the response and directing it into a different frame.

! The examples directory contains a script called ! popup.cgi that demonstrates a simple ! popup window. frameset.cgi provides a skeleton script for creating side-by-side query/result frame sets.


*************** *** 1746,1752 ****
     print $q->startform(-onSubmit=>"validateMe(this)");
  
! See the javascript.cgi script for a demonstration of how this all works.

Table of contents --- 1905,1911 ----

     print $q->startform(-onSubmit=>"validateMe(this)");
  
! See the javascript.cgi script for a demonstration of how this all works.

Table of contents *************** *** 1903,1908 **** --- 2062,2131 ---- print "<HR>\n"; print $query->end_html; +

+ Table of contents +


+ +

Migrating from cgi-lib.pl

+ + To make it easier to convert older scripts that use cgi-lib.pl, + CGI.pm provides a CGI::ReadParse() call that + is compatible with cgi-lib.pl's &ReadParse + subroutine. +

+ + When you call ReadParse(), CGI.pm creates an associative array + named %in that contains the named CGI + parameters. Multi-valued parameters are separated by "\0" + characters in exactly the same way cgi-lib.pl does it. To + port an old script to CGI.pm, you have to make just two changes: + +

Old Script

+
+     require "cgi-lib.pl";
+     &ReadParse;
+     print "The value of the antique is $in{antique}.\n";
+ 
+ +

New Script

+
+     use CGI;
+     CGI::ReadParse;
+     print "The value of the antique is $in{antique}.\n";
+ 
+ + Like cgi-lib's ReadParse, pass a variable glob in + order to use a different variable than the default "%in": +
+    CGI::ReadParse(%Q);
+    @partners = split("\0",$Q{'golf_partners'});
+ 
+ +

+ The associative array created by CGI::ReadParse() contains + a special key 'CGI', which returns the CGI query object + itself: +

+     CGI::ReadParse;
+     $q = $in{CGI};
+     print $q->textfield(-name=>'wow',
+                         -value=>'does this really work?');
+ 
+

+ + This allows you to add the more interesting features + of CGI.pm to your old scripts without rewriting them completely. + As an added benefit, the %in variable is + actually tie()'d to the CGI object. Changing the + CGI object using param() will dynamically + change %in, and vice-versa. + +

+ + cgi-lib.pl's @in and $in variables are + not supported. File upload via these compatability + routines may work, but has not been tested. +


CGI.pm and the Self Loader

*************** *** 2071,2125 ****

Using CGI.pm on non-Unix Platforms

!

Windows NT

! The NT port of perl has an annoying habit of transforming newline (\n) ! sequences into carriage-return/newline (\r\n) sequences both on ! input and output. This confuses certain servers, such as the ! Netscape Communications Server. To make things work correctly, ! find the following line in CGI.pm !
!    $needs_binmode = 0;
! 
! and change it to
!    $needs_binmode = 1;
  
! CGI.pm works well with WebSite, the EMWACS server and Purveyor. ! CGI.pm must be put in the perl5 library directory, ! and all CGI scripts that use it should be placed in cgi-bin directory. ! You also need to associate the .pl suffix with perl5 using the NT ! file manager.

WebSite uses a slightly different cgi-bin directory structure than the standard. For this server, place the scripts in the ! cgi-shl directory.

! The Netscape Communications Server has terrible problems with Perl ! scripts because it doesn't use the standard NT file extension ! associations. Netscape's recommendation of placing perl.exe ! in cgi-bin is a terrible mistake because it opens up a huge secure hole. ! Don't do it! It's also a mistake to place .bat ! files in cgi-bin because of another security hole in the server. You're ! safest running Visual Basic or C programs in cgi-bin if you use the ! Netscape Server.

VMS

! Set $needs_binmode to 1 as described above.

Macintosh

! Christian Huldt reports that at least the basic features of CGI.pm work ! correctly with MacPerl version 5.0.6r1 and ! the WebStar and MacHTTP servers. The following changes have to be made: !
    !
  1. Replace $CRLF="\r\n" with $CRLF="\015\012". ! This has to do with MacPerl's rather liberal interpretation of the ! meaning of the \r and \n escapes! (NOTE: This has already been done ! for you in version 2.18). !
  2. Use '-value' instead of -value in the parameter lists. !

Future Prospects for this Library

--- 2294,2364 ----

Using CGI.pm on non-Unix Platforms

! I don't have access to all the combinations of hardware and software ! that I really need to make sure that CGI.pm works consistently for all ! Web servers, so I rely heavily on helpful reports from users like ! yourself. ! !

! ! There are a number of differences in file name and text processing ! conventions on different platforms. By default, CGI.pm is set up ! to work properly on a Unix (or Linux) system. To run it in other ! operating systems find the section of code near the top that looks ! like this:

!    # CHANGE THIS VARIABLE FOR YOUR OPERATING SYSTEM
!    $OS = 'UNIX';
!    # $OS = 'MACINTOSH';
!    # $OS = 'WINDOWS';
!    # $OS = 'NT';
!    # $OS = 'VMS';
  
! Comment out 'UNIX' and uncomment the line that's appropriate for your ! OS. (WINDOWS is valid for both Windows 3.1 and Windows95). !

! ! Other notes follow: ! !

Windows NT

! ! CGI.pm works well with WebSite, the EMWACS server, Purveyor and the ! Microsoft IIS server. CGI.pm must be put in the perl5 library ! directory, and all CGI scripts that use it should be placed in cgi-bin ! directory. You also need to associate the .pl suffix ! with perl5 using the NT file manager (Website, Purveyor), or install ! the Perl DLL library (IIS). !

WebSite uses a slightly different cgi-bin directory structure than the standard. For this server, place the scripts in the ! cgi-shl directory. CGI.pm appears to work correctly ! in both the Windows95 and WindowsNT versions of WebSite. ! !

! Old Netscape Communications Server technical notes recommended ! placing perl.exe in cgi-bin. This a very bad idea because ! it opens up a gaping security hole. Put a C .exe wrapper ! around the perl script until such time as Netscape recognizes NT file ! manager associations, or provides a Perl-compatible DLL library for its ! servers. !

! ! If you have trouble with file uploads, make you ma

VMS

! ! I don't have access to a VMS machine, and I'm not sure whether file upload ! works correctly. Other features are known to work.

Macintosh

! CGI.pm works with MacPerl version 5.0.6r1 or higher under ! the WebStar and MacHTTP servers.
+

Future Prospects for this Library

*************** *** 2155,2171 **** You might also be interested in two packages for creating graphics on the fly:
!
GD.html
A module for creating GIF images on the fly, using Tom Boutell's ! gd graphics library. !
qd.pl
A library for creating Macintosh PICT files on the fly (which can be converted to GIF or JPEG using NetPBM).

For a collection of CGI scripts of various levels of complexity, see the companion pages for my book ! How to Set Up and Maintain a World Wide Web Site


--- 2394,2410 ---- You might also be interested in two packages for creating graphics on the fly:
!
GD.html
A module for creating GIF images on the fly, using Tom Boutell's ! gd graphics library. !
qd.pl
A library for creating Macintosh PICT files on the fly (which can be converted to GIF or JPEG using NetPBM).

For a collection of CGI scripts of various levels of complexity, see the companion pages for my book ! How to Set Up and Maintain a World Wide Web Site


*************** *** 2186,2191 **** --- 2425,2439 ----

Revision History

+

Version 2.19

+
    +
  1. Added cookie() support routines. +
  2. Added -expires parameter to header(). +
  3. Added cgi-lib.pl compatability mode. +
  4. Made the module more configurable for different + operating systems. +
  5. Fixed a dumb bug in JavaScript button() method. +

Version 2.18

  1. Fixed a bug that corrects a hang that *************** *** 2440,2445 **** Whitehead Institute/MIT Center for Genome Research

    ! Last modified: Tue Apr 2 23:54:50 EST 1996 --- 2688,2693 ---- Whitehead Institute/MIT Center for Genome Research

    ! Last modified: Wed Apr 24 22:14:08 EDT 1996 diff -cNr CGI-modules-2.75.orig/examples/cookie.cgi CGI-modules-2.75/examples/cookie.cgi *** CGI-modules-2.75.orig/examples/cookie.cgi Wed Dec 31 19:00:00 1969 --- CGI-modules-2.75/examples/cookie.cgi Mon Apr 29 23:45:16 1996 *************** *** 0 **** --- 1,90 ---- + #!/usr/local/bin/perl + + use CGI; + use CGI::Carp; + $q = new CGI; + + @ANIMALS=sort qw/lion tiger bear pig porcupine ferret zebra gnu ostrich + emu moa goat weasel yak chicken sheep hyena dodo lounge-lizard + squirrel rat mouse hedgehog racoon baboon kangaroo hippopotamus + giraffe/; + + # Recover the previous animals from the magic cookie. + # The cookie has been formatted as an associative array + # mapping animal name to the number of animals. + %zoo = $q->cookie('animals'); + + # Recover the new animal(s) from the parameter 'new_animal' + @new = $q->param('new_animals'); + + # If the action is 'add', then add new animals to the zoo. Otherwise + # delete them. + foreach (@new) { + if ($q->param('action') eq 'Add') { + $zoo{$_}++; + } elsif ($q->param('action') eq 'Delete') { + $zoo{$_}-- if $zoo{$_}; + delete $zoo{$_} unless $zoo{$_}; + } + } + + # Add new animals to old, and put them in a cookie + $the_cookie = $q->cookie(-name=>'animals', + -value=>\%zoo, + -expires=>'+1h'); + + # Print the header, incorporating the cookie and the expiration date... + print $q->header(-cookie=>$the_cookie); + + # Now we're ready to create our HTML page. + print $q->start_html('Animal crackers'); + + print <Animal Crackers + Choose the animals you want to add to the zoo, and click "add". + Come back to this page any time within the next hour and the list of + animals in the zoo will be resurrected. You can even quit Netscape + completely! +

    + Try adding the same animal several times to the list. Does this + remind you vaguely of a shopping cart? +

    + This script only works with Netscape browsers +

    +

    + +
    Add/DeleteCurrent Contents + EOF + ; + + print "
    ",$q->start_form; + print $q->scrolling_list(-name=>'new_animals', + -values=>[@ANIMALS], + -multiple=>1, + -override=>1, + -size=>10),"
    "; + print $q->submit(-name=>'action',-value=>'Delete'), + $q->submit(-name=>'action',-value=>'Add'); + print $q->end_form; + + print "
    "; + if (%zoo) { # make a table + print "
      \n"; + foreach (sort keys %zoo) { + print "
    • $zoo{$_} $_\n"; + } + print "
    \n"; + } else { + print "The zoo is empty.\n"; + } + print "
    "; + + print < +
    Lincoln D. Stein

    + More Examples + EOF + ; + print $q->end_html; + + diff -cNr CGI-modules-2.75.orig/examples/cookie.txt CGI-modules-2.75/examples/cookie.txt *** CGI-modules-2.75.orig/examples/cookie.txt Wed Dec 31 19:00:00 1969 --- CGI-modules-2.75/examples/cookie.txt Mon Apr 29 23:45:16 1996 *************** *** 0 **** --- 1,90 ---- + #!/usr/local/bin/perl + + use CGI; + use CGI::Carp; + $q = new CGI; + + @ANIMALS=sort qw/lion tiger bear pig porcupine ferret zebra gnu ostrich + emu moa goat weasel yak chicken sheep hyena dodo lounge-lizard + squirrel rat mouse hedgehog racoon baboon kangaroo hippopotamus + giraffe/; + + # Recover the previous animals from the magic cookie. + # The cookie has been formatted as an associative array + # mapping animal name to the number of animals. + %zoo = $q->cookie('animals'); + + # Recover the new animal(s) from the parameter 'new_animal' + @new = $q->param('new_animals'); + + # If the action is 'add', then add new animals to the zoo. Otherwise + # delete them. + foreach (@new) { + if ($q->param('action') eq 'Add') { + $zoo{$_}++; + } elsif ($q->param('action') eq 'Delete') { + $zoo{$_}-- if $zoo{$_}; + delete $zoo{$_} unless $zoo{$_}; + } + } + + # Add new animals to old, and put them in a cookie + $the_cookie = $q->cookie(-name=>'animals', + -value=>\%zoo, + -expires=>'+1h'); + + # Print the header, incorporating the cookie and the expiration date... + print $q->header(-cookie=>$the_cookie); + + # Now we're ready to create our HTML page. + print $q->start_html('Animal crackers'); + + print <Animal Crackers + Choose the animals you want to add to the zoo, and click "add". + Come back to this page any time within the next hour and the list of + animals in the zoo will be resurrected. You can even quit Netscape + completely! +

    + Try adding the same animal several times to the list. Does this + remind you vaguely of a shopping cart? +

    + This script only works with Netscape browsers +

    +

    + +
    Add/DeleteCurrent Contents + EOF + ; + + print "
    ",$q->start_form; + print $q->scrolling_list(-name=>'new_animals', + -values=>[@ANIMALS], + -multiple=>1, + -override=>1, + -size=>10),"
    "; + print $q->submit(-name=>'action',-value=>'Delete'), + $q->submit(-name=>'action',-value=>'Add'); + print $q->end_form; + + print "
    "; + if (%zoo) { # make a table + print "
      \n"; + foreach (sort keys %zoo) { + print "
    • $zoo{$_} $_\n"; + } + print "
    \n"; + } else { + print "The zoo is empty.\n"; + } + print "
    "; + + print < +
    Lincoln D. Stein

    + More Examples + EOF + ; + print $q->end_html; + + diff -cNr CGI-modules-2.75.orig/examples/index.html CGI-modules-2.75/examples/index.html *** CGI-modules-2.75.orig/examples/index.html Sat Mar 16 15:38:37 1996 --- CGI-modules-2.75/examples/index.html Mon Apr 29 23:44:52 1996 *************** *** 36,41 **** --- 36,47 ----
  2. Look at its source code +

    Maintain state over a long period with a cookie

    + +

    Popup the response in a new window

    • Try the script *************** *** 63,68 ****
      Lincoln D. Stein, lstein@genome.wi.mit.edu
      Whitehead Institute/MIT Center for Genome Research
      ! Last modified: Sat Mar 16 21:38:37 MET 1996 --- 69,74 ----
      Lincoln D. Stein, lstein@genome.wi.mit.edu
      Whitehead Institute/MIT Center for Genome Research
      ! Last modified: Wed Apr 24 22:24:40 EDT 1996 diff -cNr CGI-modules-2.75.orig/examples/javascript.cgi CGI-modules-2.75/examples/javascript.cgi *** CGI-modules-2.75.orig/examples/javascript.cgi Wed Mar 20 17:34:00 1996 --- CGI-modules-2.75/examples/javascript.cgi Mon Apr 29 23:44:52 1996 *************** *** 92,98 **** -onClick=>"doPraise(this)"),"

      \n"; print "Hair color: ",$q->popup_menu(-name=>'color', -value=>[qw/brunette blonde red gray/], ! -default->'red', -onChange=>"checkColor(this)"),"

      \n"; print $q->hidden(-name=>'age',-value=>0); print $q->submit(); --- 92,98 ---- -onClick=>"doPraise(this)"),"

      \n"; print "Hair color: ",$q->popup_menu(-name=>'color', -value=>[qw/brunette blonde red gray/], ! -default=>'red', -onChange=>"checkColor(this)"),"

      \n"; print $q->hidden(-name=>'age',-value=>0); print $q->submit(); diff -cNr CGI-modules-2.75.orig/examples/javascript.txt CGI-modules-2.75/examples/javascript.txt *** CGI-modules-2.75.orig/examples/javascript.txt Wed Mar 20 17:34:00 1996 --- CGI-modules-2.75/examples/javascript.txt Mon Apr 29 23:44:52 1996 *************** *** 92,98 **** -onClick=>"doPraise(this)"),"

      \n"; print "Hair color: ",$q->popup_menu(-name=>'color', -value=>[qw/brunette blonde red gray/], ! -default->'red', -onChange=>"checkColor(this)"),"

      \n"; print $q->hidden(-name=>'age',-value=>0); print $q->submit(); --- 92,98 ---- -onClick=>"doPraise(this)"),"

      \n"; print "Hair color: ",$q->popup_menu(-name=>'color', -value=>[qw/brunette blonde red gray/], ! -default=>'red', -onChange=>"checkColor(this)"),"

      \n"; print $q->hidden(-name=>'age',-value=>0); print $q->submit(); diff -cNr CGI-modules-2.75.orig/examples/multiple_forms.cgi CGI-modules-2.75/examples/multiple_forms.cgi *** CGI-modules-2.75.orig/examples/multiple_forms.cgi Wed Dec 31 19:00:00 1969 --- CGI-modules-2.75/examples/multiple_forms.cgi Mon Apr 29 23:45:37 1996 *************** *** 0 **** --- 1,54 ---- + #!/usr/local/bin/perl + + use CGI; + + $query = new CGI; + print $query->header; + print $query->start_html('Multiple Forms'); + print "

      Multiple Forms

      \n"; + + # Print the first form + print $query->startform; + $name = $query->remote_user || 'anonymous@' . $query->remote_host; + + print "What's your name? ",$query->textfield('name',$name,50); + print "

      What's the combination?

      ", + $query->checkbox_group('words',['eenie','meenie','minie','moe']); + print "

      What's your favorite color? ", + $query->popup_menu('color',['red','green','blue','chartreuse']), + "

      "; + print $query->submit('form_1','Send Form 1'); + print $query->endform; + + # Print the second form + print "


      \n"; + print $query->startform; + print "Some radio buttons: ",$query->radio_group('radio buttons', + [qw{one two three four five}],'three'),"\n"; + print "

      What's the password? ",$query->password_field('pass','secret'); + print $query->defaults,$query->submit('form_2','Send Form 2'),"\n"; + print $query->endform; + + print "


      \n"; + + $query->import('Q'); + if ($Q::form_1) { + print "

      Form 1 Submitted

      \n"; + print "Your name is $Q::name\n"; + print "

      The combination is: {",join(",",@Q::words),"}\n"; + print "

      Your favorite color is $Q::color\n"; + } elsif ($Q::form_2) { + print <Form 2 Submitted +

      The value of the radio buttons is $Q::radio_buttons +

      The secret password is $Q::pass + EOF + ; + } + print qq{

      Other examples}; + print qq{

      Go to the documentation}; + + print $query->end_html; + + + diff -cNr CGI-modules-2.75.orig/examples/multiple_forms.txt CGI-modules-2.75/examples/multiple_forms.txt *** CGI-modules-2.75.orig/examples/multiple_forms.txt Wed Dec 31 19:00:00 1969 --- CGI-modules-2.75/examples/multiple_forms.txt Mon Apr 29 23:45:37 1996 *************** *** 0 **** --- 1,54 ---- + #!/usr/local/bin/perl + + use CGI; + + $query = new CGI; + print $query->header; + print $query->start_html('Multiple Forms'); + print "

      Multiple Forms

      \n"; + + # Print the first form + print $query->startform; + $name = $query->remote_user || 'anonymous@' . $query->remote_host; + + print "What's your name? ",$query->textfield('name',$name,50); + print "

      What's the combination?

      ", + $query->checkbox_group('words',['eenie','meenie','minie','moe']); + print "

      What's your favorite color? ", + $query->popup_menu('color',['red','green','blue','chartreuse']), + "

      "; + print $query->submit('form_1','Send Form 1'); + print $query->endform; + + # Print the second form + print "


      \n"; + print $query->startform; + print "Some radio buttons: ",$query->radio_group('radio buttons', + [qw{one two three four five}],'three'),"\n"; + print "

      What's the password? ",$query->password_field('pass','secret'); + print $query->defaults,$query->submit('form_2','Send Form 2'),"\n"; + print $query->endform; + + print "


      \n"; + + $query->import('Q'); + if ($Q::form_1) { + print "

      Form 1 Submitted

      \n"; + print "Your name is $Q::name\n"; + print "

      The combination is: {",join(",",@Q::words),"}\n"; + print "

      Your favorite color is $Q::color\n"; + } elsif ($Q::form_2) { + print <Form 2 Submitted +

      The value of the radio buttons is $Q::radio_buttons +

      The secret password is $Q::pass + EOF + ; + } + print qq{

      Other examples}; + print qq{

      Go to the documentation}; + + print $query->end_html; + + +