チャット
#! /usr/local/bin/perl # 設定 $FILE = './dat/chat.dat'; # 発言保存ファイル $INFILE = './dat/chatin.dat'; # 参加者保存ファイル $MAX = 100; # 保存件数 $NAMEMAX = 10; # 名前文字数制限(全角) $TEXTMAX = 50; # 発言文字数制限(全角) $REFRESH = 50; # 再読み込み時間(秒) $DELETE = 10 * 60; # 参加者自動削除時間(秒) $time = time; # 日時取得 loadForm(); # フォームデータ取り込み if($FORM{'frame'} eq "input") { frameInput(); # 入力用フレームを表示 } elsif($FORM{'frame'} eq "view") { frameView(); # 表示用フレームを表示 } else { frameSet(); # フレームセット } exit; #================================================ フレームセット sub frameSet { print qq(Content-type: text/html; charset=Shift_JIS\n\n); print <<" END"; <html> <head> <title>チャット</title> <frameset border="0" rows="85%,*"> <frame name="view" src="$ENV{SCRIPT_NAME}?frame=view"> <frame name="input" src="$ENV{SCRIPT_NAME}?frame=input"> </frameset> </head> </html> END } #================================================ 入力用フレームを表示 sub frameInput { my ($i); if($FORM{'mode'}) { loadData(); # 参加者・発言データ読み込み } print qq(Content-type: text/html; charset=Shift_JIS\n\n); print <<" END"; <html> <head> <title>チャット</title> <style type="text/css"> <!-- body, form { margin: 0px; } table { width: 100%; text-align: center; } //--> </style> <script language="JavaScript"> <!-- function namefocus() { // ページ表示後に名前入力欄にカーソルを自動的に移動 document.inputname.name.focus() } function textfocus() { // ページ表示後に発言入力欄にカーソルを自動的に移動 document.inputtext.text.focus() } function textsubmit() { // 発言後(0.5秒後)に入力欄をリセットしカーソルを移動 setTimeout('document.inputtext.reset.click(); textfocus()', 500) } //--> </script> </head> END if($FORM{'name'} eq "" or $FORM{'mode'} eq "out" or $error) { # 名前入力ページ表示 print <<" END"; <body bgcolor="#ffffcc" onLoad="namefocus()"> <hr color="#ff9933"> <table> <tr> <td> <form name="inputname" action="$ENV{'SCRIPT_NAME'}" method="POST"> 名前($NAMEMAX文字以内): <input type="text" name="name" size="70" maxlength="$NAMEMAX" value="$FORM{'name'}"> <input type="submit" value="参加する(Enter)"> <input type="hidden" name="frame" value="input"> <input type="hidden" name="mode" value="in"> </form> </td> </tr> </table> END } else { # 発言入力ページ表示 print <<" END"; <body bgcolor="#ffffcc" onLoad="textfocus()"> <hr color="#ff9933"> <table> <tr> <td> <form name="inputtext" action="$ENV{'SCRIPT_NAME'}" method="POST" target="view" onSubmit="textsubmit()"> $FORM{'name'}: <input type="text" name="text" size="70" maxlength="$TEXTMAX"> <input type="submit" value="発言する(Enter)"> <input type="reset" name="reset" value="リセット" onClick="textfocus()"> <input type="hidden" name="frame" value="view"> <input type="hidden" name="mode" value="write"> <input type="hidden" name="name" value="$FORM{'name'}"> </form> </td> <td> <a href="$ENV{'SCRIPT_NAME'}?frame=view" target="view" onClick="textfocus()">更新(Enter)</a> </td> <td> <form action="$ENV{'SCRIPT_NAME'}" method="POST"> <input type="submit" value="退出する"> <input type="hidden" name="frame" value="input"> <input type="hidden" name="mode" value="out"> <input type="hidden" name="name" value="$FORM{'name'}"> </form> </td> </tr> </table> END } if($error) { # エラーメッセージを表示 print qq(<font color="red">※$error</font>\n); } print <<" END"; </body> </html> END } #================================================ 表示用フレームを表示 sub frameView { my ($i); loadData(); # 参加者・発言データ読み込み print qq(Content-type: text/html; charset=Shift_JIS\n\n); print <<" END"; <html> <head> <meta http-equiv="refresh" content="$REFRESH;url=$ENV{'SCRIPT_NAME'}?frame=view"> <title>チャット</title> <style type="text/css"> <!-- body { margin: 0px; } table { margin: 0px 20px; } //--> </style> </head> <body bgcolor="#ffffcc"> <hr color="#ff9933"> END printf qq(参加者: \n); for($i = 0 ; $i < @IN ; $i++) { # 参加者データ表示 my ($tm, $name) = split(/\t/, $IN[$i]); if($tm + $DELETE >= $time) { # 自動削除時間を経過した参加者以外を表示 print qq($name ); } } print <<" END"; <br> <hr color="#ff9933"> <table> END for($i = 0 ; $i < @DATA ; $i++) { # 発言データ表示 my ($tm, $name, $text) = split(/\t/, $DATA[$i]); my ($sec, $min, $hour, $date, $mon, $year, $day) = localtime($tm); print qq(<tr>); print qq(<td align="right" valign="top" nowrap><font size="-1">$name≫</font></td>); print qq(<td><b>$text</b> ); printf qq(<font size="-2">[%02d/%02d %02d:%02d]</font></td>), ++$mon, $date, $hour, $min; print qq(</tr>); } print <<" END"; </table> </body> </html> END } #================================================ 発言データ・参加者データ読み込み sub loadData { my ($i); open(FILE, "<$FILE"); # 発言データ読み込み eval{ flock(FILE, 1) }; @DATA = <FILE>; close FILE; open(FILE, "<$INFILE"); # 参加者データ読み込み eval{ flock(FILE, 1) }; @IN = <FILE>; close FILE; if($FORM{'mode'}) { if($FORM{'mode'} eq 'in') { # 参加 if($FORM{'name'} and length($FORM{'name'}) <= $NAMEMAX * 2) { # 名前入力がある場合 if($FORM{'name'} eq "管理人") { # 使用禁止の名前をチェック $error = "『$FORM{'name'}』では参加できません。" . "別の名前で参加してください。"; return; } for($i = 0 ; $i < @IN ; $i++) { # 名前の重複チェック my ($tm, $name) = split(/\t/, $IN[$i]); if($name eq $FORM{'name'}) { $error = "『$FORM{'name'}』さんは現在参加中です。" . "別の名前で参加してください。"; return; } } push @IN, "$time\t$FORM{'name'}\t\n"; unshift @DATA, "$time\t管理人\t『$FORM{'name'}』さんが参加されます。\t\n"; } else { # 空欄の場合 戻る $error = "名前を入力してください。"; return; } } elsif($FORM{'mode'} eq 'out') { # 退出 for($i = 0 ; $i < @IN ; $i++) { my ($tm, $name) = split(/\t/, $IN[$i]); if($name eq $FORM{'name'}) { # 退出者データを探す splice @IN, $i, 1; # 参加者データから削除 unshift @DATA, "$time\t管理人\t『$FORM{'name'}』さんが退出しました。\t\n"; last; } } } elsif($FORM{'mode'} eq 'write') { # 発言 if($FORM{'text'} and length($FORM{'text'}) <= $TEXTMAX * 2) { # 発言入力がある場合 if(@IN > 0) { for($i = 0 ; $i < @IN ; $i++) { my ($tm, $name) = split(/\t/, $IN[$i]); if($name eq $FORM{'name'}) { # 参加者データを探す $IN[$i] = "$time\t$FORM{'name'}\t\n"; # 参加者データ更新 unshift @DATA, "$time\t$FORM{'name'}\t$FORM{'text'}\t\n"; last; } } } } else { # 空欄の場合 戻る(ページ更新のみ) return; } } while(@DATA > $MAX) { # 保存件数以上のデータを削除 pop @DATA; } open(FILE, ">$FILE"); # 発言データ書き込み(保存) eval{ flock(FILE, 2) }; print FILE @DATA; close FILE; for($i = 0 ; $i < @IN ; $i++) { # 自動削除 my ($tm, $name) = split(/\t/, $IN[$i]); if($tm + $DELETE < $time) { # 自動削除時間経過の参加者を削除 splice @IN, $i, 1; $i--; } } open(FILE, ">$INFILE"); # 参加者データ書き込み(保存) eval{ flock(FILE, 2) }; print FILE @IN; close FILE; } } #================================================ フォームデータ取り込み sub loadForm { my ($query, $pair); if($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN, $query, $ENV{'CONTENT_LENGTH'}); } else { $query = $ENV{'QUERY_STRING'}; } foreach $pair (split(/&/, $query)) { my ($key, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/chr(hex($1))/eg; $value =~ s/&/&/g; $value =~ s/</</g; $value =~ s/>/>/g; $value =~ s/\s//g; $value =~ s/\x81\x40//g; $value =~ s/\x0D\x0A//g; $value =~ tr/\t//; $FORM{$key} = $value; } }
〔 実行する 〕