📄 ch16.htm
字号:
print $q->submit(-name=>`Action',-value=>`Divide');
print "\n</TD><TD>\n";
print "</TR></TABLE>\n";
print $q->end_form;
}
</FONT></PRE>
<P>You will note that in this example, we use the hidden field <TT>Value</TT> to
retain the current value of the calculator. We do some very basic field validation
to make sure the user actually gave us a number. Obviously, this calculator will
accept only integer values. Remember that when the user leaves our CGI program and
returns, all state is now lost. Figure 16.1 shows the calculator as it appears in
the Web browser.</P>
<P>Let's look at another example now in Listing 16.2 that will make use of a file
to retain state about a certain client. We will use the <TT>REMOTE_ADDR</TT> CGI
environment variable to distinguish between clients. In this example, we will be
allowing users to enter our Web site and write whatever they like in a big text field
and then store the contents of that field in a file for them to later come back to
and modify. Additionally, we will keep track of how many times users submitted changes
to their text and display that value to them. Our example will simply use the /tmp/visitors
directory to store these files and not worry about cleaning up these files. <BR>
<BR>
<A HREF="18wpp01.jpg" tppabs="http://210.32.137.15/ebook/Web%20Programming%20with%20Perl%205/18wpp01.jpg"><TT><B>Figure 16.1.</B></TT></A><TT> </TT>The calculator
example in the browser.
<H3 ALIGN="CENTER"><A NAME="Heading5"></A><FONT COLOR="#000077">Listing 16.2. A personal
notepad.</FONT></H3>
<PRE><FONT COLOR="#0066FF">#!/usr/local/bin/perl
$directory = "/tmp/visitors";
use CGI::Form;
$q = new CGI::Form;
print $q->header();
print $q->start_html(-title=>`A Personal Notepad');
print "<H1>A Personal Notepad</H1>\n";
$client=$q->cgi->var(`REMOTE_ADDR');
if ($client eq "") {
print "<P>Sorry, I don't know who you are. I can't continue\n";
exit;
} else {
if ($q->cgi->var(`REQUEST_METHOD') eq `GET') {
if (-e "$directory/$client") {
($text,$visits)=&getUserData("$directory/$client");
} else {
$text="";
$visits=0;
}
&printForm($q,$text,$visits);
} else {
if ($q->param(`Action') eq "Submit") {
($whocares,$visits)=&getUserData("$directory/$client");
$text=$q->param(`Text');
$visits++;
&setUserData("$directory/$client",$text,$visits);
}
&printForm($q,$text,$visits);
}
}
print $q->end_html();
sub printForm {
my($q)=@_;
$q->param(`Text',$text);
print "<P>You have modified this notepad $visits times.<P>\n";
print $q->start_multipart_form();
print $q->textarea(-name=>`Text',-default=>$text,
-rows=>20,-columns=>50);
print "<BR>";
print $q->submit(-name=>`Action',-value=>`Submit');
print $q->end_form;
}
sub getUserData {
my($file)=@_;
if (open(IN,"< $file")) {
$visits=<IN>;
$text=join(``,<IN>);
close(IN);
} else {
$text="";
$visits=0;
}
return($text,$visits);
}
sub setUserData {
my($file,$text,$visits)=@_;
if (open(OUT,"> $file")) {
print OUT "$visits\n";
print OUT $text;
close(OUT);
} else {
# This is an error condition that shouldn't happen.
# Handle it properly just the same.
print "<P>Error! I cannot save your text. Sorry!<BR>\n";
}
}
</FONT></PRE>
<P>This solution is probably more efficient if you need to save larger amounts of
data. However, this solution can also drain your server's resources very quickly.
Be sure that you have enough machine resources to handle the expected number of clients
for which you'll need to maintain state. Figure 16.2 shows the personal notepad as
it appears in the browser.</P>
<P>Hopefully, these examples will be enough to get you thinking about how you can
implement your own persistent CGI sessions across multiple transactions. <BR>
<BR>
<A HREF="18wpp02.jpg" tppabs="http://210.32.137.15/ebook/Web%20Programming%20with%20Perl%205/18wpp02.jpg"><TT><B>Figure 16.2.</B></TT></A><TT> </TT>The personal
notepad. <BR>
<BR>
<B><TT>Execution and Shell-Like Interfaces</TT></B> Using this idea of preserving
session information, we can take the example further and provide a simple remote
login type of shell for execution of things on the server. What we'll do in Listing
16.3 is provide a login form, and each subsequent calls to the CGI program will be
a command line from which the user can remotely execute programs. This can also be
accomplished within a protected directory allowing the login action to be done within
the browser. You might also consider limiting the types of commands one could execute
using this CGI session.
<H3 ALIGN="CENTER"><A NAME="Heading6"></A><FONT COLOR="#000077">Listing 16.3. A Web-based
command shell.</FONT></H3>
<PRE><FONT COLOR="#0066FF">#!/usr/local/bin/perl
use CGI::Form;
$q = new CGI::Form;
print $q->header();
print $q->start_html(-title=>`A Web-based Command Shell');
print "<H1>A Web-based Command Shell</H1>\n";
if ($q->cgi->var(`REQUEST_METHOD') eq `GET') {
&loginForm($q);
} else {
if ($q->param(`Action') eq "Login") {
$uid=$q->param(`uid');
$pw=$q->param(`pw');
if (&validateLogin($uid,$pw)) {
$history="";
&shellForm($q,$history);
} else {
&unauthorized($q);
}
} elsif ($q->param(`Action') eq "Doit") {
$history=$q->param(`cmdHistory');
$command=$q->param(`command');
if ($command ne "") {
$history.=&doCommand($q,$command);
}
$q->param(`cmdHistory',$history);
&shellForm($q,$history);
} else {
&unauthorized($q);
}
}
print $q->end_html();
sub validateLogin {
my($userid,$pw)=@_;
my($retval)=0;
if (open(PASSWD,"/etc/passwd")) {
while (<PASSWD>) {
chop;
my($login,$passwd,$uid,$gid,$rest)=split(/:/);
if ($login eq $userid && crypt($pw,$passwd) eq $passwd) {
$retval=1;
last;
}
}
close(PASSWD);
}
return $retval;
}
sub unauthorized {
my($q)=@_;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -