⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch20.htm

📁 CGI programming is the hottest stuff to look out for in this book
💻 HTM
📖 第 1 页 / 共 3 页
字号:
Perl 5 is required for this example because of the use of references. Perl 5 contains many new features and is almost completely backward compatible. It is available from <TT><FONT FACE="Courier"><A 
HREF="http://www.perl.com/perl">http://www.perl.com/perl</A></FONT></TT>.
</BLOCKQUOTE>

</TD></TR>
</TABLE></CENTER>
<P>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">sub getinfo {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
Get information about existing players.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;open (P, &quot;state.dat&quot;);&nbsp;&nbsp;&nbsp;&nbsp;
# Open player database.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $n = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
Number of active players.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (&lt;P&gt;)
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Read
through each player.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chop;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
Remove newline.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@dat
= split(/:/,$_,7);&nbsp;&nbsp;&nbsp;&nbsp;# Get values from lines.
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$p[$dat[0]]{'name'}
= $dat[1];&nbsp;&nbsp;&nbsp;&nbsp;# Get Name.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$p[$dat[0]]{'xpos'}
= $dat[2];&nbsp;&nbsp;&nbsp;&nbsp;# Get X Position<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$p[$dat[0]]{'ypos'}
= $dat[3];&nbsp;&nbsp;&nbsp;&nbsp; # Get Y Position<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$p[$dat[0]]{'pass'}
= $dat[4];&nbsp;&nbsp;&nbsp;&nbsp;# Get Password<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$p[$dat[0]]{'hp'}
= $dat[5];&nbsp;&nbsp;&nbsp;&nbsp;# Get Hit Points<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$p[$dat[0]]{'mes'}
= $dat[6];&nbsp;&nbsp;&nbsp;&nbsp;# Get List of Attackers<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if
($p[$dat[0]]{'name'}) {$n++;} # If there was a character<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
on this line, increment $n.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close P;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$n&#173;&#173;;
# Since the last character was incremented. Decrement $n.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $n; # Return
$n. The rest of the data is stored in the<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
associative references \%$p[0..n]<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
This function uses some of the most basic and common functions
of Perl with no actual CGI interface. You can use functions similar
to this to retrieve and store any kind of information from text
files (including e-mail messages).
<P>
Now we can actually create the new character. The actual HTML
form can be anything as long as it returns a field with the name
<TT><FONT FACE="Courier">name</FONT></TT>. In this function, I
make use of a Perl module called cgi_head.pm. This takes input
from a form and stores it in variables called <TT><FONT FACE="Courier">$FORM{'x'}</FONT></TT>
where <TT><FONT FACE="Courier">x</FONT></TT> is the name of the
input field. It also prints the correct HTML header so the browser
knows to expect HTML code. There are many modules available for
Perl that provide similar functionality (including CGI.pm from
CPAN <TT><FONT FACE="Courier"><A HREF="http://www.perl.com/perl/CPAN/">http://www.perl.com/perl/CPAN/</A></FONT></TT>).
<BLOCKQUOTE>
<TT><FONT FACE="Courier">require cgi_head; # include the cgi_head.pm
module<BR>
<BR>
sub new_char {<BR>
<BR>
$| = 1;&nbsp;&nbsp;# Turn off buffering. Mostly for good luck.
<BR>
srand; # initialize the random number generator.<BR>
<BR>
while (-e &quot;statelock&quot;) { sleep 1; } # If someone else
is modifying the<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
database, wait till they finish.<BR>
system(&quot;touch statelock&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# Lock the database for our use.<BR>
<BR>
$n = &amp;getinfo;&nbsp;&nbsp;&nbsp;&nbsp;# Get player information.
<BR>
<BR>
$xpos = int(rand(28)) + 1; # Create x and y coordinates<BR>
$ypos = int(rand(13)) + 1; # for new character.<BR>
loop:<BR>
for ($I = 0; $I &lt;= $n; $I++) {&nbsp;&nbsp;&nbsp;# Look through
all existing players.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# If another player has these<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# coordinates, make new ones.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (($xpos ==
$p[$I]{'xpos'})&amp;&amp;($ypos == $p[$I]{'ypos'})) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$xpos
= int(rand(28)) + 1;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ypos
= int(rand(13)) + 1;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next
loop;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
}<BR>
open (P, &quot;&gt;&gt;state.dat&quot;);&nbsp;&nbsp;&nbsp;# append
to database.<BR>
$pass = int(rand(1000));&nbsp;&nbsp;&nbsp;# Make new password.
<BR>
<BR>
if ($n &gt; 0) {&nbsp;&nbsp;&nbsp;&nbsp;# A kludge to correctly
increment $n if there are 0 or 1<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# existing players.
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$newp = $n++;
<BR>
} elsif ($n eq &quot;0&quot;) { $newp = 1; }<BR>
else { $newp = 0; }<BR>
<BR>
print P &quot;$newp:$FORM{'name'}:$xpos:$ypos:$pass:10:\n&quot;;
# make database entry.<BR>
close P;<BR>
system (&quot;rm statelock&quot;); # Remove lock.<BR>
print &lt;&lt;EOP; # Print confirmation.<BR>
<BR>
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Welcome!&lt;/title&gt;&lt;/head&gt;&lt;BODY&gt;
<BR>
&lt;H2&gt;Your character has been approved!&lt;/h2&gt;<BR>
&lt;FORM ACTION=&quot;begin.cgi&quot;&gt;<BR>
&lt;INPUT TYPE=HIDDEN NAME=&quot;name&quot; VALUE=&quot;$FORM{'name'}&quot;&gt;
<BR>
&lt;INPUT TYPE=HIDDEN NAME=&quot;pass&quot; VALUE=&quot;$pass&quot;&gt;
<BR>
&lt;INPUT TYPE=SUBMIT VALUE=&quot;Enter the Cage!&quot;&gt;<BR>
&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;<BR>
<BR>
EOP</FONT></TT>
</BLOCKQUOTE>
<P>
There are two main things to note about this function. First,
the &quot;password&quot; is just a random number out of 1000.
The only purpose for this is to discourage players from forging
other players' actions. The password is silently included on all
transactions and matched with the password in the database. Also,
the end of the script just prints out an HTML page that links
to the game. The only reason this exists is to allow people to
refresh the game screen by reloading the page on their browser.
We could have directly loaded the game page from this CGI, but
a reload would then re-create the character.
<P>
Now that we have any number of characters created, we need to
design the actual game page on which to place them. Creating games
on the Web is unique among all Web applications. It is not necessarily
a bad thing (in fact, it can be a very good thing) to push the
speed and technology limits of the Web. While you don't want your
game to take 15 minutes to load, it does have to hold your player's
attention, and graphics are vital to that. Additionally, while
you'd like your game to be playable on as many browsers as possible,
a game is the perfect showcase for the latest HTML extension or
browser toy. Our example is going to be extremely Spartan, with
one concession: frames. While frames have serious issues for serious
pages, they bring a great advantage to game pages: the capability
to display a &quot;control panel&quot; independent of the main
display.
<P>
To accomplish this, we are actually going to have three CGI programs
controlling the game: one to generate the frames, one for the
control panel, and one for the game itself (the functions we've
already created can be made part of the cage CGI with the use
of hidden variables in the form, or they can be separate files).
<P>
The first CGI (which was referenced as <TT><FONT FACE="Courier">begin.cgi</FONT></TT>
in the <TT><FONT FACE="Courier">new_char</FONT></TT> function)
simply prints out the frames page (passing along the name and
password of the player):
<BLOCKQUOTE>
<TT><FONT FACE="Courier">#!/bin/perl<BR>
require cgi_head;<BR>
<BR>
$| = 1;<BR>
<BR>
print &lt;&lt;EOP;<BR>
<BR>
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;The Cage!&lt;/title&gt;&lt;/head&gt;
<BR>
&lt;FRAMESET ROWS=&quot;80%,20%&quot;&gt;<BR>
&lt;FRAME SRC=&quot;cage.cgi?name=$FORM{'name'}&amp;pass=$FORM{'pass'}&quot;
NAME=Cage&gt;<BR>
&lt;FRAME SRC=&quot;con.cgi?name=$FORM{'name'}&amp;pass=$FORM{'pass'}&quot;
NAME=Con&gt;<BR>
&lt;/frameset&gt;<BR>
&lt;/html&gt;<BR>
<BR>
EOP<BR>
<BR>
The control panel (called &quot;con.cgi&quot; here) is virtually
the same code.<BR>
<BR>
#!/bin/perl<BR>
<BR>
require cgi_head;<BR>
<BR>
print &lt;&lt;EOP;<BR>
<BR>
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Control Panel&lt;/title&gt;&lt;/head&gt;&lt;BODY&gt;
<BR>
&lt;A HREF=&quot;cage.cgi?d=up&amp;name=$FORM{'name'}&amp;pass=$FORM{'pass'}&quot;
TARGET=Cage&gt;Go Up<BR>
&Acirc;&lt;/a&gt;&lt;br&gt;<BR>
&lt;A HREF=&quot;cage.cgi?d=down&amp;name=$FORM{'name'}&amp;pass=$FORM{'pass'}&quot;
TARGET=Cage&gt;<BR>
&Acirc;Go Down&lt;/a&gt;&lt;br&gt;<BR>
&lt;A HREF=&quot;cage.cgi?d=left&amp;name=$FORM{'name'}&amp;pass=$FORM{'pass'}&quot;
TARGET=Cage&gt;<BR>
&Acirc;Go Left&lt;/a&gt;&lt;br&gt;<BR>
&lt;A HREF=&quot;cage.cgi?d=right&amp;name=$FORM{'name'}&amp;pass=$FORM{'pass'}&quot;
TARGET=Cage&gt;<BR>
&Acirc;Go Right&lt;/a&gt;&lt;br&gt;<BR>
<BR>
To attack, click on the player you wish to attack.<BR>
&lt;/body&gt;&lt;/html&gt;<BR>
<BR>
EOP<BR>
<BR>
Again note that the generated links pass the name and password
with every transaction.<BR>
<BR>
Finally, the heart of the game: &quot;cage.cgi&quot;:<BR>
<BR>
#!/bin/perl<BR>
<BR>
require cgi_head;<BR>
require getpos; # Or include the text of the getpos function from
above.<BR>
<BR>
srand; # Initialize the random number generator.<BR>
$| = 1;<BR>
<BR>
$name = $FORM{'name'}; # Grab name and password from the form.
<BR>
$pass = $FORM{'pass'};<BR>
<BR>
while ( -e &quot;statelock&quot;) { sleep 1; } # Wait until database
is free.<BR>
<BR>
system (&quot;touch statelock&quot;); # Lock database.<BR>
<BR>
$n = &amp;getpos; # Get player information.<BR>
<BR>
loop:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# Find the player that initiated<BR>
for ($I = 0; $I &lt;= $n; $I++) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
this transaction.Store their id<BR>
&nbsp;&nbsp;&nbsp;&nbsp;if ($name ne $p[$I]{'name'}) {&nbsp;&nbsp;#
number in $me.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next loop;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;$me = $I;<BR>
}<BR>
<BR>
<BR>
# Make sure the correct password was passed to us.<BR>
# If not, print an error message and die (rememebering to free
the database.)<BR>
if ($p[$me]{'pass'} ne $pass) { print &lt;&lt;EOP;<BR>
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Sorry!&lt;/title&gt;&lt;/head&gt;&lt;BODY&gt;
<BR>
You are not authorized to play this character.<BR>
&lt;A HREF=&quot;index.html&quot;&gt;Go to the entry room&lt;/a&gt;
to create a new character.&lt;br&gt;<BR>
&lt;/body&gt;&lt;/html&gt;<BR>
<BR>
EOP<BR>
&nbsp;&nbsp;&nbsp;&nbsp;system (&quot;rm statelock&quot;);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;die;<BR>
}<BR>
<BR>
@atts = split(',',$p[$me]{'mes'}); # Make an array of the recent
attackers.<BR>
<BR>
if ($d = $FORM{'d'}) {&nbsp;&nbsp;# If the player is requesting
movement, first<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
Check to see if they're trying to move past the<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
Boundries of the cage.&nbsp;&nbsp;If not, move them.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
We've chosen the cage to be 30x15, which displays<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
well on most browsers.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;if (($d eq &quot;up&quot;) &amp;&amp;
($p[$me]{'ypos'} == 1)) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;} elsif ($d eq &quot;up&quot;) { $p[$me]{'ypos'}--;
}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;if (($d eq &quot;down&quot;) &amp;&amp;
($p[$me]{'ypos'} == 13)) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;} elsif ($d eq &quot;down&quot;) { $p[$me]{'ypos'}++;
}<BR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -