Tải bản đầy đủ (.pdf) (12 trang)

tạo ứng dụng webchat phần 3 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (93.79 KB, 12 trang )

Finally, $chat_buffer is ended with a footer stating that the end of the
occupants list has been reached.
$chat_buffer .=
"<P><H2>End of Occupants List</H2><P>";
} # End of occupants processing
P
ROCESS CHAT M
ESSAGES
The next part of the chat script processes the chat messages for display to
the user. Here, there is one thing to take into consideration: frames. If
frames are activated, the chat program should display messages only if it
has been called upon to read messages
($fmsgs is on). If the main frame
HTML document is being output (
$frames is on) or if the message submit
frame is being output (
$fsubmit), the script will not enter the part of the
script that processes messages.
if ($fmsgs eq "on" ||
($frames ne "on" &&
$fsubmit ne "on")) {
PROCESS WHO FILES
Before the messages are collected, a new who file is generated indicating
that the user has read new messages. First, the old who file is deleted
using
unlink. Then the who file is re-created and the user information is
printed to it:
$user_name, $user_email, $user_http, and $current_date_time.
$whofile = "$chat_room_dir/$session.who";
unlink($whofile);
open(WHOFILE, ">$whofile");


print WHOFILE "$user_name|$user_email|$user_http";
print WHOFILE "|$current_date_time\n";
close (WHOFILE);
Chapter 26: WebChat
709
The code deletes the file instead of writing over it, to ensure that the
who file is assigned a different file creation time. A subroutine dis-
cussed later removes old who files on the basis of creation time.
Because this script is meant to run on multiple operating system
platforms other than UNIX, the file is deleted and re-created to
ensure consistency on as many platforms as possible.
The RemoveOldWhoFiles subroutine is called to delete who files for users
that have not read messages within the
$chat_who_length period of time.
$chat_who_length is a global variable that is specified in chat.setup.
&RemoveOldWhoFiles;
READ CHAT MESSAGES
To read the chat messages, the script can be configured to restrict the num-
ber of messages that are seen. Generally, users do not want to see all the old
messages over and over again, so the chat script keeps track of the last read
message of the user. When it is created, each message is assigned a unique
sequence number in ascending order. Whenever a user reads all the mes-
sages in the chat room directory, the current highest message number is set
to the user’s last read message number. Then, the next time the script is
called to view messages, the “last read” message number can be compared
against the message numbers in the directory. If the message number is
lower than the last read number, we know that the message is old.
The
$msg_to_read variable is set up to reflect the preceding algorithm
except that 1 is added to it. Later, when the message numbers are com-

pared, we will use the greater than or equal to (
>=) 0 operator to com-
pare the current message numbers to the last read message number
stored in
$msg_to_read.
$msg_to_read = $user_last_read + 1;
Next, $how_many_old is subtracted from $msg_to_read. As a result, some old
messages are displayed with the new ones. Remember that in the chat
room logon screen, the user chooses how many old messages to display
with new ones.
Chapter 26: WebChat
710
$msg_to_read -= $how_many_old;
If there are fewer messages in the directory than $how_many_old messages,
$msg_to_read could become a negative number or zero and the chat
script would spend extra work trying to read files that do not exist. Thus,
the next piece of code converts
$msg_to_read into a positive value.
if ($msg_to_read < 1) {
$msg_to_read = 1;
}
The next if statement checks quickly to see whether $msg_to_read is
greater than the current
$high_message number. If $msg_to_read is greater
than
$high_message, we do not need to bother iterating through all the
files in the directory, because nothing would be displayed.
if ($high_message >= $msg_to_read) {
Now we begin reading the messages within the for loop started here.
for ($x = $high_message; $x >= $msg_to_read; $x—){

The sprintf command is used to format the current message number, $x,
to an integer with a length of
6. Because $x is usually fewer than six char-
acters long,
sprintf pads it with leading spaces. Immediately afterward,
the
tr command is used to convert all the leading spaces to zeros. Thus,
sprintf converts a number such as "5" to " 5", and the tr command
converts
" 5" to "000005." This is done because the messages are
stored in the chat room directory as six-digit numbers with leading zeros.
$x = sprintf("%6d",$x);
$x =~ tr/ /0/;
The message is checked for existence using the -e operator. If it exists, it
is opened. If the opening of any message fails, the program exits with an
error message printed to the user’s Web browser.
if (-e "$chat_room_dir/$x.msg") {
open(MSG,"$chat_room_dir/$x.msg") ||
&CgiDie("Could not open $x.msg");
Chapter 26: WebChat
711
If the file is opened successfully, the message is processed. Each line of the
message corresponds to a field of information. The format of a message
appears below:
[USERNAME OF USER WHO POSTED MESSAGE]
[EMAIL OF USER WHO POSTED MESSAGE]
[URL LINK TO USER WHO POSTED MESSAGE]
[USERNAME OF USER MESSAGE IS ADDRESS TO (USUALLY ALL)]
[MESSAGE DATE AND TIME]
[MESSAGE BODY]

All the preceding fields (except the message body) are read to the follow-
ing variables:
$msg_from_user, $msg_email, $msg_http, $msg_to_user, and
$msg_date_time. The <MSG> command is a Perl convention that takes any
file handle surrounded by brackets (
<>) and returns the next line in the
file. In addition, any fields that the user has entered are processed using
the
HtmlFilter function to remove HTML codes if you have disallowed
them in chat.setup.
$msg_from_user = <MSG>;
$msg_from_user = &HtmlFilter($msg_from_user);
$msg_email = <MSG>;
$msg_email = &HtmlFilter($msg_email);
$msg_http = <MSG>;
$msg_http = &HtmlFilter($msg_http);
$msg_to_user = <MSG>;
$msg_to_user = &HtmlFilter($msg_to_user);
$msg_date_time = <MSG>;
The last character of all the variables is chopped, because a superfluous
newline character is always appended to the end of a line read from a file.
chop($msg_from_user);
chop($msg_email);
chop($msg_http);
chop($msg_to_user);
chop($msg_date_time);
Messages are displayed to a user only if the addressee is "ALL," if the
addressee matches the current username, and if the poster username
matches the current username.
Chapter 26: WebChat

712
if ($msg_to_user eq "ALL" ||
$msg_to_user =~ /^$user_name$/i ||
$msg_from_user =~ /^$user_name$/i) {
The information about the message is then converted to HTML code to
be displayed to the user. This code is placed in the
$chat_buffer variable,
just as the occupants list HTML code was placed there previously.
Each message header is formatted as an HTML table. The first field
set up in the table is the
"From:" field.
$chat_buffer .= "<TABLE>\n";
$chat_buffer .= "<TR><TD>";
$chat_buffer .= "From:</TD><TD>";
If there is an E-mail address associated with the user who posted the mes-
sage, a hypertext reference to the user’s address is placed in
$chat_buffer. Otherwise, $msg_from_user is placed in $chat_buffer.
if ($msg_email ne "") {
$chat_buffer .= qq!<A HREF=MAILTO:! .
qq!$msg_email>!;
}
$chat_buffer .= $msg_from_user;
if ($msg_email ne "") {
$chat_buffer .= "</A>";
}
If $msg_http is defined, the user’s URL link will be added as a hypertext
reference in
$chat_buffer.
if ($msg_http ne "") {
$chat_buffer .= qq! (<A HREF="$msg_http">! .

qq!Home Page</A>)!;
}
Periodically, the $chat_buffer fields are delimited with the standard <TR>,
</TR>, <TD>, and </TD> HTML tags.
$chat_buffer .= "</TD>\n";
$chat_buffer .= "\n<TD>";
Chapter 26: WebChat
713
If the current message number ($x) is greater than $user_last_read, then
a
New Msg tag is appended to the information header.
if ($x > $user_last_read) {
$chat_buffer .= " (New Msg) "
}
The date and time of the message are added to $chat_buffer.
$chat_buffer .= " at $msg_date_time</TD>";
If the message was generated for a particular user, a tag is generated for
the information header that lets the user know that this is a private mes-
sage to him or her or that it is a private message that the user posted to
someone else.
$chat_buffer .= "</TR>\n";
if ($msg_to_user =~ /^$user_name$/i ||
($msg_from_user =~ /^$user_name$/i &&
$msg_to_user ne "ALL")) {
$chat_buffer .= "<TR><TD>";
$chat_buffer .= "Private Msg To:" .
"</TD><TD>$msg_to_user</TD>" .
"</TR>\n";
}
The table is closed using the </TABLE> HTML tag, and then the body of

the message is read from the file inside
<BLOCKQUOTE> HTML tags. Each
line is filtered using the
HtmlFilter subroutine. In addition, each line is
printed with a
<BR> tag to show a line break.
$chat_buffer .= "</TABLE>\n";
$chat_buffer .= "<BLOCKQUOTE>\n";
while(<MSG>) {
$_ = &HtmlFilter($_);
$chat_buffer .= "$_<BR>";
}
When the message body is finished, the file is closed and the program
loops back to process another file unless the current message number
(
$x) has reached $high_message_number.
Chapter 26: WebChat
714
close(MSG);
$chat_buffer .= "\n";
}
$chat_buffer .= "</BLOCKQUOTE>\n";
} # End of IF msg is to all or just us
}
}
# End of IF we are not in the submit msg frame
# or simply printing the main frameset
# document
}
PROCESS LOGOFF

If the logoff button was pressed, the who file is deleted immediately
using unlink. The user will no longer show up on the occupants list.
if ($logoff ne "") {
$whofile = "$chat_room_dir/$session.who";
unlink($whofile);
}
Because the Web is connectionless, it is possible to stay online after
you “log off.” The ability to “log off” is presented as a means to allow
a group of people who follow chat room etiquette to gain an accurate
picture of who is in the chat room. It is not a security measure.
PRINT THE CHAT SCREEN
The final part of the main chat.cgi program is the printing of the chat
page. The logic contained in the
PrintChatScreen subroutine is complex,
because it must account for both frames and nonframes printing of the
chat messages and submit message form. An example of a new message
in the chat message frame appears in Figure 26.11.
&PrintChatScreen($chat_buffer, $refresh_rate,
$session, $chat_room, $setup,
$frames, $fmsgs, $fsubmit);
Chapter 26: WebChat
715
Figure 26.11 Example of a new message appearing in the chat message frame.
THE GETSESSIONINFO SUBROUTINE
The GetSessionInfo subroutine in the chat script retrieves information
about the user’s current session. This includes the username, E-mail
address, URL link, refresh rate, use of frames, and last read message
number. The routine starts by accepting the current session number and
data about whether we are currently using frames (
$frames) and, if so,

whether we are refreshing the submit message frame (
$fsubmit).
sub GetSessionInfo {
local($session, $fsubmit,$frames) = @_;
$session_file
, $temp, @fields, @f, $high_number, and $high_message are
declared local to the subroutine.
Chapter 26: WebChat
716
local($session_file);
local($temp,@fields, @f);
local($high_number, $high_message);
$session_file
appends a .dat extension to the session ID. This is the
name of the session file. Then the session file is opened in the $chat_ses-
sion_dir directory.
$session_file = "$session.dat";
open (SESSIONFILE, "$chat_session_dir/$session_file");
The session file is read using a while loop. The session file should consist
of one line of fields that are pipe-delimited. (The fields are separated by
the pipe (|) symbol.) Here is an example session file:
Gunther|| />The fields in the preceding session file are the username, E-mail address,
URL, automatic refresh rate (in seconds), number of messages to display,
and last read message number.
while (<SESSIONFILE>) {
$temp = $_;
}
A chop is added so that the last field does not have a hanging newline at
the end. (A file read typically reads the whole line including the newline
character that separates lines in a file.) The fields are separated into the

@fields array. Finally, the session file is closed.
chop($temp);
@fields = split(/\|/, $temp);
close (SESSIONFILE);
$high_message
is set to the highest message number in the current chat
room. This message number is used to overwrite the last read message
for the user. In other words, now that the user’s last read message num-
Chapter 26: WebChat
717
ber has been read to @fields from the session file, we update it with the
highest message number so that the next time the script runs, only the
latest messages will be displayed to the user.
$high_message = &GetHighMessageNumber;
@f
stores the contents of @fields as a temporary holder for the old session
values. Then the last field in the
@fields array is set equal to $high_mes-
sage
. This last field corresponds to the user’s last read message number.
@f = @fields;
@fields[@fields - 1] = $high_message;
@fields - 1 returns a number representing the number of the last
element of the
@fields array. @fields returns the total number of ele-
ments in the array, but because arrays start counting at zero instead
of 1, we subtract 1 from
@fields to get a reference to the last element
of the @fields array. This technique is used throughout the chapter.
If frames are not on and if we are not printing the submit portion of a

frame, the session file is updated with the new high message number. We
open the session file and write the new
@fields values to it.
if ($fsubmit ne "on" &&
$frames ne "on") {
open (SESSIONFILE,
">$chat_session_dir/$session_file");
print SESSIONFILE join ("\|", @fields);
print SESSIONFILE "\n";
close (SESSIONFILE);
}
Finally, the original session values in @f are returned, along with the cur-
rent high message number. This message number is returned because the
script must know up to what sequence number to display new messages.
(@f, $high_message);
} # End of GetSessionInfo
Chapter 26: WebChat
718
Because the user’s last read message number is set to $high_mes-
sage
, there is a chance that more messages might be posted to the
chat room while this script is processing the messages to display.
Although
$high_message is actually out of date with regard to the
true high message number, it is important to see that the user’s last
read message is in sync with the
$high_message number of mes-
sages that have been displayed to the user.
GETHIGHMESSAGENUMBER SUBROUTINE
The GetHighMessageNumber routine reads the current chat room directory

and returns the highest message number found. It uses
$last_file and
@files as locally declared variables to do this processing.
sub GetHighMessageNumber {
local($last_file, @files);
First, $chat_room_dir is opened and all the files are read. The grep com-
mand is used to filter in only files that have msg in the filename. In addi-
tion, the messages are sorted.
opendir(CHATDIR, "$chat_room_dir");
@files = sort(grep(/msg/, readdir(CHATDIR)));
closedir(CHATDIR);
If the number of files in the array is greater than zero, the highest mes-
sage number in the array is placed in
$last_file. If there are no files with
msg in the chat room directory,
$last_file is set to zero. Note that the
filenames are all six digits long and use leading zeros to pad the number.
if (@files > 0) {
$last_file = $files[@files - 1];
} else {
$last_file = "0000000";
}
The substr command is used to return the first six characters of the file-
name. Because the filenames contain six-digit numbers, this arrangement
effectively returns just the numeric portion of the message filename.
Chapter 26: WebChat
719
substr($last_file,0,6);
} # End of GetHighMessageNumber
T

HE MAKESESSIONFILE
SUBROUTINE
The MakeSessionFile routine creates the session file that stores the cur-
rent user information.
GetSessionInfo later uses this session file to
retrieve information about the currently logged on user every time the
current session ID is sent to the routine. This routine starts by accepting
a list of fields that make up the user information and then returns the
newly acquired session ID that is associated with the session file.
sub MakeSessionFile {
local(@fields) = @_;
local($session, $session_file);
The first thing MakeSessionFile does is to call a routine (RemoveOldSessions)
to remove old session files that are no longer being used. Then a new ses-
sion ID is generated by generating a random number.
The random number is first seeded in the
srand function by taking
the value of the process ID and current time variable and combining
them with the
or operator (|). This random number, the time, and the
process ID are converted to a long hexadecimal number that serves as
the new session ID. A hexadecimal number is made up of digits that
cover the numbers 0 through 9 and the letters A through F instead of the
digits found in the base 10 system, 0 through 9. The session filename
consists of the session ID plus a .dat extension.
&RemoveOldSessions;
srand($$|time);
$session = int(rand(60000));
$session = unpack("H*", pack("Nnn", time, $$, $session));
$session_file = "$session.dat";

Next, the session file is opened for creation in the directory specified by
the
$chat_session_dir variable, which has been set in chat.setup. The
Chapter 26: WebChat
720

×