WARNING: The overloaded double-quote ("") operator has been removed. In previous versions, CGI objects were automatically interpolated as HTML into double-quoted strings. This was useful for debugging, but broke in newer versions of Perl.
Everything is done through a ``CGI'' object. When you create one of these objects it examines the environment for a query string, parses it, and stores the results. You can then ask the CGI object to return or modify the query values. CGI objects handle POST and GET methods correctly, and correctly distinguish between scripts called from <ISINDEX> documents and form-based documents. In fact you can debug your script from the command line without worrying about setting up environment variables.
A script to create a fill-out form that remembers its state each time it's invoked is very easy to write with CGI.pm:
#!/usr/local/bin/perl use CGI qw(:standard); print header; print start_html('A Simple Example'), h1('A Simple Example'), start_form, "What's your name? ",textfield('name'), p, "What's the combination?", p, checkbox_group(-name=>'words', -values=>['eenie','meenie','minie','moe'], -defaults=>['eenie','minie']), p, "What's your favorite color? ", popup_menu(-name=>'color', -values=>['red','green','blue','chartreuse']), p, submit, end_form, 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')), hr; } print a({href=>'../cgi_docs.html'},'Go to the documentation');Select this link to try the script
This package requires perl 5.001m or higher. (Perl 5.003 is
highly recommended because of a security hole in
earlier versions of perl.) You also must have the SelfLoader module installed. To use CGI.pm
simply install it in your perl library directory. On most systems
this will be /usr/local/lib/perl5
, but check with the
administrator of your system to be sure. If you know the location of
the directory, you can move the module directly:
cp CGI.pm /usr/local/lib/perl5/(This assumes that the perl library is located at
/usr/local/lib/perl5
.
Windows users should of course use the "copy" command rather than "cp").
In most cases, though, you should have perl do the installation for you. Move to the directory containing CGI.pm and type the following commands:
% perl Makefile.PL % make % make installYou may need to be root to do the last step.
This will create two new files in your Perl library. CGI.pm is the main library file. Carp.pm (in the subdirectory "CGI") contains some optional utility routines for writing nicely formatted error messages into your server logs. See the Carp.pm man page for more details.
If you get error messages when you try to install, then you are either:
If you do not have sufficient privileges to install into
/usr/local/lib/perl5, you can still use CGI.pm. Place it
in some convenient place, for example, in
/usr/local/etc/httpd/cgi-bin
and preface your CGI
scripts with a preamble something like the following:
Users of pre-5.002 versions of perl (which includes NT perl) will have to use this form instead:use lib '/usr/local/etc/httpd/cgi-bin'; use CGI;
Be sure to replace /usr/local/etc/httpd/cgi-bin with the true location of CGI.pm.BEGIN { unshift(@INC,'/usr/local/etc/httpd/cgi-bin'); } use CGI;
Notes on using CGI.pm in NT and other non-Unix platforms
use CGI; $query = new CGI;In the object-oriented world of Perl 5, this code calls the new() method of the CGI class and stores a new CGI object into the variable named $query. The new() method does all the dirty work of parsing the script parameters and environment variables and stores its results in the new object. You'll now make method calls with this object to get at the parameters, generate form elements, and do other useful things.
An alternative form of the new() method allows you to read script parameters from a previously-opened file handle:
$query = new CGI(FILEHANDLE)The filehandle can contain a URL-encoded query string, or can be a series of newline delimited TAG=VALUE pairs. This is compatible with the save() method. This lets you save the state of a CGI script to a file and reload it later. It's also possible to save the contents of several query objects to the same file, either within a single script or over a period of time. You can then reload the multiple records into an array of query objects with something like this:
You can make simple databases this way, or create a guestbook. If you're a Perl purist, you can pass a reference to the filehandle glob instead of the filehandle name. This is the "official" way to pass filehandles in Perl5:open (IN,"test.out") || die; while (!eof(IN)) { my $q = new CGI(IN); push(@queries,$q); }
(If you don't know what I'm talking about, then you're not a Perl purist and you needn't worry about it.)my $q = new CGI(\*IN);
You can initialize a CGI object from an associative-array reference. Values can be either single- or multivalued:
Finally, you can initialize a CGI object by passing a URL-style query string to the new() method like this:$query = new CGI({'dinosaur'=>'barney', 'song'=>'I love you', 'friends'=>[qw/Jessica George Nancy/]});
This form also allows you to create a CGI object that is initially empty:$query = new CGI('dinosaur=barney&color=purple');
See advanced techniques for more information.$empty_query = new CGI('');
@keywords = $query->keywordsIf the script was invoked as the result of an <ISINDEX> search, the parsed keywords can be obtained with the keywords() method. This method will return the keywords as a perl array.
@names = $query->paramIf the script was invoked with a parameter list (e.g. "name1=value1&name2=value2&name3=value3"), the param() method will return the parameter names as a list. For backwards compatability, this method will work even if the script was invoked as an <ISINDEX> script: in this case there will be a single parameter name returned named 'keywords'.
@values = $query->param('foo'); -or- $value = $query->param('foo');Pass the param() method a single argument to fetch the value of the named parameter. If the parameter is multivalued (e.g. from multiple selections in a scrolling list), you can ask to receive an array. Otherwise the method will return a single value.
As of version 1.50 of this library, the array of parameter names returned
will be in the same order in which the browser sent them. Although
this is not guaranteed to be identical to the order in which the
parameters were defined in the fill-out form, this is usually the
case.
Setting The Value(s) Of A Named Parameter
$query->param('foo','an','array','of','values'); -or- $query->param(-name=>'foo',-values=>['an','array','of','values']);This sets the value for the named parameter 'foo' to one or more values. These values will be used to initialize form elements, if you so desire. Note that this is the one way to forcibly change the value of a form field after it has previously been set.
The second example shows an alternative "named parameter" style of function
call that is accepted by most of the CGI methods. See
Calling CGI functions that Take Multiple Arguments for an explanation of
this style.
Appending a Parameter
$query->append(-name=>'foo',-values=>['yet','more','values']);This adds a value or list of values to the named parameter. The values are appended to the end of the parameter if it already exists. Otherwise the parameter is created.
$query->delete('foo');This deletes a named parameter entirely. This is useful when you want to reset the value of the parameter so that it isn't passed down between invocations of the script.
$query->delete_all();This deletes all the parameters and leaves you with an empty CGI object. This may be useful to restore all the defaults produced by the form element generating methods.
$query->import_names('R'); print "Your name is $R::name\n" print "Your favorite colors are @R::colors\n";This imports all parameters into the given name space. For example, if there were parameters named 'foo1', 'foo2' and 'foo3', after executing
$query->import_names('R')
, the variables
@R::foo1, $R::foo1, @R::foo2, $R::foo2,
etc. would
conveniently spring into existence. Since CGI has no way of
knowing whether you expect a multi- or single-valued parameter,
it creates two variables for each parameter. One is an array,
and contains all the values, and the other is a scalar containing
the first member of the array. Use whichever one is appropriate.
For keyword (a+b+c+d) lists, the variable @R::keywords will be
created.
If you don't specify a name space, this method assumes namespace "Q".
Warning: do not import into namespace 'main'. This represents a major security risk, as evil people could then use this feature to redefine central variables such as @INC. CGI.pm will exit with an error if you try to do this.
Note: this method used to be called import(). As of
version 2.20 import()
has been changed to be consistent
with other Perl modules. Please change all occurrences of import() to
import_names().
$query->save(FILEHANDLE)This writes the current query out to the file handle of your choice. The file handle must already be open and be writable, but other than that it can point to a file, a socket, a pipe, or whatever. The contents of the form are written out as TAG=VALUE pairs, which can be reloaded with the new() method at some later time. You can write out multiple queries to the same file and later read them into query objects one by one.
See advanced techniques for more information.
$my_url=$query->self_urlThis call returns a URL that, when selected, reinvokes this script with all its state information intact. This is most useful when you want to jump around within a script-generated document using internal anchors, but don't want to disrupt the current contents of the form(s). See advanced techniques for an example.
If you'd like to get the URL without the entire query string appended to
it, use the url()
method:
$my_self=$query->urlTable of contents
$field = $query->radio_group(-name=>'OS', -values=>[Unix,Windows,Macintosh], -default=>'Unix');The advantages of this style are that you don't have to remember the exact order of the arguments, and if you leave out a parameter, iit will usually default to some reasonable value. If you provide a parameter that the method doesn't recognize, it will usually do something useful with it, such as incorporating it into the HTML tag as an attribute. For example if Netscape decides next week to add a new JUSTIFICATION parameter to the text field tags, you can start using the feature without waiting for a new version of CGI.pm:
$field = $query->textfield(-name=>'State', -default=>'gaseous', -justification=>'RIGHT');This will result in an HTML tag that looks like this:
<INPUT TYPE="textfield" NAME="State" VALUE="gaseous" JUSTIFICATION="RIGHT">Parameter names are case insensitive: you can use -name, or -Name or -NAME. You don't have to use the hyphen if you don't want to. After creating a CGI object, call the
use_named_parameters()
method with
a nonzero value. This will tell CGI.pm that you intend to use named
parameters exclusively:
$query = new CGI; $query->use_named_parameters(1); $field = $query->radio_group('name'=>'OS', 'values'=>['Unix','Windows','Macintosh'], 'default'=>'Unix');Actually, CGI.pm only looks for a hyphen in the first parameter. So you can leave it off subsequent parameters if you like. Something to be wary of is the potential that a string constant like "values" will collide with a keyword (and in fact it does!) While Perl usually figures out when you're referring to a function and when you're referring to a string, you probably should put quotation marks around all string constants just to play it safe.
print $query->header('image/gif');This prints out the required HTTP Content-type: header and the requisite blank line beneath it. If no parameter is specified, it will default to 'text/html'.
An extended form of this method allows you to specify a status code and a message to pass back to the browser:
print $query->header(-type=>'image/gif', -status=>'204 No Response');This presents the browser with a status code of 204 (No response). Properly-behaved browsers will take no action, simply remaining on the current page. (This is appropriate for a script that does some processing but doesn't need to display any results, or for a script called when a user clicks on an empty part of a clickable image map.)
Several other named parameters are recognized. Here's a contrived example that uses them all:
print $query->header(-type=>'image/gif', -status=>'402 Payment Required', -expires=>'+3d', -cookie=>$my_cookie, -Cost=>'$0.02');
+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 & dateWhen you use -expires, the script also generates a correct time stamp for the generated document to ensure that your clock and the browser's clock agree. This allows you to create documents that are reliably cached for short periods of time.
CGI::expires() is the static function call used internally that turns relative time intervals into HTTP dates. You can call it directly if you wish.
You will need to use this if:print $query->header(-nph=>1, -status=>'200 OK', -type=>'text/html');
Cost: $0.02You can use this to take advantage of new HTTP header fields without waiting for the next release of CGI.pm.
print $query->redirect('http://somewhere.else/in/the/world');This generates a redirection request for the remote browser. It will immediately go to the indicated URL. You should exit soon after this. Nothing else will be displayed.
You can add your own headers to this as in the header() method.
You should always use absolute or full URLs in redirection requests. Relative URLs will not work correctly.
An alternative syntax for redirect()
is:
The -nph parameter, if non-zero tells CGI.pm that this script is running as a no-parsed-header script. See Using NPH Scripts for more information. Table of contentsprint $query->redirect(-uri=>'http://somewhere.else/', -nph=>1);
named parameter style print $query->start_html(-title=>'Secrets of the Pyramids', -author=>'fred@capricorn.org', -base=>'true', -meta=>{'keywords'=>'pharoah secret mummy', 'copyright'=>'copyright 1996 King Tut'}, -style=>{'src'=>'/styles/style1.css'}, -BGCOLOR=>'blue'); old style print $query->start_html('Secrets of the Pyramids', 'fred@capricorn.org','true');This will return a canned HTML header and the opening <BODY> tag. All parameters are optional:
print $query->start_html(-title=>'Secrets of the Pyramids', -xbase=>'http://www.nile.eg/pyramid.html');
print $query->start_html(-title=>'Secrets of the Pyramids', -target=>'answer_frame');-target can be used with either -xbase or -base.
There is no support for the HTTP-EQUIV type of <META> tag. This is because you can modify the HTTP header directly with the header method. Example:<META NAME="keywords" CONTENT="pharoah secret mummy"> <META NAME="description" CONTENT="copyright 1996 King Tut">
print $q->header(-Refresh=>'10; URL=http://www.capricorn.com');
print $q->header(-head=>link({-rel=>'next', -href=>'http://www.capricorn.com/s2.html'}));or even
print $q->header(-head=>[ link({-rel=>'next', -href=>'http://www.capricorn.com/s2.html'}), link({-rel=>'previous', -href=>'http://www.capricorn.com/s1.html'}) ] );
$query = new CGI; print $query->header; $JSCRIPT=<<END; // Ask a silly question function riddle_me_this() { var r = prompt("What walks on four legs in the morning, " + "two legs in the afternoon, " + "and three legs in the evening?"); response(r); } // Get a silly answer function response(answer) { if (answer == "man") alert("Right you are!"); else alert("Wrong! Guess again."); } END print $query->start_html(-title=>'The Riddle of the Sphinx', -script=>$JSCRIPT);Netscape 3.0 allows you to place the JavaScript code in an external document and refer to it by URL. This allows you to keep the JavaScript code in a file or CGI script rather than cluttering up each page with the source. Netscape 3.0 and Internet Explorer also recognize a "language" parameter that allows you to use other languages, such as VBScript and PerlScript (yes indeed!) To use these attributes pass a HASH reference in the -script parameter containing one or more of the keys language, src, or code. Here's how to refer to an external script URL:
print $q->start_html(-title=>'The Riddle of the Sphinx', -script=>{-language=>'JavaScript', -src=>'/javascript/sphinx.js'} );Here's how to refer to scripting code incorporated directly into the page:
print $q->start_html(-title=>'The Riddle of the Sphinx', -script=>{-language=>'PerlScript', -code->'print "hello world!\n;"' );
print $query->start_html(-title=>'The Riddle of the Sphinx', -script=>$JSCRIPT, -onLoad=>'riddle_me_this()');See JavaScripting for more details.
print $query->end_htmlThis ends an HTML document by printing the </BODY> </HTML> tags.
print $query->hr;This prints out the text "<hr>".
print $query->em("What a silly art exhibit!");This prints out the text "<em>What a silly art exhibit!</em>".
You can pass as many text arguments as you like: they'll be concatenated together with spaces. This allows you to create nested tags easily:
print $query->h3("The",$query->em("silly"),"art exhibit");This creates the text:
<h3>The <em>silly</em> art exhibit</h3>
When used in conjunction with the import facility, the HTML shortcuts can make CGI scripts easier to read. For example:
use CGI ':standard'; print h1("Road Guide"), ol( li(a {href=>"start.html"},"The beginning"), li(a {href=>"middle.html"},"The middle"), li(a {href=>"end.html"},"The end") );
Most HTML tags are represented as lowercase function calls. There are a few exceptions:
tr()
. Use
TR() or Tr() instead.
param()
method. Use
PARAM() instead.
Select()
instead.
use CGI shortcuts; print a({href=>"bad_art.html"},"Jump to the silly exhibit");
General note 2. The default values that you specify for the forms are only used the first time the script is invoked. If there are already values present in the query string, they are used, even if blank.
If you want to change the value of a field from its previous value, you have two choices:
print $query->textfield(-name=>'favorite_color', -default=>'red', -override=>1);
General note 4. By popular demand, the text and labels that you
provide for form elements are escaped according to HTML rules. This means
that you can safely use "<CLICK ME>" as the label for a button. However,
this behavior may interfere with your ability to incorporate special HTML
character sequences, such as Á (Á) into your fields. If
you wish to turn off automatic escaping, call the autoEscape()
method with a false value immediately after creating the CGI object:
$query = new CGI; $query->autoEscape(undef);You can turn autoescaping back on at any time with
$query->autoEscape('yes')
print $query->isindex($action);isindex() without any arguments returns an <ISINDEX> tag that designates your script as the URL to call. If you want the browser to call a different URL to handle the search, pass isindex() the URL you want to be called.
print $query->startform($method,$action,$encoding); ...various form stuff... print $query->endform;startform() will return a <FORM> tag with the optional method, action and form encoding that you specify. endform() returns a </FORM> tag.
The form encoding is a new feature introduced in version 1.57 in order to support the "file upload" feature of Netscape 2.0. The form encoding tells the browser how to package up the contents of the form in order to transmit it across the Internet. There are two types of encoding that you can specify:
$CGI::URL_ENCODED
.
$CGI::MULTIPART
Forms that use this type of encoding are not easily interpreted by CGI scripts unless they use CGI.pm or another library that knows how to handle them. Unless you are using the file upload feature, there's no particular reason to use this type of encoding.
startform()
.
If you plan to make use of the JavaScript features
of Netscape 2.0, you can provide startform()
with the optional
-name
and/or -onSubmit
parameters. -name
has no effect on the display of the
form, but can be used to give the form an identifier so that it can
be manipulated by JavaScript functions. Provide the
-onSubmit
parameter in order to register some JavaScript code
to be performed just before the form is submitted. This is useful for
checking the validity of a form before submitting it.
Your JavaScript code should return a value of "true" to let Netscape
know that it can go ahead and submit the form, and "false" to abort
the submission.
Starting a Form that Uses the Netscape 2.0 "File Upload" Feature
print $query->start_multipart_form($method,$action,$encoding); ...various form stuff... print $query->endform;This has exactly the same usage as
startform()
, but
it specifies form encoding type multipart/form-data
as the default.
Named parameter style print $query->textfield(-name=>'field_name', -default=>'starting value', -size=>50, -maxlength=>80); Old style print $query->textfield('foo','starting value',50,80);textfield() will return a text input field.
When the form is processed, the value of the text field can be retrieved with:
$value = $query->param('foo');
JavaScripting: You can also provide
-onChange, -onFocus, -onBlur and
-onSelect parameters to register
JavaScript event handlers.
Creating A Big Text Field
Named parameter style print $query->textarea(-name=>'foo', -default=>'starting value', -rows=>10, -columns=>50); Old style print $query->textarea('foo','starting value',10,50);textarea() is just like textfield(), but it allows you to specify rows and columns for a multiline text entry box. You can provide a starting value for the field, which can be long and contain multiple lines.
JavaScripting: Like textfield(), you can provide -onChange, -onFocus,
-onBlur and -onSelect parameters to register
JavaScript event handlers.
Creating A Password Field
Named parameter style print $query->password_field(-name=>'secret', -value=>'starting value', -size=>50, -maxlength=>80); Old style print $query->password_field('secret','starting value',50,80);password_field() is identical to textfield(), except that its contents will be starred out on the web page.
Named parameters style print $query->filefield(-name=>'uploaded_file', -default=>'starting value', -size=>50, -maxlength=>80); Old style print $query->filefield('uploaded_file','starting value',50,80);filefield() will return a form field that prompts the user to upload a file.
In order to take full advantage of the file upload
facility you must use the new multipart
form encoding scheme. You can do this either
by calling startform()
and specify an encoding type of $CGI::MULTIPART
or by using the new start_multipart_form()
method. If you don't use multipart encoding, then you'll be
able to retreive the name of the file selected by the remote
user, but you won't be able to access its contents.
When the form is processed, you can retrieve the entered filename by calling param().
$filename = $query->param('uploaded_file');where "uploaded_file" is whatever you named the file upload field. Under Netscape 2.0beta1 the filename that gets returned is the full local filename on the remote user's machine. If the remote user is on a Unix machine, the filename will follow Unix conventions:
/path/to/the/fileOn an MS-DOS/Windows machine, the filename will follow DOS conventions:
C:\PATH\TO\THE\FILE.MSWOn a Macintosh machine, the filename will follow Mac conventions:
HD 40:Desktop Folder:Sort Through:RemindersNetscape 2.0beta2 changes this behavior and only returns the name of the file itself. Who knows what the behavior of the release browser will be?
The filename returned is also a file handle. You can read the contents of the file using standard Perl file reading calls:
# Read a text file and print it out while (<$filename>) { print; } # Copy a binary file to somewhere safe open (OUTFILE,">>/usr/local/web/users/feedback"); while ($bytesread=read($filename,$buffer,1024)) { print OUTFILE $buffer; } close $filename;You can have several file upload fields in the same form, and even give them the same name if you like (in the latter case
param()
will return a list of file names).
When processing an uploaded file, CGI.pm creates a temporary file on your hard disk and passes you a file handle to that file. After you are finished with the file handle, CGI.pm unlinks (deletes) the temporary file. If you need to you can access the temporary file directly. Its name is stored inside the CGI object's "private" data, and you can access it by passing the file name to the tmpFileName() method:
$filename = $query->param('uploaded_file'); $tmpfilename = $query->tmpFileName($filename);
The temporary file will be deleted automatically when your program exits unless you manually rename it. On some operating systems (such as Windows NT), you will need to close the temporary file's filehandle before your program exits. Otherwise the attempt to delete the temporary file will fail.
A potential problem with the temporary file upload feature is that the temporary file is accessible to any local user on the system. In previous versions of this module, the temporary file was world readable, meaning that anyone could peak at what was being uploaded. As of version 2.36, the modes on the temp file have been changed to read/write by owner only. Only the Web server and its CGI scripts can access the temp file. Unfortunately this means that one CGI script can spy on another! To make the temporary files really private, set the CGI global variable $CGI::PRIVATE_TEMPFILES to 1. Alternatively, call the built-in function CGI::private_tempfiles(1), or just use CGI qw/:private_tempfiles. The temp file will now be unlinked as soon as it is created, making it inaccessible to other users. The downside of this is that you will be unable to obtain the name of the temporary file using tmpFileName(). This function will return an empty string. Further, since PRIVATE_TEMPFILES is a global variable, its setting will affect all instances of CGI.pm if you are running mod_perl. You can work around this limitation by declaring $CGI::PRIVATE_TEMPFILES as a local at the top of your script.
Usually the browser sends along some header information along with the text of the file itself. Currently the headers contain only the original file name and the MIME content type (if known). Future browsers might send other information as well (such as modification date and size). To retrieve this information, call uploadInfo(). It returns a reference to an associative array containing all the document headers. For example, this code fragment retrieves the MIME type of the uploaded file (be careful to use the proper capitalization for "Content-Type"!):
$filename = $query->param('uploaded_file'); $type = $query->uploadInfo($filename)->{'Content-Type'}; unless ($type eq 'text/html') { die "HTML FILES ONLY!"; }
JavaScripting: Like textfield(), filefield()
accepts -onChange, -onFocus, -onBlur and
-onSelect parameters to register
JavaScript event handlers.
Caveats and potential problems in
the file upload feature.
Creating A Popup Menu
Named parameter style print $query->popup_menu(-name=>'menu_name', -values=>['eenie','meenie','minie'], -default=>'meenie', -labels=>{'eenie'=>'one','meenie'=>'two', 'minie'=>'three'}); Old style print $query->popup_menu('menu_name', ['eenie','meenie','minie'],'meenie', {'eenie'=>'one','meenie'=>'two','minie'=>'three'});popup_menu() creates a menu.
$popup_menu_value = $query->param('menu_name');JavaScripting: You can provide
-onChange,
-onFocus, and -onBlur
parameters to register JavaScript event
handlers.
Named parameter style print $query->scrolling_list(-name=>'list_name', -values=>['eenie','meenie','minie','moe'], -default=>['eenie','moe'], -size=>5, -multiple=>'true', -labels=>\%labels); Old style print $query->scrolling_list('list_name', ['eenie','meenie','minie','moe'], ['eenie','moe'],5,'true', \%labels);scrolling_list() creates a scrolling list.
%labels
has already been created.
@selected = $query->param('list_name');JavaScripting: You can provide -onChange, -onFocus, and -onBlur parameters to register JavaScript event handlers.
Named parameter style print $query->checkbox_group(-name=>'group_name', -values=>['eenie','meenie','minie','moe'], -default=>['eenie','moe'], -linebreak=>'true', -labels=>\%labels); Old Style print $query->checkbox_group('group_name', ['eenie','meenie','minie','moe'], ['eenie','moe'],'true',\%labels); HTML3 Browsers Only print $query->checkbox_group(-name=>'group_name', -values=>['eenie','meenie','minie','moe'], -rows=>2,-columns=>2);checkbox_group() creates a list of checkboxes that are related by the same name.
%labels
has previously been created.
To include row and column headings in the returned table, you can use the -rowheaders and -colheaders parameters. Both of these accept a pointer to an array of headings to use. The headings are just decorative. They don't reorganize the interpetation of the checkboxes -- they're still a single named unit.
When viewed with browsers that don't understand HTML3 tables, the -rows and -columns parameters will leave you with a group of buttons that may be awkwardly formatted but still useable. However, if you add row and/or column headings, the resulting text will be very hard to read.
@turned_on = $query->param('group_name');This function actually returns an array of button elements. You can capture the array and do interesting things with it, such as incorporating it into your own tables or lists. The -nolabels option is also useful in this regard:
@h = $query->checkbox_group(-name=>'choice', -value=>['fee','fie','foe'], -nolabels=>1); create_nice_table(@h);JavaScripting: You can provide an -onClick parameter to register some JavaScript code to be performed every time the user clicks on any of the buttons in the group.
Named parameter list print $query->checkbox(-name=>'checkbox_name', -checked=>'checked', -value=>'TURNED ON', -label=>'Turn me on'); Old style print $query->checkbox('checkbox_name',1,'TURNED ON','Turn me on');checkbox() is used to create an isolated checkbox that isn't logically related to any others.
$turned_on = $query->param('checkbox_name');JavaScripting: You can provide an
-onClick
parameter to register some JavaScript
code to be performed every time the user clicks on the button.
Named parameter style print $query->radio_group(-name=>'group_name', -values=>['eenie','meenie','minie'], -default=>'meenie', -linebreak=>'true', -labels=>\%labels); Old style print $query->radio_group('group_name',['eenie','meenie','minie'], 'meenie','true',\%labels); HTML3-compatible browsers only print $query->radio_group(-name=>'group_name', -values=>['eenie','meenie','minie','moe'], -rows=2,-columns=>2);radio_group() creates a set of logically-related radio buttons. Turning one member of the group on turns the others off.
\@foo
.
%labels
has already been defined.
To include row and column headings in the returned table, you can use the -rowheader and -colheader parameters. Both of these accept a pointer to an array of headings to use. The headings are just decorative. They don't reorganize the interpetation of the radio buttons -- they're still a single named unit.
When viewed with browsers that don't understand HTML3 tables, the -rows and -columns parameters will leave you with a group of buttons that may be awkwardly formatted but still useable. However, if you add row and/or column headings, the resulting text will be very hard to read.
$which_radio_button = $query->param('group_name');This function actually returns an array of button elements. You can capture the array and do interesting things with it, such as incorporating it into your own tables or lists The -nolabels option is useful in this regard.:
@h = $query->radio_group(-name=>'choice', -value=>['fee','fie','foe'], -nolabels=>1); create_nice_table(@h);
JavaScripting: You can provide an -onClick
parameter to register some JavaScript
code to be performed every time the user clicks on any of the buttons
in the group.
Creating A Submit Button
Named parameter style print $query->submit(-name=>'button_name', -value=>'value'); Old style print $query->submit('button_name','value');submit() will create the query submission button. Every form should have one of these.
You can figure out which of several buttons was pressed by using different values for each one:
$which_one = $query->param('button_name');
-name
and -value
changes the user-visible
label on the button.
print $query->resetreset() creates the "reset" button. It undoes whatever changes the user has recently made to the form, but does not necessarily reset the form all the way to the defaults. See defaults() for that. It takes the optional label for the button ("Reset" by default). JavaScripting: You can provide an -onClick parameter to register some JavaScript code to be performed every time the user clicks on the button.
print $query->defaults('button_label')defaults() creates "reset to defaults" button. It takes the optional label for the button ("Defaults" by default). When the user presses this button, the form will automagically be cleared entirely and set to the defaults you specify in your script, just as it was the first time it was called.
Named parameter style print $query->hidden(-name=>'hidden_name', -default=>['value1','value2'...]); Old style print $query->hidden('hidden_name','value1','value2'...);hidden() produces a text field that can't be seen by the user. It is useful for passing state variable information from one invocation of the script to the next.
Hidden fields used to behave differently from all other fields: the provided default values always overrode the "sticky" values. This was the behavior people seemed to expect, however it turns out to make it harder to write state-maintaining forms such as shopping cart programs. Therefore I have made the behavior consistent with other fields.
Just like all the other form elements, the value of a hidden field is "sticky". If you want to replace a hidden field with some other values after the script has been called once you'll have to do it manually before writing out the form element:
$query->param('hidden_name','new','values','here'); print $query->hidden('hidden_name');Fetch the value of a hidden field this way:
$hidden_value = $query->param('hidden_name'); -or (for values created with arrays)- @hidden_values = $query->param('hidden_name');
Named parameter style print $query->image_button(-name=>'button_name', -src=>'/images/NYNY.gif', -align=>'MIDDLE'); Old style print $query->image_button('button_name','/source/URL','MIDDLE');image_button() produces an inline image that acts as a submission button. When selected, the form is submitted and the clicked (x,y) coordinates are submitted as well.
$x = $query->param('button_name.x'); $y = $query->param('button_name.y');JavaScripting: You can provide an
-onClick
parameter to register some JavaScript
code to be performed every time the user clicks on the button.
Named parameter style print $query->button(-name=>'button1', -value=>'Click Me', -onClick=>'doButton(this)'); Old style print $query->image_button('button1','Click Me','doButton(this)');button() creates a JavaScript button. When the button is pressed, the JavaScript code pointed to by the
-onClick
parameter
is executed. This only works with Netscape 2.0 and higher. Other browsers
do not recognize JavaScript and probably won't even display the button.
autoEscape()
.
Use
$query->autoEscape(undef);to turn automatic HTML escaping off, and
$query->autoEscape('true');to turn it back on.
This imports the standard methods into your namespace. Now instead of getting parameters like this:use CGI qw(:standard);
You can do it like this:use CGI; $dinner = $query->param('entree');
Similarly, instead of creating a form like this:use CGI qw(:standard); $dinner = param('entree');
You can create it like this:print $query->start_form, "Check here if you're happy: ", $query->checkbox(-name=>'happy',-value=>'Y',-checked=>1), "<P>", $query->submit, $query->end_form;
Even though there's no CGI object in view in the second example, state is maintained using an implicit CGI object that's created automatically. The form elements created this way are sticky, just as before. If you need to get at the implicit CGI object directly, you can refer to it as:print start_form, "Check here if you're happy: ", checkbox(-name=>'happy',-value=>'Y',-checked=>1), p, submit, end_form;
$CGI::Q;
The use CGI statement is used to import method names into the current name space. There is a slight overhead for each name you import, but ordinarily is nothing to worry about. You can import selected method names like this:
Ordinarily, however, you'll want to import groups of methods using export tags. Export tags refer to sets of logically related methods which are imported as a group with use. Tags are distinguished from ordinary methods by beginning with a ":" character. This example imports the methods dealing with the CGI protocol (use CGI qw(header start_html end_html);
param()
and the like) as well as shortcuts that generate
HTML2-compliant tags:
Currently there are 8 method families defined in CGI.pm. They are:use CGI qw(:cgi :html2);
Since using any causes any mistyped method name to be interpreted as an HTML tag, use it with care or not at all.use CGI qw(:any :all); $q=new CGI; print $q->gradient({speed=>'fast',start=>'red',end=>'blue'});
my_script.pl keyword1 keyword2 keyword3or this:
my_script.pl keyword1+keyword2+keyword3or this:
my_script.pl name1=value1 name2=value2or this:
my_script.pl name1=value1&name2=value2or even by sending newline-delimited parameters to standard input:
% my_script.pl first_name=fred last_name=flintstone occupation='granite miner' ^D
When debugging, you can use quotation marks and the backslash character to escape spaces and other funny characters in exactly the way you would in the shell (which isn't surprising since CGI.pm uses "shellwords.pl" internally). This lets you do this sort of thing:
my_script.pl "'name 1'='I am a long value'" "'name 2'=two\ words"Table of contents
print $query->dumpProduces something that looks like this:
<UL> <LI>name1 <UL> <LI>value1 <LI>value2 </UL> <LI>name2 <UL> <LI>value1 </UL> </UL>You can achieve the same effect by incorporating the CGI object directly into a string, as in:
print "<H2>Current Contents:</H2>\n$query\n";
$query->accept('text/html')
, it will return a
floating point value corresponding to the browser's
preference for this type from 0.0 (don't want) to 1.0.
Glob types (e.g. text/*) in the browser's accept list
are handled correctly.
/cgi-bin/your_script/additional/stuff
will
result in $query->path_info()
returning
"/additional/stuff"
"/usr/local/etc/httpd/htdocs/additional/stuff"
.
GET, POST,
or HEAD
.
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:
$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:
$cookie=$query->cookie(-name=>'family information', -value=>\%childrens_ages);
"+1h" one hour from now
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!To retrieve the names of all cookies passed to your script, call cookie() without any parameters. This allows you to iterate through all cookies:
foreach $name ($query->cookie()) { print $query->cookie($name); }
The cookie and CGI namespaces are separate. If you have a parameter named 'answers' and a cookie named 'answers', the values retrieved by param() and cookie() are independent of each other. However, it's simple to turn a CGI parameter into a cookie, and vice-versa:
# turn a CGI parameter into a cookie $c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]); # vice-versa $q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
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.
-target
argument in the header method. For example,
the following code will pop up a new Netscape window and display the script's
output:
$query = new CGI; print $query->header(-target=>'_blank');
-target
parameter. When the form is submitted, the output
will be redirected to the indicated frame:
print $query->start_form(-target=>'result_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.
You'll need to know JavaScript in order to use it. The Netscape JavaScript manual contains a good tutorial and reference guide to the JavaScript programming language.
The usual way to use JavaScript is to define a set of functions in a <SCRIPT> block inside the HTML header and then to register event handlers in the various elements of the page. Events include such things as the mouse passing over a form element, a button being clicked, the contents of a text field changing, or a form being submitted. When an event occurs that involves an element that has registered an event handler, its associated JavaScript code gets called.
The elements that can register event handlers include the <BODY> of an HTML document, hypertext links, all the various elements of a fill-out form, and the form itself. There are a large number of events, and each applies only to the elements for which it is relevant:
validateAge()
JavaScript code executed every time the
textfield named "age" changes, generate the field like this:
print $q->textfield(-name=>'age',-onChange=>"validateAge(this)");This example assumes that you've already declared the
validateAge()
function by incorporating it into
a <SCRIPT> block. The CGI.pm
start_html() method provides a convenient way
to create this section.
Similarly, you can create a form that checks itself over for consistency and alerts the user if some essential value is missing by creating it this way:
print $q->startform(-onSubmit=>"validateMe(this)");See the javascript.cgi script for a demonstration of how this all works.
To refer to a style within the body of your document, add the -class parameter to any HTML element:
Or define styles on the fly with the -style parameter:print h1({-class=>'Fancy'},'Welcome to the Party');
You may also use the new span() element to apply a style to a section of text:print h1({-style=>'Color: red;'},'Welcome to Hell');
Note that you must import the ":html3" definitions to get the span() and style() methods.print span({-style=>'Color: red;'}, h1('Welcome to Hell'), "Where did that handbasket get to?" );
You won't be able to do much with this unless you understand the CSS specification. A more intuitive subclassable library for cascading style sheets in Perl is in the works, but until then, please read the CSS specification at http://www.w3.org/pub/WWW/Style/ to find out how to use these features. Here's a final example to get you started.
use CGI qw/:standard :html3/; #here's a stylesheet incorporated directly into the page $newStyle=<<END; >!-- P.Tip { margin-right: 50pt; margin-left: 50pt; color: red; } P.Alert { font-size: 30pt; font-family: sans-serif; color: red; } --> END print header(); print start_html( -title=>'CGI with Style', -style=>{-src=>'http://www.capricorn.com/style/st1.css', -code=>$newStyle} ); print h1('CGI with Style'), p({-class=>'Tip'}, "Better read the cascading style sheet spec before playing with this!" ), span({-style=>'color: magenta'},"Look Mom, no hands!", p(), "Whooo wee!" ); print end_html;
Servers use a variety of conventions for designating CGI scripts as NPH. Many Unix servers look at the beginning of the script's name for the prefix "nph-". The Macintosh WebSTAR server and Microsoft's Internet Information Server, in contrast, try to decide whether a program is an NPH script by examining the first line of script output.
CGI.pm supports NPH scripts with a special NPH mode. When in this
mode, CGI.pm will output the necessary extra header information when
the header()
and redirect()
methods are
called.
Important: If you use the Microsoft Internet Information Server, you must designate your script as an NPH script. Otherwise many of CGI.pm's features, such as redirection and the ability to output non-HTML files, will fail.
There are a number of ways to put CGI.pm into NPH mode:
use CGI qw(:standard :nph)
CGI->nph(1)
print $q->header(-nph=>1);
#!/usr/local/bin/perl use CGI; $query = new CGI; print $query->header; print $query->start_html("Save and Restore Example"); print "<H1>Save and Restore Example</H1>\n"; # Here's where we take action on the previous request &save_parameters($query) if $query->param('action') eq 'save'; $query = &restore_parameters($query) if $query->param('action') eq 'restore'; # Here's where we create the form print $query->startform; print "Popup 1: ",$query->popup_menu('popup1',['eenie','meenie','minie']),"\n"; print "Popup 2: ",$query->popup_menu('popup2',['et','lux','perpetua']),"\n"; print "<P>"; print "Save/restore state from file: ",$query->textfield('savefile','state.sav'),"\n"; print "<P>"; print $query->submit('action','save'),$query->submit('action','restore'); print $query->submit('action','usual query'); print $query->endform; # Here we print out a bit at the end print $query->end_html; sub save_parameters { local($query) = @_; local($filename) = &clean_name($query->param('savefile')); if (open(FILE,">$filename")) { $query->save(FILE); close FILE; print "<STRONG>State has been saved to file $filename</STRONG>\n"; } else { print "<STRONG>Error:</STRONG> couldn't write to file $filename: $!\n"; } } sub restore_parameters { local($query) = @_; local($filename) = &clean_name($query->param('savefile')); if (open(FILE,$filename)) { $query = new CGI(FILE); # Throw out the old query, replace it with a new one close FILE; print "<STRONG>State has been restored from file $filename</STRONG>\n"; } else { print "<STRONG>Error:</STRONG> couldn't restore file $filename: $!\n"; } return $query; } # Very important subroutine -- get rid of all the naughty # metacharacters from the file name. If there are, we # complain bitterly and die. sub clean_name { local($name) = @_; unless ($name=~/^[\w\._-]+$/) { print "<STRONG>$name has naughty characters. Only "; print "alphanumerics are allowed. You can't use absolute names.</STRONG>"; die "Attempt to use naughty characters"; } return $name; }If you use the CGI save() and restore() methods a lot, you might be interested in the Whitehead Genome Center's Boulderio file format. It's a way of transferring semi-strucured data from the standard output of one program to the standard input of the next. It comes with a simple Perl database that allows you to store and retrieve records from a DBM or DB_File database, and is compatible with the format used by save() and restore(). You can get more information on Boulderio from:
http://www.genome.wi.mit.edu/genome_software/other/boulder.html
Many people have experienced problems with internal links on pages that have forms. Jumping around within the document causes the state of the form to be reset. A partial solution is to use the self_url() method to generate a link that preserves state information. This script illustrates how this works.
#!/usr/local/bin/perl use CGI; $query = new CGI; # We generate a regular HTML file containing a very long list # and a popup menu that does nothing except to show that we # don't lose the state information. print $query->header; print $query->start_html("Internal Links Example"); print "<H1>Internal Links Example</H1>\n"; print "<A NAME=\"start\"></A>\n"; # an anchor point at the top # pick a default starting value; $query->param('amenu','FOO1') unless $query->param('amenu'); print $query->startform; print $query->popup_menu('amenu',[('FOO1'..'FOO9')]); print $query->submit,$query->endform; # We create a long boring list for the purposes of illustration. $myself = $query->self_url; print "<OL>\n"; for (1..100) { print qq{<LI>List item #$_<A HREF="$myself#start">Jump to top</A>\n}; } print "</OL>\n"; print $query->end_html;
There is, however, a problem with maintaining the states of multiple forms. Because the browser only sends your script the parameters from the form in which the submit button was pressed, the state of all the other forms will be lost. One way to get around this, suggested in this example, is to use hidden fields to pass as much information as possible regardless of which form the user submits.
#!/usr/local/bin/perl use CGI; $query=new CGI; print $query->header; print $query->start_html('Multiple forms'); print "<H1>Multiple forms</H1>\n"; # form 1 print "<HR>\n"; print $query->startform; print $query->textfield('text1'),$query->submit('submit1'); print $query->hidden('text2'); # pass information from the other form print $query->endform; print "<HR>\n"; # form 2 print $query->startform; print $query->textfield('text2'),$query->submit('submit2'); print $query->hidden('text1'); # pass information from the other form print $query->endform; print "<HR>\n"; print $query->end_html;
FastCGI modules are available for the Apache and NCSA servers as well as for OpenMarket's own server. In order to use FastCGI with Perl you have to run a specially-modified version of the Perl interpreter. Precompiled Binaries and a patch kit are all available on OpenMarket's FastCGI web site.
To use FastCGI with CGI.pm, change your scripts as follows:
#!/usr/local/bin/perl use CGI qw(:standard); print header, start_html("CGI Script"), h1("CGI Script"), "Not much to see here", hr, address(a({href=>'/'},"home page"), end_html;
That's all there is to it. The param() method, form-generation, HTML shortcuts, etc., all work the way you expect.#!/usr/local/fcgi/bin/perl use Fast::CGI qw(:standard); # Do time-consuming initialization up here. while (new CGI::Fast) { print header, start_html("CGI Script"), h1("CGI Script"), "Not much to see here", hr, address(a({href=>'/'},"home page"), end_html; }
If you use Perl 5.003_93 or higher, your scripts should also run unmodified even if you didn't compile with sfio, because mod_perl takes advantage of the tied filehandle interface present in that version of Perl. However this has not been tested (I'm too lazy to have two versions of the Perl libraries installed). If you find that this does not work as advertised, just use the CGI::Apache module as shown below. This has been tested:
#!/usr/local/bin/perl use CGI qw(:standard); print header, start_html("CGI Script"), h1("CGI Script"), "Not much to see here", hr, address(a({href=>'/'},"home page"), end_html;
Important configuration note: When using CGI.pm with mod_perl be careful not to enable either the PerlSendHeader or PerlSetupEnv directives. This is handled automatically by CGI.pm and by Apache::Registry.#!/usr/bin/perl use CGI::Apache qw(:standard); print header, start_html("CGI Script"), h1("CGI Script"), "Not much to see here", hr, address(a({href=>'/'},"home page"), end_html; }
Users of CGI::Switch can continue to use it to create scripts that can run under each of normal CGI, mod_perl CGI or the command line. Unfortunately the "simple" interface to the CGI.pm functions does not work with CGI::Switch. You'll have to use the object-oriented versions (or use the sfio version of Perl!)
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:
require "cgi-lib.pl"; ReadParse(); print "The price of your purchase is $in{price}.\n";
use CGI qw(:cgi-lib); ReadParse(); print "The price of your purchase is $in{price}.\n";Like cgi-lib's ReadParse, pass a variable glob in order to use a different variable than the default "%in":
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:
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. In addition, the extended version of
ReadParse() that allows you to spool uploaded files to disk is not
available. You are strongly encouraged to use CGI.pm's file upload
interface instead.
See cgi-lib_porting.html for more details on porting cgi-lib.pl scripts to CGI.pm.
Known problems include:
I haven't found a way to determine the correct caller in this situation. I might add a readFile() method to CGI if this problem bothers enough people.$file = $query->param('file to upload'); $file = "main::$file"; ...
/usr/tmp
or the /tmp
directory. These temporary files
have names like CGItemp125421
, and should be
deleted automatically.
first_name=Fred last_name=Flintstone city=BedrockEnd the list by typing a control-D (or control-Z on DOS/Windows systems).
If you want to run a CGI script from a script or batch file, and don't want this behavior, just pass it an empty parameter list like this:
my_script.pl ''This will work too on Unix systems:
my_script.pl </dev/null
CGITemp123456
in a temporary
directory. To find a suitable directory it first looks
for /usr/tmp
and then for /tmp
.
If it can't find either of these directories, it tries
for the current directory, which is usually the same
directory that the script resides in.
If you're on a non-Unix system you may need to modify CGI.pm to point at a suitable temporary directory. This directory must be writable by the user ID under which the server runs (usually "nobody") and must have sufficient capacity to handle large file uploads. Open up CGI.pm, and find the line:
package TempFile; foreach ('/usr/tmp','/tmp') { do {$TMPDIRECTORY = $_; last} if -w $_; }Modify the foreach() line to contain a series of one or more directories to store temporary files in.
\temp
, taking up space.A workaround for this is to use additional path information to trick Netscape into thinking that the form and the response have different URLs. I recommend giving each form a sequence number and bumping the sequence up by one each time the form is accessed:
my($s) = $query->path_info=~/(\d+)/; # get sequence $s++; #bump it up # Trick Netscape into thinking it's loading a new script: print $q->start_multipart_form(-action=>$q->script_name . '/$s');
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. During load, it will attempt to guess the correct operating system using the Config module. Currently it guesses correctly; however if the operating system names change it may not work right. The main symptom will be that file upload does not work correctly. If this happens, find the place at the top of the script where the OS is defined, and uncomment the correct definition:
# CHANGE THIS VARIABLE FOR YOUR OPERATING SYSTEM # $OS = 'UNIX'; # $OS = 'MACINTOSH'; # $OS = 'WINDOWS'; # $OS = 'VMS';Other notes follow:
.pl
suffix
with perl5 using the NT file manager (Website, Purveyor), or install
the Perl DLL library (IIS). The home site for the NT port of Perl is:
http://www.perl.hip.com/
The Microsoft IIS server is seriously broken with respect to the handling of additional path information. If you use the DLL version of Perl, IIS will attempt to execute the additional path information as a script. If you use the normal version of Perl, the additional path information will contain incorrect information. This is not a bug in CGI.pm.
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 find that binary files get slightly larger when uploaded but that text files remain the same, then binary made is not correctly activated. Be sure to set the $OS variable to 'NT' or 'WINDOWS'. If you continue to have problems, make sure you're calling binmode() on the filehandle that you use to write the uploaded file to disk.
Known incompatibilities between CGI.pm and MacPerl include:ftp://err.ethz.ch/pub/neeri/MacPerl/
The CGI::* modules are being reworked to be interoperable with the excellent LWP modules. Stay tuned.
The current version of CGI.pm can be found at:
http://www-genome.wi.mit.edu/ftp/pub/software/WWW/
You are encouraged to look at these other Web-related modules:
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
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
user_name()
and remote_user()
methods.
autoEscape()
method.
Last modified: Fri May 9 11:16:24 EDT 1997