|
|
| There's more than one way to do things | |
| PerlMonks |
perlman:lib:CGI:2by root (Monk) |
| on Dec 23, 1999 at 02:39 UTC ( [id://1312]=perlman: print w/replies, xml ) | Need Help?? |
libCurrent Perl documentation can be found at perldoc.perl.org. Here is our local, out-dated (pre-5.6) version: CREATING A FILE UPLOAD FIELD
print $query->filefield(-name=>'uploaded_file',
-default=>'starting value',
-size=>50,
-maxlength=>80);
-or-
print $query->filefield('uploaded_file','starting value',50,80);
When the form is processed, you can retrieve the entered filename by calling
$filename = $query->param('uploaded_file');
In Netscape Navigator 2.0, 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/file On an MS-DOS/Windows and OS/2 machines, the filename will follow DOS conventions:
C:\PATH\TO\THE\FILE.MSW On a Macintosh machine, the filename will follow Mac conventions:
HD 40:Desktop Folder:Sort Through:Reminders 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;
}
When a file is uploaded the browser usually sends along some information along with it in the format of headers. The information usually includes the
MIME content type. Future browsers may send other information as well (such as modification date and size). To retrieve this information, call
$filename = $query->param('uploaded_file');
$type = $query->uploadInfo($filename)->{'Content-Type'};
unless ($type eq 'text/html') {
die "HTML FILES ONLY!";
}
If you are using a machine that recognizes ``text'' and ``binary'' data modes, be sure to understand when and how to use them (see the Camel book). Otherwise you may find that binary files are corrupted during file uploads.
JAVASCRIPTING: The -onChange, -onFocus, -onBlur,
-onMouseOver, -onMouseOut and -onSelect parameters are recognized. See
CREATING A POPUP MENU
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie');
-or-
%labels = ('eenie'=>'your first choice',
'meenie'=>'your second choice',
'minie'=>'your third choice');
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie',\%labels);
-or (named parameter style)-
print $query->popup_menu(-name=>'menu_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-labels=>\%labels);
When the form is processed, the selected value of the popup menu can be retrieved using:
$popup_menu_value = $query->param('menu_name');
JAVASCRIPTING:
CREATING A SCROLLING LIST
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true');
-or-
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true',
\%labels);
-or-
print $query->scrolling_list(-name=>'list_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-size=>5,
-multiple=>'true',
-labels=>\%labels);
JAVASCRIPTING:
CREATING A GROUP OF RELATED CHECKBOXES
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-linebreak=>'true',
-labels=>\%labels);
print $query->checkbox_group('group_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],'true',\%labels);
HTML3-COMPATIBLE BROWSERS ONLY:
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-rows=2,-columns=>2);
When the form is processed, all checked boxes will be returned as a list under the parameter name 'group_name'. The values of the ``on'' checkboxes can be retrieved with:
@turned_on = $query->param('group_name');
The value returned by
@h = $query->checkbox_group(-name=>'group_name',-values=>\@values);
&use_in_creative_way(@h);
JAVASCRIPTING:
CREATING A STANDALONE CHECKBOX
print $query->checkbox(-name=>'checkbox_name',
-checked=>'checked',
-value=>'ON',
-label=>'CLICK ME');
-or-
print $query->checkbox('checkbox_name','checked','ON','CLICK ME');
The value of the checkbox can be retrieved using:
$turned_on = $query->param('checkbox_name');
JAVASCRIPTING:
CREATING A RADIO BUTTON GROUP
print $query->radio_group(-name=>'group_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-linebreak=>'true',
-labels=>\%labels);
-or-
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);
When the form is processed, the selected radio button can be retrieved using:
$which_radio_button = $query->param('group_name');
The value returned by
@h = $query->radio_group(-name=>'group_name',-values=>\@values);
&use_in_creative_way(@h);
CREATING A SUBMIT BUTTON
print $query->submit(-name=>'button_name',
-value=>'value');
-or-
print $query->submit('button_name','value');
You can figure out which button was pressed by using different values for each one:
$which_one = $query->param('button_name');
JAVASCRIPTING:
CREATING A RESET BUTTON
print $query->reset
CREATING A DEFAULT BUTTON
print $query->defaults('button_label')
CREATING A HIDDEN FIELD
print $query->hidden(-name=>'hidden_name',
-default=>['value1','value2'...]);
-or-
print $query->hidden('hidden_name','value1','value2'...);
Fetch the value of a hidden field this way:
$hidden_value = $query->param('hidden_name');
Note, that 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:
$query->param('hidden_name','new','values','here');
CREATING A CLICKABLE IMAGE BUTTON
print $query->image_button(-name=>'button_name',
-src=>'/source/URL',
-align=>'MIDDLE');
-or-
print $query->image_button('button_name','/source/URL','MIDDLE');
JAVASCRIPTING:
Fetch the value of the button this way: CREATING A JAVASCRIPT ACTION BUTTON
print $query->button(-name=>'button_name',
-value=>'user visible label',
-onClick=>"do_something()");
-or-
print $query->button('button_name',"do_something()");
NETSCAPE COOKIESNetscape browsers versions 1.1 and higher support a so-called ``cookie'' designed to help maintain state within a browser session. CGI.pm has several methods that support cookies. A cookie is a name=value pair much like the named parameters in a CGI query string. CGI scripts create one or more cookies and send them to the browser in the HTTP header. The browser maintains a list of cookies that belong to a particular Web server, and returns them to the CGI script during subsequent interactions. In addition to the required name=value pair, each cookie has several optional attributes:
The interface to Netscape cookies is the cookie() method:
$cookie = $query->cookie(-name=>'sessionID',
-value=>'xyzzy',
-expires=>'+1h',
-path=>'/cgi-bin/database',
-domain=>'.capricorn.org',
-secure=>1);
print $query->header(-cookie=>$cookie);
cookie() creates a new cookie. Its parameters include:
The cookie created by
print $query->header(-cookie=>$my_cookie);
To create multiple cookies, give
$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
use CGI;
$query = new CGI;
%answers = $query->cookie(-name=>'answers');
# $query->cookie('answers') will work too!
The cookie and
CGI namespaces are separate. If you have a parameter named 'answers' and a cookie named 'answers', the values retrieved by
# turn a CGI parameter into a cookie
$c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]);
# vice-versa
$q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
See the cookie.cgi example script for some ideas on how to use cookies effectively. NOTE: There appear to be some (undocumented) restrictions on Netscape cookies. In Netscape 2.01, at least, I haven't been able to set more than three cookies at a time. There may also be limits on the length of cookies. If you need to store a lot of information, it's probably better to create a unique session ID, store it in a cookie, and use the session ID to locate an external file/database saved on the server's side of the connection. WORKING WITH NETSCAPE FRAMESIt's possible for CGI.pm scripts to write into several browser panels and windows using Netscape's frame mechanism. There are three techniques for defining new frames programmatically:
The script ``frameset.cgi'' in the examples directory shows one way to create pages in which the fill-out form and the response live in side-by-side frames. LIMITED SUPPORT FOR CASCADING STYLE SHEETS
CGI.pm has limited support for HTML3's cascading style sheets (css). To incorporate a stylesheet into your document, pass the
You may also specify the type of the stylesheet by adding the optional -type parameter to the hash pointed to by -style. If not specified, the style defaults to 'text/css'. To refer to a style within the body of your document, add the -class parameter to any HTML element:
print h1({-class=>'Fancy'},'Welcome to the Party');
Or define styles on the fly with the -style parameter:
print h1({-style=>'Color: red;'},'Welcome to Hell');
You may also use the new span() element to apply a style to a section of text:
print span({-style=>'Color: red;'},
h1('Welcome to Hell'),
"Where did that handbasket get to?"
);
Note that you must import the ``:html3'' definitions to have the span() method available. Here's a quick and dirty example of using CSS's. See the CSS specification at http://www.w3.org/pub/WWW/TR/Wd-css-1.html for more information.
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;
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:
your_script.pl keyword1 keyword2 keyword3 or this:
your_script.pl keyword1+keyword2+keyword3 or this:
your_script.pl name1=value1 name2=value2 or this:
your_script.pl name1=value1&name2=value2 or even as newline-delimited parameters on standard input. When debugging, you can use quotes and backslashes to escape characters in the familiar shell manner, letting you place spaces and other funny characters in your parameter=value pairs:
your_script.pl "name1='I am a long value'" "name2=two\ words" DUMPING OUT ALL THE NAME/VALUE PAIRS
The
print $query->dump
Produces something that looks like:
<UL>
<LI>name1
<UL>
<LI>value1
<LI>value2
</UL>
<LI>name2
<UL>
<LI>value1
</UL>
</UL>
You can pass a value of 'true' to
As a shortcut, as of version 1.56 you can interpolate the entire CGI object into a string and it will be replaced with the a nice HTML dump shown above:
$query=new CGI;
print "<H2>Current Values</H2> $query\n";
FETCHING ENVIRONMENT VARIABLESSome of the more useful environment variables can be fetched through this interface. The methods are as follows:
USING NPH SCRIPTSNPH, or ``no-parsed-header'', scripts bypass the server completely by sending the complete HTTP header directly to the browser. This has slight performance benefits, but is of most use for taking advantage of HTTP extensions that are not directly supported by your server, such as server push and PICS headers. Servers use a variety of conventions for designating CGI scripts as NPH. Many Unix servers look at the beginning of the script's name for the prefix ``nph-''. The Macintosh WebSTAR server and Microsoft's Internet Information Server, in contrast, try to decide whether a program is an NPH script by examining the first line of script output.
CGI.pm supports
NPH scripts with a special
NPH mode. When in this mode, CGI.pm will output the necessary extra header information when the
The Microsoft Internet Information Server requires NPH mode. As of version 2.30, CGI.pm will automatically detect when the script is running under IIS and put itself into this mode. You do not need to do this manually, although it won't hurt anything if you do. There are a number of ways to put CGI.pm into NPH mode:
Server PushCGI.pm provides three simple functions for producing multipart documents of the type needed to implement server push. These functions were graciously provided by Ed Jordan <ed@fidalgo.net> 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!');
while (1) {
print multipart_start(-type=>'text/plain'),
"The current time is ",scalar(localtime),"\n",
multipart_end;
sleep 1;
}
This script initializes server push by calling multipart_init(). It then enters an infinite 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.
Users interested in server push applications should also have a look at the CGI::Push module. Avoiding Denial of Service AttacksA potential problem with CGI.pm is that, by default, it attempts to process form POSTings no matter how large they are. A wily hacker could attack your site by sending a CGI script a huge POST of many megabytes. CGI.pm will attempt to read the entire POST into a variable, growing hugely in size until it runs out of memory. While the script attempts to allocate the memory the system may slow down dramatically. This is a form of denial of service attack. 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:
You can use these variables in either of two ways.
Since an attempt to send a
POST larger than COMPATIBILITY WITH CGI-LIB.PLTo make it easier to port existing programs that use cgi-lib.pl the compatibility routine ``ReadParse'' is provided. Porting is simple: OLD VERSION require ``cgi-lib.pl''; &ReadParse; print ``The value of the antique is $in{antique}.\n''; NEW VERSION use CGI; CGI::ReadParse print ``The value of the antique is $in{antique}.\n'';
CGI.pm's
Once you use ReadParse, you can retrieve the query object itself this way:
$q = $in{CGI};
print $q->textfield(-name=>'wow',
-value=>'does this really work?');
This allows you to start using the more interesting features of CGI.pm without rewriting your old scripts from scratch. AUTHOR INFORMATIONCopyright 1995-1997, Lincoln D. Stein. All rights reserved. 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. Address bug reports and comments to: lstein@genome.wi.mit.edu CREDITSThanks very much to:
A COMPLETE EXAMPLE OF A SIMPLE FORM-BASED SCRIPT
#!/usr/local/bin/perl
use CGI;
$query = new CGI;
print $query->header;
print $query->start_html("Example CGI.pm Form");
print "<H1> Example CGI.pm Form</H1>\n";
&print_prompt($query);
&do_work($query);
&print_tail;
print $query->end_html;
sub print_prompt {
my($query) = @_;
print $query->startform;
print "<EM>What's your name?</EM><BR>";
print $query->textfield('name');
print $query->checkbox('Not my real name');
print "<P><EM>Where can you find English Sparrows?</EM><BR>";
print $query->checkbox_group(
-name=>'Sparrow locations',
-values=>[England,France,Spain,Asia,Hoboken],
-linebreak=>'yes',
-defaults=>[England,Asia]);
print "<P><EM>How far can they fly?</EM><BR>",
$query->radio_group(
-name=>'how far',
-values=>['10 ft','1 mile','10 miles','real far'],
-default=>'1 mile');
print "<P><EM>What's your favorite color?</EM> ";
print $query->popup_menu(-name=>'Color',
-values=>['black','brown','red','yellow'],
-default=>'red');
print $query->hidden('Reference','Monty Python and the Holy Grail');
print "<P><EM>What have you got there?</EM><BR>";
print $query->scrolling_list(
-name=>'possessions',
-values=>['A Coconut','A Grail','An Icon',
'A Sword','A Ticket'],
-size=>5,
-multiple=>'true');
print "<P><EM>Any parting comments?</EM><BR>";
print $query->textarea(-name=>'Comments',
-rows=>10,
-columns=>50);
print "<P>",$query->reset;
print $query->submit('Action','Shout');
print $query->submit('Action','Scream');
print $query->endform;
print "<HR>\n";
}
sub do_work {
my($query) = @_;
my(@values,$key);
print "<H2>Here are the current settings in this form</H2>";
foreach $key ($query->param) {
print "<STRONG>$key</STRONG> -> ";
@values = $query->param($key);
print join(", ",@values),"<BR>\n";
}
}
sub print_tail {
print <<END;
<HR>
<ADDRESS>Lincoln D. Stein</ADDRESS><BR>
<A HREF="/">Home Page</A>
END
}
BUGSThis module has grown large and monolithic. Furthermore it's doing many things, such as handling URLs, parsing CGI input, writing HTML, etc., that are also done in the LWP modules. It should be discarded in favor of the CGI::* modules, but somehow I continue to work on it. Note that the code is truly contorted in order to avoid spurious warnings when programs are run with the -w switch. SEE ALSOCGI::Carp, URI, CGI::Request, CGI::MiniSvr, CGI::Base, CGI::Form, CGI::Apache, CGI::Switch, CGI::Push, CGI::Fast DISCLAIMERWe are painfully aware that these documents may contain incorrect links and misformatted HTML. Such bugs lie in the automatic translation process that automatically created the hundreds and hundreds of separate documents that you find here. Please do not report link or formatting bugs, because we cannot fix per-document problems. The only bug reports that will help us are those that supply working patches to the installhtml or pod2html programs, or to the Pod::HTML module itself, for which I and the entire Perl community will shower you with thanks and praises.If rather than formatting bugs, you encounter substantive content errors in these documents, such as mistakes in the explanations or code, please use the perlbug utility included with the Perl distribution.
Return to the index. Return to the Perl Home Page. </BODY> </HTML> |
|