チャット
#! /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;
}
}
〔 実行する 〕