![]() |
Netmar.com |
| Contact Netmar | |
| Order Webhosting | |
|
Netmar User's
Guide: Software Features: CGI PM
|
Back | |||||||
|
CGI.pm - a Perl5 CGI LibraryVersion 2.18, 3/30/96, L. SteinWarning: Version 2.18 requires the SelfLoader module. This module is part of the standard Perl 5.002 distribution, but can be used with older versions of Perl as well. If you don't want to use SelfLoader, you can disable this requirement easily. Read CGI.pm and the SelfLoader for an explanation of how the SelfLoader improves loading speed, a list of places where you can obtain it, and how to modify CGI.pm so that you can work without it. AbstractThis perl 5 library uses objects to create Web fill-out forms on the fly and to parse their contents. It is similar tocgi-lib.pl
in some respects. It provides a simple
interface for parsing and interpreting query strings passed to CGI
scripts. However, it also offers a rich set of functions for creating
fill-out forms. Instead of remembering the syntax for HTML form
elements, you just make a series of perl function calls. An important
fringe benefit of this is that the value of the previous query is used
to initialize the form, so that the state of the form is preserved
from invocation to invocation.
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:
use CGI;
$query = new CGI;
print $query->header;
print $query->startform;
print "What's your name? ",$query->textfield('name');
print "<P>What's the combination? ",
$query->checkbox_group(-name=>'words',
-values=>['eenie','meenie','minie','moe']);
print "<P>What's your favorite color? ",
$query->popup_menu(-name=>'color',
-values=>['red','green','blue','chartreuse']);
print "<P>",$query->submit;
print $query->endform;
print "<HR>\n";
if ($query->param) {
print "Your name is <EM>",$query->param('name'),"</EM>\n";
print "<P>The keywords are: <EM>",join(", ",$query->param('words')),"</EM>\n";
print "<P>Your favorite color is <EM>",$query->param('color'),"</EM>\n";
}
Select this link to try the script
More scripting examples ContentsCreating a new CGI objectThe most basic use of CGI.pm is to get at the query parameters submitted to your script. To create a new CGI object that contains the parameters passed to your script, put the following at the top of your perl CGI programs:
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 form to a file and reload it later!.
See advanced techniques for more information.
Fetching A List Of Keywords From The Query
@keywords = $query->keywords
If 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.
Fetching The Names Of All The Parameters Passed To Your Script
@names = $query->param
If 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'.
Fetching The Value(s) Of A Named Parameter
@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.
$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->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.
Importing parameters into a namespace
$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('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() (and CGI.pm still recognizes this method call). However the official method name has been changed to import_names() for compatability with the CGI:: modules. Saving the Current State of a FormSaving the State to a File$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. See advanced techniques for more information. Saving the State in a Self-Referencing URL$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 $my_self=$query->urlTable of contents Calling CGI Functions that Take Multiple ArgumentsIn versions of CGI.pm prior to 2.0, it could get difficult to remember the proper order of arguments in CGI function calls that accepted five or six different arguments. As of 2.0, there's a better way to pass arguments to the various CGI functions. In this style, you pass a series of name=>argument pairs, like this:
$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.
Creating the HTTP HeaderCreating the Standard Header for a Virtual Document
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.)
You can add any number of HTTP headers, including ones that aren't implemented, using named parameters:
print $query->header(-type=>'image/gif',
-status=>'402 Payment Required',
-Cost=>'$0.02');
Magic cookiesNetscape 1.1 and higher supports a "magic cookie" HTTP header. This cookie is a piece of text that the browser sends to the server during each request to your script. Your script can set the cookie to whatever you like the first time it gets called, and retrieve it on later invocations. This allows you to track a particular browser; you can even store parameters in the cookie if you want to.
To set a browser cookie, call print $query->header(-cookie=>'chocolate chip #3');Later you can retrieve it using the cookie() method. The idiom for creating a cookie if it doesn't already exist looks like this:
$cookie = $query->cookie();
if (!$cookie) {
$cookie = generate_some_random_cookie();
}
print $query->header(-cookie=>$cookie);
This technique will not work with non-Netscape browsers.
You should also be warned that certain servers, such as Apache 1.0 and
the Netscape servers, will attempt to generate magic cookies for you.
You should be alert for any adverse interaction between your script
and the server.
Creating the Header for a Redirection Request
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. HTML ShortcutsCreating an HTML Header
named parameter style
print $query->start_html(-title=>'Secrets of the Pyramids',
-author=>'fred@capricorn.org',
-base=>'true',
-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:
Ending an HTML Documentprint $query->end_htmlThis ends an HTML document by printing the </BODY></HTML> tags. Creating FormsGeneral note 1. The various form-creating methods all return strings to the caller. These strings will contain the HTML code that will create the requested form element. You are responsible for actually printing out these strings. It's set up this way so that you can place formatting tags around the form elements.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:
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 of automatic escaping, call the
$query = new CGI;
$query->autoEscape(undef);
You can turn autoescaping back on at any time with $query->autoEscape('yes')
Form ElementsUp to table of contentsCreating An Isindex Tagprint $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. Starting And Ending A Form
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:
startform().
If you plan to make use of the JavaScript features
of Netscape 2.0, you can provide
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.
Creating A Text Field
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.
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.
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.
Creating a File Upload Field
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 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;
}
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);
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.
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.
Creating A Scrolling List
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.
@selected = $query->param('list_name');
JavaScripting: You can provide -onChange,
-onFocus, and -onBlur
parameters to register JavaScript event
handlers.
Creating A Group Of Related Checkboxes
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.
@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.
Creating A Standalone Checkbox
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.
Creating A Radio Button Group
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.
$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.
$which_one = $query->param('button_name');
JavaScripting: You can provide an -onClick
parameter to register some JavaScript
code to be performed every time the user clicks on the button.
You can't prevent a form from being submitted, however. You must
provide an -onSubmit handler to the form
itself to do that.
Creating A Reset Buttonprint $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. Creating A Defaults 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.
Creating A Hidden Field
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');
Creating a Clickable Image Button
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.
Creating a JavaScript 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.
Controlling HTML AutoescapingBy default, if you use a special HTML character such as >, < or & as the label or value of a button, it will be escaped using the appropriate HTML escape sequence (e.g. >). This lets you use anything at all for the text of a form field without worrying about breaking the HTML document. However, it may also interfere with your ability to use special characters, such as Á as default contents of fields. You can turn this feature on and off with the methodautoEscape().
Use
$query->autoEscape(undef);
to turn automatic HTML escaping off, and
$query->autoEscape('true');
to turn it back on.
DebuggingIf you are running the script from the command line or in the perl debugger, you can pass the script a list of keywords or parameter=value pairs on the command line or from standard input (you don't have to worry about tricking your script into reading from environment variables). You can pass keywords like this: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
Dumping Out All The Name/Value PairsThe dump() method produces a string consisting of all the query's name/value pairs formatted nicely as a nested list. This is useful for debugging purposes: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"; HTTP Session VariablesSome of the more useful environment variables can be fetched through this interface. The methods are as follows:
Support for Netscape FramesCGI.pm contains support for Netscape frames, a new feature in version 2.0 and higher. Frames are supported in two ways:
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. Support for JavaScriptNetscape versions 2.0 and higher incorporate an interpreted language called JavaScript. It isn't the same as Java, and certainly isn't at all the same as Perl, which is a great pity. JavaScript allows you to programatically change the contents of fill-out forms, create new windows, and pop up dialog box from within Netscape itself. From the point of view of CGI scripting, JavaScript is quite useful for validating fill-out forms prior to submitting them.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. Advanced TechniquesA Script that Saves Some Information to a File and Restores ItThis script will save its state to a file of the user's choosing when the "save" button is pressed, and will restore its state when the "restore" button is pressed. Notice that it's very important to check the file name for shell metacharacters so that the script doesn't inadvertently open up a command or overwrite someone's file. For this to work, the script's current directory must be writable by "nobody".
#!/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;
}
A Script that Uses Self-Referencing URLs to Jump to Internal Links(Without losing form information).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;
Multiple forms on the same pageThere's no particular trick to this. Just remember to close one form before you open another one. You can reuse the same query object or create a new one. Either technique works.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;
CGI.pm and the Self LoaderIn the past one problem with CGI.pm was that, being a bloated everything-but-the-kitchen sink module, it took a long time to load. The long loading time was due to the many functions it defined, most of which never got used in a particular session anyway. As of version 2.17, CGI.pm uses the SelfLoader module to load functions only on demand. This improves loading speed considerably.When CGI.pm is first loaded, it only compiles the core new(), param(), keywords() and import() functions that are used by almost every CGI program. This cuts the loading time by a factor of half. If you use any of the other functions, the appropriate section of the code will be loaded and compiled. For people who only want to read in and parse the CGI variables, this is a big win. For everyone else, there's more or less of a gain in load speed depending on how many functions you call on.
Unfortunately there are problems with the self loader. For
one thing, it is not
yet part of the standard Macintosh and Windows NT distributions,
and the Unix variants of the self loader are not known to work
with these versions of perl.
For another, it is incompatible with the
useful
The SelfLoader can be found in the standard Perl 5.002 distribution. You can also obtain it separately and use it with 5.001. Use archie or a webcrawler to find a CPAN perl archive site near you, or consult this partial list:
As an aside, I've noticed that the new perl debugger Using the File Upload FeatureFirst of all, because the file upload feature is so new, this code is has not been tested as much as I'd like. A complicating factor is that the various versions of Netscape on the Macintosh, Unix and Windows platforms don't all seem to implement file uploading in exactly the same way. I've tried to make CGI.pm work with all versions on all platforms, but I keep getting reports from people of instances that break the file upload feature. (Currently the only unresolved problem is a report that uploads of large binary files are aborted when SSL is in use. If you can reproduce this problem and have some idea what's happening I'd like to know about it.)
The main technical challenge of handling file uploads is that
it potentially involves sending more data to the CGI script
than the script can hold in main memory. For this reason
CGI.pm creates temporary files in
either the
Frequent ProblemsYou can't retrieve the name of the uploaded file using the param() methodMost likely the remote user isn't using version 2.0 (or higher) of Netscape. Alternatively she just isn't filling in the form completely.You can read the name of the uploaded file, but can't retrieve the dataFirst check that you've told CGI.pm to use the new multipart/form-data scheme. If it still isn't working, there may be a problem with the temporary files that CGI.pm needs to create in order to read in the (potentially very large) uploaded files. Internally, CGI.pm tries to create temporary files with names similar toCGITemp123456 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.
When you press the "back" button, the same page is loaded, not the previous one.Netscape 2.0's history list gets confused when processing multipart forms. If the script generates different pages for the form and the results, hitting the "back" button doesn't always return you to the previous page; instead Netscape reloads the current page. This happens even if you don't use an upload file field in your form.The 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'); You can't find the temporary file that CGI.pm createsYou're encouraged to copy the data into your own file by reading from the file handle that CGI.pm provides you with. In the future there may be no temporary file at all, just a pipe. However, for now, if you really want to get at the temp file, you can retrieve its path using the tmpFileName() method. Be sure to move the temporary file elsewhere in the file system if you don't want it to be automatically deleted when CGI.pm exits.Using CGI.pm on non-Unix PlatformsWindows NTThe NT port of perl has an annoying habit of transforming newline (\n) sequences into carriage-return/newline (\r\n) sequences both on input and output. This confuses certain servers, such as the Netscape Communications Server. To make things work correctly, find the following line in CGI.pm$needs_binmode = 0;and change it to $needs_binmode = 1;CGI.pm works well with WebSite, the EMWACS server and Purveyor. CGI.pm must be put in the perl5 library directory, and all CGI scripts that use it should be placed in cgi-bin directory. You also need to associate the .pl suffix with perl5 using the NT
file manager.
WebSite uses a slightly different cgi-bin directory structure than
the standard. For this server, place the scripts in the
The Netscape Communications Server has terrible problems with Perl
scripts because it doesn't use the standard NT file extension
associations. Netscape's recommendation of placing VMSSet $needs_binmode to 1 as described above.MacintoshChristian Huldt reports that at least the basic features of CGI.pm work correctly with MacPerl version 5.0.6r1 and the WebStar and MacHTTP servers. The following changes have to be made:
Future Prospects for this LibraryThis library is a precursor to the full featured CGI, URL, and HTML modules being developed as part of the Perl CGI developer's effort. Although those modules supersede much of the functionality of this one, I am continuing to maintain and improve this library in order to maintain compatability with CGI scripts that rely on it and to satisfy people who are looking for an easy-to-use introduction to the world of CGI scripting.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 Distribution Information:This code is copyright 1995, 1996 by Lincoln Stein and the Whitehead Institute for Biomedical Research. It may be used and modified freely, but I do request that this copyright notice remain attached to the file. You may modify this module as you wish, but if you redistribute a modified version, please attach a note listing the modifications you have made.Bug ReportsAddress bug reports and comments to:lstein@genome.wi.mit.edu Revision HistoryVersion 2.18
Version 2.17
Version 2.16
Version 2.15
Version 2.14This was an internal experimental version that was never released.Version 2.13
Version 2.01
Version 2.0The changes seemed to touch every line of code, so I decided to bump up the major version number.
Version 1.57
Version 1.56
Bug fixes in version 1.55
Bug fixes in version 1.54
Bug fixes in version 1.53
New features added in version 1.52
Bugs fixed in version 1.51
New features added in version 1.50
Bugs fixed in version 1.45
Bugs fixed in version 1.44
New features added in version 1.43
New features added in version 1.42
New features added in version 1.4
Bug fixes
Lincoln D. Stein, lstein@genome.wi.mit.edu Whitehead Institute/MIT Center for Genome Research Last modified: Tue Apr 2 23:54:50 EST 1996 |
|||||||||