📄 ch20.htm
字号:
<I>Declare a hash variable to hold the form's input fields.<BR>
Call the </I><TT><I>getFormData()</I></TT><I>
fuNCtion.<BR>
Define the </I><TT><I>getFormData()</I></TT><I>
fuNCtion.<BR>
Declare a local variable to hold the refereNCe to the input field
hash.<BR>
Initialize a buffer.<BR>
If the </I><TT><I>GET</I></TT><I>
method is used, copy the form information into the buffer.<BR>
If the </I><TT><I>POST</I></TT><I>
method is used, read the form information into the buffer.<BR>
Iterate over the array returned by the </I><TT><I>split()</I></TT><I>
fuNCtion.<BR>
Decode both the input field name and value.<BR>
Create an entry in the input field hash variable.<BR>
Define the </I><TT><I>decodeURL()</I></TT><I>
fuNCtion.<BR>
Get the eNCoded string from the parameter array.<BR>
Translate all plus signs into spaces.<BR>
Convert character coded as hexadecimal digits into regular characters.
<BR>
Return the decoded string.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 20.2 20LST02.PL-The First Step Is to Get
the Form Information<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
my(%frmFlds);
getFormData(\%frmFlds);
sub getFormData {
my($hashRef) = shift;
my($buffer) = "";
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
$buffer = $ENV{'QUERY_STRING'};
}
else {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}
foreach (split(/&/, $buffer)) {
my($key, $value) = split(/=/, $_);
$key = decodeURL($key);
$value = decodeURL($value);
%{$hashRef}->{$key} = $value;
}
}
sub decodeURL {
$_ = shift;
tr/+/ /;
s/%(..)/pack('c', hex($1))/eg;
return($_);
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
The <TT>getFormData()</TT> fuNCtion
could be considered complete at this point. It correctly reads
from both the <TT>GET</TT> and <TT>POST</TT>
transmission methods, decodes the information, and places the
input fields into a hash variable for easy access.
<P>
There are some additional considerations of which you need to
be aware. If you simply display the information that a user entered,
there are some risks involved that you may not be aware of. Let's
take a simple example. What if the user enters <TT><B>Rolf</B></TT>
in the <TT>name</TT> field and you
subsequently displayed that field's value? Yep, you guessed it,
<TT>Rolf</TT> would be displayed in
bold! For simple formatting HTML tags this is not a problem, and
may even be a feature. However, if the user entered an SSI tag,
he or she may be able to take advantage of a security hole-remember
the <TT><!--#exec --></TT> tag?
<P>
You can thwart would-be hackers by converting every instaNCe of
<TT><</TT> to <TT>&lt;</TT>
and of <TT>></TT> to <TT>&gt;</TT>.
The HTML standard allows for certain characters to be displayed
using symbolic codes. This allows you to display a <TT><</TT>
character without the web browser thinking that a new HTML tag
is starting.
<P>
If you'd like to give users the ability to retain the character
formatting HTML tags, you can test for each tag that you want
to allow. When an allowed tag is found, reconvert it back to using
normal <TT><</TT> and <TT>></TT>
tags.
<P>
You might want to check for users entering a series of <TT><P></TT>
tags in the hopes of generating pages and pages of blank lines.
Also, you might want to convert pressing the enter key into spaces
so that the line endings that the user entered are ignored and
the text will wrap normally when displayed by a web browser. One
small refinement of eliminating the line endings could be to convert
two consecutive newlines into a paragraph (<TT><P></TT>)
tag.
<P>
When you put all of these new features together, you wind up with
a <TT>getFormData()</TT> fuNCtion
that looks like Listing 20.3.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Declare a hash variable to hold the form's input fields.<BR>
Call the </I><TT><I>getFormData()</I></TT><I>
fuNCtion.<BR>
Define the </I><TT><I>getFormData()</I></TT><I>
fuNCtion.<BR>
Declare a local variable to hold the refereNCe to the input field
hash.<BR>
Initialize a buffer.<BR>
If the </I><TT><I>GET</I></TT><I>
method is used, copy the form information into the buffer.<BR>
If the </I><TT><I>POST</I></TT><I>
method is used, read the form information into the buffer.<BR>
Iterate over the array returned by the </I><TT><I>split()</I></TT><I>
fuNCtion.<BR>
Decode both the input field name and value.<BR>
Compress multiple </I><TT><I><P></I></TT><I>
tags into one.<BR>
Convert </I><TT><I><</I></TT><I>
into </I><TT><I>&lt;</I></TT><I>
and </I><TT><I>></I></TT><I> into
</I><TT><I>&gt;</I></TT><I> stopping
HTML tags from interpretation.<BR>
Turn back on the bold and italic HTML tags.<BR>
Remove unneded carriage returns.<BR>
Convert two newlines into a HTML paragraph tag.<BR>
Convert single newlines into spaces.<BR>
Create an entry in the input field hash variable.<BR>
Define the </I><TT><I>decodeURL()</I></TT><I>
fuNCtion.<BR>
Get the eNCoded string from the parameter array.<BR>
Translate all plus signs into spaces.<BR>
Convert character coded as hexadecimal digits into regular characters.
<BR>
Return the decoded string.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 20.3 20LST03.PL-The First Step Is to Get
the Form Information<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
my(%frmFlds);
getFormData(\%frmFlds);
sub getFormData {
my($hashRef) = shift;
my($buffer) = "";
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
$buffer = $ENV{'QUERY_STRING'};
}
else {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}
foreach (split(/&/, $buffer)) {
my($key, $value) = split(/=/, $_);
$key = decodeURL($key);
$value = decodeURL($value);
$value =~ s/(<P>\s*)+/<P>/g; # compress multiple <P> tags.
$value =~ s/</&lt;/g; # turn off all HTML tags.
$value =~ s/>/&gt;/g;
$value =~ s/&lt;b&gt;/<b>/ig; # turn on the bold tag.
$value =~ s!&lt;/b&gt;!</b>!ig;
$value =~ s/&lt;i&gt;/<b>/ig; # turn on the italic tag.
$value =~ s!&lt;/i&gt;!</b>!ig;
$value =~ s!\cM!!g; # Remove unneeded carriage re
$value =~ s!\n\n!<P>!g; # Convert 2 newlines into para
$value =~ s!\n! !g; # Convert newline into spaces.
%{$hashRef}->{$key} = $value;
}
}
sub decodeURL {
$_ = shift;
tr/+/ /;
s/%(..)/pack('c', hex($1))/eg;
return($_);
}
</PRE>
</BLOCKQUOTE>
<HR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Caution</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
Tracking security problems seems like a never-ending task but it is very important, especially if you are responsible for a web server. As complicated as the <TT>getFormData()</TT> fuNCtion is, it is still not complete. The <TT><TEXTAREA></TT> tag
lets users enter an unlimited amount of information. What would happen to your web server if someone used the cut and paste ability in Windows 95 to insert four or five megabytes into your form? Perhaps the <TT>getFormData()</TT> fuNCtion should have some
type of limitation that any individual field should only be 1,024 bytes in length?
</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<H2><A NAME="FillinginaFormandMailingtheInformation"><FONT SIZE=5 COLOR=#FF0000>
Filling in a Form and Mailing the Information</FONT></A></H2>
<P>
You can have a form's information automatically mailed to an email
address by using the <TT>mailto:</TT>
notation in the <TT>ACTION</TT> modifier
of the <TT><FORM></TT> tag.
For example,
<BLOCKQUOTE>
<PRE>
<FORM METHOD=get ACTION=mailto:medined@planet.net>
</PRE>
</BLOCKQUOTE>
<P>
When the form's submit button is clicked, the form's information
will be mailed to the email address specified in the <TT><FORM></TT>
tag. The information will be URL eNCoded and all on one line.
This means you can't read the information until it has been processed.
<P>
It is generally a bad idea to email form information because of
the URL eNCoding that is done. It is better to save the information
to a data file so that you can easily read and analyze it later.
Sending notifications by email is a good idea. For example, you
could tell an email reader that a certain form has been completed
and that the log file should be checked. If you want to send email
from a CGI script, you can use the sample program from Listing
18.2 in <A HREF="ch18.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch18.htm" >Chapter 18</A>, "Using Internet Protocols."
<P>
Before sending any form information, ensure that it has been decoded.
If you are using one of the CGI modules or the decoding fuNCtions
from <A HREF="ch19.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch19.htm" >Chapter 19</A>, "What Is CGI?," then you don't have
to worry about this requirement. Otherwise, please reread the
section called "URL ENCoding" in <A HREF="ch19.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch19.htm" >Chapter 19</A>.
<P>
Make sure to use a <TT>Reply-To</TT>
field in the body of your email message because you won't know
which login name the CGI program will be running under. INCluding
the <TT>Reply-To</TT> field will ensure
that the reader of the message can easily respond to the email
message if needed.
<H2><A NAME="DebuggingFormProcessingCGIScripts"><FONT SIZE=5 COLOR=#FF0000>
Debugging Form Processing CGI Scripts</FONT></A></H2>
<P>
CGI programs get their information from three sources: the URL
that invokes them, environment variables, and from the <TT>STDIN</TT>
filehandle. Most of the time, this information comes from the
web server that invokes the CGI script. However, you can manually
recreate the script's normal environment. This lets you debug
a CGI program from the operating system's command line which should
save you time.
<P>
The first thing to look at is how to set environment variables.
The method used depends on your operating system. Table 20.2 shows
you how to set environment variables for a variety of operating
systems.<BR>
<P>
<CENTER><B>Table 20.2 How to Set Environment Variables
by Hand</B></CENTER>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD WIDTH=164><I>Operating System</I></TD><TD WIDTH=349><I>Command Or UNIX Command Shells</I>
</TD></TR>
<TR><TD WIDTH=164>csh</TD><TD WIDTH=349><TT>setenv HTTP_USER_AGENT "Mozilla"</TT>
</TD></TR>
<TR><TD WIDTH=164>ksh or bash</TD><TD WIDTH=349><TT>export HTTP_USER_AGENT = "Mozilla"</TT>
</TD></TR>
<TR><TD WIDTH=164>Win95, WinNT, OS/2</TD><TD WIDTH=349><TT>set HTTP_USER_AGENT = Mozilla</TT>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
In order to recreate the environmental variables that a server
sets, you need to initialize at least the following environmental
variables:
<UL>
<LI>CONTENT_LENGTH-If you are using the <TT>POST</TT>
method of processing information, set this variable to the length
of the input. Finding the input length is easier than it sounds.
SiNCe you'll be creating a file to hold the test form information,
you only need to find that file's size.
<LI>REQUEST_METHOD-You should set this to either <TT>GET</TT>
or <TT>POST</TT>.
<LI>QUERY_STRING-You should value this variable, if you are using
the <TT>GET</TT> method or if your
script needs information passed to it via its URL and the extra
information should follow a question mark (<TT>?</TT>).
<LI>PATH_INFO-If your script needs information passed to it via
its URL and the extra information should follow a slash (<TT>/)</TT>,
then value this variable with the extra information.
</UL>
<P>
You also need to initialize any other variables that your program
needs. Rather than retyping the <TT>set</TT>
commands each time you want to test your CGI program, create a
shell or batch file.
<P>
The next step is to create a text file that will be substituted
for STDIN when the CGI program is run. You only need to create
this text file if you are using the <TT>GET</TT>
method. The text file can be called anything you'd like and should
contain just one line-the line of form information. For example:
<BLOCKQUOTE>
<PRE>
name=Rolf D'Barno&age=34
</PRE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -