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 end_html;Select this link to try the script
The current version of the software can always be downloaded from the master copy of this document maintained at http://stein.cshl.org/WWW/software/CGI/.
This package requires perl 5.004 or higher. Earlier versions of Perl may work, but CGI.pm has not been tested with them. If you're really stuck, edit the source code to remove the line that says "require 5.004", but don't be surprised if you run into problems.
If you are using a Unix system, 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:
> cd CGI.pm-2.73 > copy CGI.pm C:\Perl\lib > mkdir C:\Perl\lib\CGI > copy CGI\*.pm C:\Perl\lib\CGIModify this recipe if your Perl library has a different location.
For Macintosh users, just drag the file named CGI.pm into the folder where your other Perl .pm files are stored. Also drag the subfolder named "CGI".
If you do not have sufficient privileges to install into /usr/local/lib/perl5, you can still use CGI.pm. Modify the installation recipe as follows:
% perl Makefile.PL INSTALLDIRS=site INSTALLSITELIB=/home/your/private/dir % make % make installReplace /home/your/private/dir with the full path to the directory you want the library placed in. Now preface your CGI scripts with a preamble something like the following:
Be sure to replace /home/your/private/dir with the true location of CGI.pm.use lib '/home/your/private/dir'; use CGI;
Notes on using CGI.pm in NT and other non-Unix platforms
The use operator loads the CGI.pm definitions and imports the ":standard" set of function definitions. We then make calls to various functions such as header(), to generate the HTTP header, start_html(), to produce the top part of an HTML document, h1() to produce a level one header, and so forth.#!/usr/local/bin/perl use CGI qw/:standard/; print header(), start_html(-title=>'Wow!'), h1('Wow!'), 'Look Ma, no hands!', end_html();
In addition to the standard set, there are many optional sets of less frequently used CGI functions. See Importing CGI Methods for full details.
In the object-oriented mode, you use CGI; without specifying any functions or function sets to import. In this case, you communicate with CGI.pm via a CGI object. The object is created by a call to CGI::new() and encapsulates all the state information about the current CGI transaction, such as values of the CGI parameters passed to your script. Although more verbose, this coding style has the advantage of allowing you to create multiple CGI objects, save their state to disk or to a database, and otherwise manipulate them to achieve neat effects.
The same script written using the object-oriented style looks like this:
The object-oriented mode also has the advantage of consuming somewhat less memory than the function-oriented coding style. This may be of value to users of persistent Perl interpreters such as mod_perl.#!/usr/local/bin/perl use CGI; $q = new CGI; print $q->header(), $q->start_html(-title=>'Wow!'), $q->h1('Wow!'), 'Look Ma, no hands!', $q->end_html();
Many of the code examples below show the object-oriented coding style. Mentally translate them into the function-oriented style if you prefer.
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.in") || 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);
If you are using the function-oriented interface and want to initialize CGI state from a file handle, the way to do this is with restore_parameters(). This will (re)initialize the default CGI object from the indicated file handle.
open (IN,"test.in") || die; restore_parameters(IN); close IN;
You can initialize a CGI object from an associative-array reference. Values can be either single- or multivalued:
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/]});
Or you can clone a CGI object from an existing one. The parameter lists of the clone will be identical, but other fields, such as autoescaping, are not:$query = new CGI('dinosaur=barney&color=purple');
$old_query = new CGI; $new_query = new CGI($old_query);
This form also allows you to create a CGI object that is initially empty:
$empty_query = new CGI('');
If you are using mod_perl, you can initialize a CGI object at any stage of the request by passing the request object to CGI->new:
$q = CGI->new($r);
To do this with the function-oriented interface, set Apache->request($r) before calling the first CGI function.
Finally, you can pass code reference to new() in order to install an upload_hook function that will be called regularly while a long file is being uploaded. See Creating a File Upload Field for details.
See advanced techniques for more information.
@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 compatibility if the script was invoked as an <ISINDEX> script and contains a string without ampersands (e.g. "value1+value2+value3") , there will be a single parameter named "keywords" containing the "+"-delimited 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.
If a value is not given in the query string, as in the queries "name1=&name2=" or "name1&name2", it will be returned as an empty string (not undef). This feature is new in 2.63, and was introduced to avoid multiple "undefined value" warnings when running with the -w switch.
If the parameter does not exist at all, then param() will return undef in a scalar context, and the empty list in a list context.
$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.
$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.
If POSTed data is not of type application/x-www-form-urlencoded or multipart/form-data, then the POSTed data will not be processed, but instead be returned as-is in a parameter named POSTDATA. To retrieve it, use code like this:
my $data = $query->param('POSTDATA');(If you don't know what the preceding means, don't worry about it. It only affects people trying to use CGI for XML processing and other specialized tasks.)
$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".
An optional second argument to import_names, if present and non-zero, will delete the contents of the namespace before loading it. This may be useful for environments like mod_perl in which the script does not exit after processing a request.
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: Variable names are transformed as necessary into legal Perl variable names. All non-legal characters are transformed into underscores. If you need to keep the original names, you should use the param() method instead to access CGI variables by name.
If you need access to the parameter list in a way that isn't covered by the methods above, you can obtain a direct reference to it by calling the param_fetch() method with the name of the parameter you want. This will return an array reference to the named parameters, which you then can manipulate in any way you like.$q->param_fetch('address')->[1] = '1313 Mockingbird Lane'; unshift @{$q->param_fetch(-name=>'address')},'George Munster';
You may call param_fetch() with the name of the CGI parameter, or with the -name argument, which has the same meaning as elsewhere.
$params = $q->Vars; print $params->{'address'}; @foo = split("\0",$params->{'foo'}); %params = $q->Vars; use CGI ':cgi-lib'; $params = Vars;
Many people want to fetch the entire parameter list as a hash in which the keys are the names of the CGI parameters, and the values are the parameters' values. The Vars() method does this. Called in a scalar context, it returns the parameter list as a tied hash reference. Changing a key changes the value of the parameter in the underlying CGI parameter list. Called in an list context, it returns the parameter list as an ordinary hash. This allows you to read the contents of the parameter list, but not to change it.
When using this, the thing you must watch out for are multivalued CGI parameters. Because a hash cannot distinguish between scalar and list context, multivalued parameters will be returned as a packed string, separated by the "\0" (null) character. You must split this packed string in order to get at the individual values. This is the convention introduced long ago by Steve Brenner in his cgi-lib.pl module for Perl version 4.
If you wish to use Vars() as a function, import the :cgi-lib set of function calls (also see the section on CGI-LIB compatibility).
Errors can occur while processing user input, particularly when processing uploaded files. When these errors occur, CGI will stop processing and return an empty parameter list. You can test for the existence and nature of errors using the cgi_error() function. The error messages are formatted as HTTP status codes. You can either incorporate the error text into an HTML page, or use it as the value of the HTTP status:
my $error = $q->cgi_error; if ($error) { print $q->header(-status=>$error), $q->start_html('Problems'), $q->h2('Request not processed'), $q->strong($error); exit 0; }
When using the function-oriented interface (see the next section), errors may only occur the first time you call param(). Be prepared for this! Table of contents
$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.
If you wish to use this method from the function-oriented (non-OO) interface, the exported name for this method is save_parameters(). 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->url
$full_url = $query->url(); $full_url = $query->url(-full=>1); #alternative syntax $relative_url = $query->url(-relative=>1); $absolute_url = $query->url(-absolute=>1); $url_with_path = $query->url(-path_info=>1); $url_with_path_and_query = $query->url(-path_info=>1,-query=>1);
url()
returns the script's URL in a variety of formats.
Called without any arguments, it returns the full form of the URL,
including host name and port number
http://your.host.com/path/to/script.cgiYou can modify this format with the following named arguments:
/path/to/script.cgi
script.cgi
$color = $query->url_param('color');It is possible for a script to receive CGI parameters in the URL as well as in the fill-out form by creating a form that POSTs to a URL containing a query string (a "?" mark followed by arguments). The param() method will always return the contents of the POSTed fill-out form, ignoring the URL's query string. To retrieve URL parameters, call the url_param() method. Use it in the same way as param(). The main difference is that it allows you to read the parameters, but not set them.
Under no circumstances will the contents of the URL query string interfere with similarly-named CGI parameters in POSTed forms. If you try to mix a URL query string with a form submitted with the GET method, the results will not be what you expect.
$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, it 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. 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.
HTML/HTTP parameters that contain internal hyphens, such as -Content-language can be passed by putting quotes around them, or by using an underscore for the second hyphen, e.g. -Content_language.
The fact that you must use curly {} braces around the attributes passed to functions that create simple HTML tags but don't use them around the arguments passed to all other functions has many people, including myself, confused. As of 2.37b7, the syntax is extended to allow you to use curly braces for all function calls:
$field = $query->radio_group({-name=>'OS', -values=>[Unix,Windows,Macintosh], -default=>'Unix'});Table of contents
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, -charset=>'UTF-7', -attachment=>'foo.gif', -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 Thu, 25-Apr-1999 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');
In either case, the outgoing header will be formatted as:print header(-p3p=>[qw(CAO DSP LAW CURa)]); print header(-p3p=>'CAO DSP LAW CURa');
P3P: policyref="/w3c/p3p.xml" cp="CAO DSP LAW CURa"
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 full URLs (including the http: or ftp: part) in redirection requests. Relative URLs will not work correctly.
An alternative syntax for redirect()
is:
The -location parameter gives the destination URL. You may also use -uri or -url if you prefer.print $query->redirect(-location=>'http://somewhere.else/', -nph=>1, -status=>301);
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.
The -status parameter will set the status of the redirect. HTTP defines three different possible redirection status codes:
301 Moved Permanently 302 Found 303 See Other
The default if not specified is 302, which means "moved temporarily." You may change the status to another status code if you wish. Be advised that changing the status to anything other than 301, 302 or 303 will probably break redirection.
The -method parameter tells the browser what method to use for redirection. This is handy if, for example, your script was called from a fill-out form POST operation, but you want to redirect the browser to a static page that requires a GET.
All other parameters recognized by the header() method are also valid in redirect. Table of contents
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'}, -dtd=>1, -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.
To create an HTTP-EQUIV tag, use the -head argument as described below.<META NAME="keywords" CONTENT="pharoah secret mummy"> <META NAME="description" CONTENT="copyright 1996 King Tut">
To leave off the lang attribute, as you must do if you want to generate legal HTML 3.2 or earlier, pass the empty string (-lang=>'').print $q->start_html(-lang=>'fr-CA');
-dtd=>'-//W3C//DTD HTML 3.2//EN'
print start_html(-head=>Link({-rel=>'next', -href=>'http://www.capricorn.com/s2.html'}));or even
print start_html(-head=>[ Link({-rel=>'next', -href=>'http://www.capricorn.com/s2.html'}), Link({-rel=>'previous', -href=>'http://www.capricorn.com/s1.html'}) ] );To create an HTTP-EQUIV tag, use something like this:
print start_html(-head=>meta({-http_equiv=>'Content-Type', -content=>'text/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 and higher 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.X-4.X and Internet Explorer 3.X-4.X 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;"'} );A final feature allows you to incorporate multiple <SCRIPT> sections into the header. Just pass the list of script sections as an array reference. This allows you to specify different source files for different dialects of JavaScript. Example:
print $q->start_html(-title=>'The Riddle of the Sphinx', -script=>[ { -language => 'JavaScript1.0', -src => '/javascript/utilities10.js' }, { -language => 'JavaScript1.1', -src => '/javascript/utilities11.js' }, { -language => 'JavaScript1.2', -src => '/javascript/utilities12.js' }, { -language => 'JavaScript28.2', -src => '/javascript/utilities219.js' } ] );(If this looks a bit extreme, take my advice and stick with straight CGI scripting.)
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.
To see the list of HTML tags that are supported, open up the CGI.pm file and look at the functions defined in the %EXPORT_TAGS array.
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 qw/: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.
Sub()
instead.
use CGI qw/:standard/; print a({-href=>"bad_art.html"},"Jump to the silly exhibit"); <A HREF="bad_art.html">Jump to the silly exhibit</A>You may dispense with the dashes in front of the attribute names if you prefer:
print img {src=>'fred.gif',align=>'LEFT'}; <IMG ALIGN="LEFT" SRC="fred.gif">Sometimes an HTML tag attribute has no argument. For example, ordered lists can be marked as COMPACT, or you wish to specify that a table has a border with <TABLE BORDER>. The syntax for this is an argument that that points to an undef string:
print ol({compact=>undef},li('one'),li('two'),li('three'));Prior to CGI.pm version 2.41, providing an empty ('') string as an attribute argument was the same as providing undef. However, this has changed in order to accomodate those who want to create tags of the form <IMG ALT="">. The difference is shown in this table:
CODE | RESULT |
---|---|
img({alt=>undef}) | <IMG ALT> |
img({alt=>''}) | <IMT ALT=""> |
This example will result in HTML output that looks like this:print ul( li({-type=>'disc'},['Sneezy','Doc','Sleepy','Happy']); );
You can take advantage of this to create HTML tables easily and naturally. Here is some code and the HTML it outputs:<UL> <LI TYPE="disc">Sneezy</LI> <LI TYPE="disc">Doc</LI> <LI TYPE="disc">Sleepy</LI> <LI TYPE="disc">Happy</LI> </UL>
use CGI qw/:standard :html3/; print table({-border=>undef}, caption(strong('When Should You Eat Your Vegetables?')), Tr({-align=>CENTER,-valign=>TOP}, [ th(['','Breakfast','Lunch','Dinner']), th('Tomatoes').td(['no','yes','yes']), th('Broccoli').td(['no','no','yes']), th('Onions').td(['yes','yes','yes']) ] ) );
Breakfast | Lunch | Dinner | |
---|---|---|---|
Tomatoes | no | yes | yes |
Broccoli | no | no | yes |
Onions | yes | yes | yes |
If you want to produce tables programatically, you can do it this way:
use CGI qw/:standard :html3/; @values = (1..5); @headings = ('N','N'.sup('2'),'N'.sup('3')); @rows = th(\@headings); foreach $n (@values) { push(@rows,td([$n,$n**2,$n**3])); } print table({-border=>undef,-width=>'25%'}, caption(b('Wow. I can multiply!')), Tr(\@rows) );
N | N2 | N3 |
---|---|---|
1 | 1 | 1 |
2 | 4 | 8 |
3 | 9 | 27 |
4 | 16 | 64 |
5 | 25 | 125 |
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(0);You can turn autoescaping back on at any time with
$query->autoEscape(1)
General note 5. Some of the form-element generating methods return multiple tags. In a scalar context, the tags will be concatenated together with spaces, or whatever is the current value of the $" global. In a list context, the methods will return a list of elements, allowing you to modify them if you wish. Usually you will not notice this behavior, but beware of this:
printf("%s\n",$query->end_form())end_form() produces several tags, and only the first of them will be printed because the format only expects one value.
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 supports the "file upload" feature of Netscape 2.0 (and higher) and Internet Explorer 4.0 (and higher). 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, 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.
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, -onMouseOver, -onMouseOut and -onSelect parameters to register JavaScript event handlers.
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, -onMouseOver, -onMouseOut and -onSelect parameters to register JavaScript event handlers.
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. Depending on the browser version, the filename that gets returned may be the full local file path on the remote user's machine, or just the bare filename. If a path is provided, the follows the path conventions of the local machine.
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;
There are problems with the dual nature of the upload fields. If you
use strict
, then Perl will complain when you try to use a
string as a filehandle. You can get around this by placing the file
reading code in a block containing the no strict
pragma.
More seriously, it is possible for the remote user to type garbage
into the upload field, in which case what you get from param()
is not a filehandle at all, but a string.
To be safe, use the upload() function (new in version 2.47). When called with the name of an upload field, upload() returns a filehandle, or undef if the parameter is not a valid filehandle.
$fh = $query->upload('uploaded_file'); while (<$fh>) { print; }
In an list context, upload() will return an array of filehandles. This makes it possible to create forms that use the same name for multiple upload fields.
This is the recommended idiom.
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). However, if
the user attempts to upload several files with exactly the same name,
CGI.pm will only return the last of them. This is a known bug.
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.
You can set up a callback that will be called whenever a file upload is being read during the form processing. This is much like the UPLOAD_HOOK facility available in Apache::Request, with the exception that the first argument to the callback is an Apache::Upload object, here it's the remote filename.
$q = CGI->new(\&hook); sub hook { my ($filename, $buffer, $bytes_read, $data) = @_; print "Read $bytes_read bytes of $filename\n"; }
If using the function-oriented interface, call the CGI::upload_hook() method before calling param() or any other CGI functions: CGI::upload_hook(\&hook,$data);
This method is not exported by default. You will have to import it explicitly if you wish to use it without the CGI:: prefix.
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 access this temporary file directly (tmpFileName() will continue to return a string, but you will find no file at that location.) 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.
On Windows NT, it is impossible to make a temporary file private. This is because Windows doesn't allow you to delete a file before closing it.
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!"; }
You can set up a callback that will be called whenever a file upload is being read during the form processing. This is much like the UPLOAD_HOOK facility available in Apache::Request, with the exception that the first argument to the callback is an Apache::Upload object, here it's the remote filename.
$q = CGI->new(undef, \&hook, $data); sub hook { my ($filename, $buffer, $bytes_read, $data) = @_; print "Read $bytes_read bytes of $filename\n"; }
JavaScripting: Like textfield(), filefield() accepts -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut and -onSelect parameters to register JavaScript event handlers. Caveats and potential problems in the file upload feature.
Named parameter style print $query->popup_menu(-name=>'menu_name', -values=>[qw/eenie meenie minie/], -labels=>{'eenie'=>'one', 'meenie'=>'two', 'minie'=>'three'}, -default=>'meenie'); print $query->popup_menu(-name=>'menu_name', -values=>['eenie','meenie','minie'], -default=>'meenie'); 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, -onMouseOver, -onMouseOut, 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, -onMouseOver, -onMouseOut 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. This is equivalent to passing a
hash reference to -values. If you don't use
-nolabels, CGI.pm will add HTML label
tag around each checkbox and its label, so a browser can identify the
text as form element label properly.
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
. You may also use a hash reference in
order to produce human-readable labels that are different from
the values that will be returned as parameters to the CGI
script.
%labels
has already been defined. This is
equivalent to passing a hash reference to -values.
If you don't use -nolabels, CGI.pm will add HTML label
tag around each radio button and its label, so a browser can identify the
text as form element label properly.
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.
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: Current versions of JavaScript do not honor the
-onClick
handler, unlike other buttons.
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(0);to turn automatic HTML escaping off, and
$query->autoEscape(1);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); $q=new CGI; print $q->gradient({speed=>'fast',start=>'red',end=>'blue'});
or evenuse CGI qw(-compile :standard :html3);
use CGI qw(-compile :all);
Note that using the -compile pragma in this way will always have the effect of importing the compiled functions into the current namespace. If you want to compile without importing use the compile() method instead.
$href = $q->self_url(); $href = escapeHTML($href); print I'm talking to myself
As of version 2.64, this is the default style.name=fred;age=24;favorite_color=3
use CGI qw(-no_debug :standard);
See debugging for more details.
print h1('Level 1 Header');produces
<H1>Level 1 Header</H1>There will be some times when you want to produce the start and end tags yourself. In this case, you can use the form start_Itag_name and end_Itag_name, as in:
print start_h1,'Level 1 Header',end_h1;With a few exceptions (described below), start_tag_name and end_Itag_name functions are not generated automatically when you use CGI. However, you can specify the tags you want to generate start/end functions for by putting an asterisk in front of their name, or, alternatively, requesting either "start_tag_name" or "end_tag_name" in the import list.
Example:
use CGI qw/:standard *table start_ul/;In this example, the following functions are generated in addition to the standard ones:
start_table()
(generates a <TABLE> tag)
end_table()
(generates a </TABLE> tag)
start_ul()
(generates a <UL> tag)
end_ul()
(generates a </UL> tag)
$escaped_string = escapeHTML("unescaped string");
Provided that you have specified a character set of ISO-8859-1 (the default), the standard HTML escaping rules will be used. The "<" character becomes "<", ">" becomes ">", "&" becomes "&", and the quote character becomes """. In addition, the hexadecimal 0x8b and 0x9b characters, which many windows-based browsers interpret as the left and right angle-bracket characters, are replaced by their numeric HTML entities ("‹" and "›"). If you manually change the charset, either by calling the charset() method explicitly or by passing a -charset argument to header(), then all characters will be replaced by their numeric entities, since CGI.pm has no lookup table for all the possible encodings.
Autoescaping does not apply to other HTML-generating functions, such as h1(). You should call escapeHTML() yourself on any data that is passed in from the outside, such as nasty text that people may enter into guestbooks.
To change the character set, use charset(). To turn autoescaping off completely, use autoescape():
$charset = charset([$charset]); # Get or set the current character set. $flag = autoEscape([$flag]); # Get or set the value of the autoescape flag.
These functions escape and unescape strings according to the URL hex escape rules. For example, the space character will be converted into the string "%20".use CGI qw/escape unescape/; $q = escape('This $string contains ~wonderful~ characters'); $u = unescape($q);
These functions escape and unescape strings according to the HTML character entity rules. For example, the character < will be escaped as <.use CGI qw/escapeHTML unescapeHTML/; $q = escapeHTML('This string is <illegal> html!'); $u = unescapeHTML($q);
The arguments to compile() are a list of method names or sets, and are identical to those accepted by the use operator.use CGI (); CGI->compile(':all');
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=value2If you pass the -debug pragma to CGI.pm, you can send CGI name-value pairs as newline-delimited parameters on 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
If you run a script that uses CGI.pm from the command line and fail to provide it with any arguments, it will print out the line
(offline mode: enter name=value pairs on standard input)then appear to hang. In fact, the library is waiting for you to give it some parameters to process on its standard input. If you want to give it some parameters, enter them as shown above, then indicate that you're finished with input by pressing ^D (^Z on NT/DOS systems). If you don't want to give CGI.pm parameters, just press ^D.
You can suppress this behavior in any of the following ways:
my_script.pl ''
my_script.pl </dev/null
use CGI qw/:standard -no_debug/;
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. Note the capitalization of the initial letter. This avoids
conflict with the Perl built-in accept().
/cgi-bin/your_script/additional/stuff
will
result in $query->path_info()
returning
"/additional/stuff"
. In addition to reading the
path information, you can set it by giving path_info() an
optional string argument. The argument is expected to begin
with a "/". If not present, one will be added for you. The new
path information will be returned by subsequent calls to
path_info(), and will be incorporated into the URL generated by
self_url().
"/usr/local/etc/httpd/htdocs/additional/stuff"
.
You cannot change the path_translated, nor will setting the
additional path information change this value. The reason for
this restriction is that the translation of path information
into a physical path is ordinarily done by the server in a layer
that is inaccessible to CGI scripts.
GET, POST,
or HEAD
.
For example, all three of these examples are equivalent:
$requested_language = $q->http('Accept-language'); $requested_language = $q->http('Accept_language'); $requested_language = $q->http('HTTP_ACCEPT_LANGUAGE');
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:
Negative expiration times (e.g. "-1d") cause some browsers to delete the cookie from its persistent store. This is a poorly documented feature.
$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 are some limitations on cookies. Here is what RFC2109, section 6.3, states:
Practical user agent implementations have limits on the number and size of cookies that they can store. In general, user agents' cookie support should have no fixed limits. They should strive to store as many frequently-used cookies as possible. Furthermore, general-use user agents should provide each of the following minimum capabilities individually, although not necessarily simultaneously: * at least 300 cookies * at least 4096 bytes per cookie (as measured by the size of the characters that comprise the cookie non-terminal in the syntax description of the Set-Cookie header) * at least 20 cookies per unique host or domain name User agents created for specific purposes or for limited-capacity devices should provide at least 20 cookies of 4096 bytes, to ensure that the user can interact with a session-based origin server. The information in a Set-Cookie response header must be retained in its entirety. If for some reason there is inadequate space to store the cookie, it must be discarded, not truncated. Applications should use as few and as small cookies as possible, and they should cope gracefully with the loss of a cookie.Unfortunately, some browsers appear to have limits that are more restrictive than those given in the RFC. 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
parameter. When the form is submitted, the output
will be redirected to the indicated frame:
print $query->start_form(-target=>'result_frame');
-target
argument in the header method. For example,
the following code will pop up a new window and display the script's
output:
$query = new CGI; print $query->header(-target=>'_blank');This feature is a non-standard extension to HTTP which is supported by Netscape browsers, but not by Internet Explorer.
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. Here is a partial list:
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.
The JavaScript "standard" is still evolving, which means that new handlers may be added in the future, or may be present in some browsers and not in others. You do not need to wait for a new version of CGI.pm to use new event handlers. Just like any other tag attribute they will produce syntactically correct HTML. For instance, if Microsoft invents a new event handler called onInterplanetaryDisaster, you can install a handler for it with:
Table of contentsprint button(-name=>'bail out',-onInterPlaneteryDisaster=>"alert('uh oh')");
CGI.pm has limited support for HTML3's cascading style sheets (css). To incorporate a stylesheet into your document, pass the start_html() method a -style parameter. The value of this parameter may be a scalar, in which case it is incorporated directly into a <STYLE> section, or it may be a hash reference. In the latter case you should provide the hash with one or more of -src or -code. -src points to a URL where an externally-defined stylesheet can be found. -code points to a scalar value to be incorporated into a <STYLE> section. Style definitions in -code override similarly-named ones in -src, hence the name "cascading."
You may also specify the MIME type of the stylesheet by including an optional -type parameter in the hash pointed to by -style. If not specified, the type defaults to 'text/css'.
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;
Pass an array reference to -code or -srcin order to incorporate multiple stylesheets into your document.
Should you wish to incorporate a verbatim stylesheet that includes arbitrary formatting in the header, you may pass a -verbatim tag to the -style hash, as follows:
print $q->start_html (-STYLE => {-verbatim => '@import url("/server-common/css/'.$cssFile.'");', -src => '/server-common/css/core.css'});
This will generate HTML like this:
<link rel="stylesheet" type="text/css" href="/server-common/css/core.css"> <style type="text/css"> @import url("/server-common/css/main.css"); </style>
Any additional arguments passed in the -style value will be incorporated into the <link> tag. For example:
This will give:start_html(-style=>{-src=>['/styles/print.css','/styles/layout.css'], -media => 'all'});
<link rel="stylesheet" type="text/css" href="/styles/print.css" media="all"/> <link rel="stylesheet" type="text/css" href="/styles/layout.css" media="all"/>
To make more complicated <link> tags, use the Link() function and pass it to start_html() in the -head argument, as in:
Table of contents@h = (Link({-rel=>'stylesheet',-type=>'text/css',-src=>'/ss/ss.css',-media=>'all'}), Link({-rel=>'stylesheet',-type=>'text/css',-src=>'/ss/fred.css',-media=>'paper'})); print start_html({-head=>\@h})
Servers use a variety of conventions for designating CGI scripts as NPH. IIS and many Unix servers look at the beginning of the script's name for the prefix "nph-".
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. However, after applying Service Pack 6, NPH scripts do not work at all on IIS without a special patch from Microsoft. See Knowledgebase article Q280/3/31 Non-Parsed Headers Stripped From CGI Applications That Have nph- Prefix in Name
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 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://stein.cshl.org/software/boulder/
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;
If you use standard subclassing techniques and restrict yourself to using CGI.pm and its subclasses in the object-oriented manner, you'll have no problems. However, if you wish to use the function-oriented calls with your subclass, follow this model:
The first special trick is to set the CGI package variable $CGI::DefaultClass to the name of the module you are defining. If you are using perl 5.004 or higher, you can use the special token "__PACKAGE__" to retrieve the name of the current module. Otherwise, just hard code the name of the module. This variable tells CGI what type of default object to create when called in the function-oriented manner.package MySubclass; use vars qw(@ISA $VERSION); require CGI; @ISA = qw(CGI); $VERSION = 1.0; $CGI::DefaultClass = __PACKAGE__; $AutoloadClass = 'CGI'; sub new { .... } 1;
The second trick is to set the package variable $AutoloadClass to the string "CGI". This tells the CGI autoloader where to look for functions that are not defined. If you wish to override CGI's autoloader, set this to the name of your own package.
More information on extending CGI.pm can be found in my new book, The Official Guide to CGI.pm, which was published by John Wiley & Sons in April 1998. Check out the book's Web site, which contains multiple useful coding examples.
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 CGI::Fast 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; }
#!/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;
Configuration note: When using CGI.pm with mod_perl it is not necessary to enable the PerlSendHeader directive. 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; }
mod_perl comes with a small wrapper library named CGI::Switch that selects dynamically between using CGI and CGI::Apache. This library is no longer needed. However users of CGI::Switch can continue to use it without risk. Note that 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!)
If you use CGI.pm in many of your mod_perl scripts, you may want to preload CGI.pm and its methods at server startup time. To do this, add the following line to httpd.conf:
Create the file /home/httpd/conf/startup.pl and put in it all the modules you want to load. Include CGI.pm among them and call its compile() method to precompile its autoloaded methods.PerlScript /home/httpd/conf/startup.pl
Change the path to the startup script according to your preferences.#!/usr/local/bin/perl use CGI (); CGI->compile(':all');
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. The function result is the number of parameters
parsed. You can use this to determine whether the script is being
called from a fill out form or not.
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/nullAnother option is to use the "-no_debug" pragma when you "use" CGI.pm. This will suppress command-line debugging completely:
use CGI qw/:standard -no_debug/;
Due to problems that integer.pm has with unary negation, calls to CGI.pm that use the -arg=>value format will break if you load the integer.pm module. This is fixed in Perl 5.005_61 and up.
A workaround is to put all arguments in quotes: '-arg'=>'value'
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 -d $_ && -w _; }Modify the foreach() line to contain a series of one or more directories to store temporary files in.
Alternatively, you can just skip the search entirely and force CGI.pm to store its temporary files in some logical location. Do this at the top of your script with a line like this one: $TempFile::TMPDIRECTORY='/WWW_ROOT';
\temp
, taking up space.Unix users don't have this problem, because well designed operating systems make it possible to delete a file without closing it.
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");
CGI.pm provides four simple functions for producing multipart documents of the type needed to implement server push. To import these into your namespace, you must import the ":push" set. You are also advised to put the script into NPH mode and to set $| to 1 to avoid buffering problems.
Here is a simple script that demonstrates server push:
#!/usr/local/bin/perl use CGI qw/:push -nph/; $| = 1; print multipart_init(-boundary=>'----------------here we go!'); foreach (0 .. 4) { print multipart_start(-type=>'text/plain'), "The current time is ",scalar(localtime),"\n"; if ($_ < 4) { print multipart_end; } else { print multipart_final; } sleep 1; }
This script initializes server push by calling multipart_init(). It then enters a loop in which it begins a new multipart section by calling multipart_start(), prints the current local time, and ends a multipart section with multipart_end(). It then sleeps a second, and begins again. On the final iteration, it ends the multipart section with multipart_final() rather than with multipart_end().
Initialize the multipart system. The -boundary argument specifies what MIME boundary string to use to separate parts of the document. If not provided, CGI.pm chooses a reasonable boundary for you.multipart_init(-boundary=>$boundary);
Start a new part of the multipart document using the specified MIME type. If not specified, text/html is assumed.multipart_start(-type=>$type)
End a part. You must remember to call multipart_end() once for each multipart_start(), except at the end of the last part of the multipart document when multipart_final() should be called instead of multipart_end().multipart_end()
End all parts. You should call multipart_final() rather than multipart_end() at the end of the last part of the multipart document.multipart_final()
Only Netscape Navigator supports server push. Internet Explorer browsers do not.
Another possible attack is for the remote user to force CGI.pm to accept a huge file upload. CGI.pm will accept the upload and store it in a temporary directory even if your script doesn't expect to receive an uploaded file. CGI.pm will delete the file automatically when it terminates, but in the meantime the remote user may have filled up the server's disk space, causing problems for other programs.
The best way to avoid denial of service attacks is to limit the amount of memory, CPU time and disk space that CGI scripts can use. Some Web servers come with built-in facilities to accomplish this. In other cases, you can use the shell limit or ulimit commands to put ceilings on CGI resource usage.
CGI.pm also has some simple built-in protections against denial of service attacks, but you must activate them before you can use them. These take the form of two global variables in the CGI name space:
use CGI qw/:standard/; use CGI::Carp 'fatalsToBrowser'; $CGI::POST_MAX=1024 * 100; # max 100K posts $CGI::DISABLE_UPLOADS = 1; # no uploads
An attempt to send a POST larger than $POST_MAX bytes will cause param() to return an empty CGI parameter list. You can test for this event by checking cgi_error(), either after you create the CGI object or, if you are using the function-oriented interface, call param() for the first time. If the POST was intercepted, then cgi_error() will return the message "413 POST too large".
This error message is actually defined by the HTTP protocol, and is designed to be returned to the browser as the CGI script's status code. For example:
$uploaded_file = param('upload'); if (!$uploaded_file && cgi_error()) { print header(-status=>cgi_error()); exit 0; }
Some browsers may not know what to do with this status code. It may be better just to create an HTML page that warns the user of the problem. Table of contents
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 correct script mapping registry keys for IIS. Perl for Windows is
available from the ActiveState company, which can be found at:
http://www.activestate.com/
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
http://www.wiley.com/compbooks/stein/
perl -MCGI -e 'print $CGI::VERSION'
)
perl -v
)
September 13, 2000
September 12, 2000
August 19, 2000
August 13, 2000
August 4, 2000
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
user_name()
and remote_user()
methods.
autoEscape()
method.
v Last modified: Mon Apr 12 16:36:49 EDT 2004