フレーム版チャット

 掲示板スクリプトも、大体考えつく機能の搭載が終了しましたので、今度はチャットスクリプトの機能増強版を作って行きましょう。まず、書き込み記事を見やすくする為に、フレーム版にして書き込み欄と分けて表示するようなチャットスクリプトを作って見たいと思います。では、以下に必要なファイルを示します。f_chat.cgiはこのスクリプト本体です。f_chat.datは書き込み記事の保存用ファイルです。誰でも書き込みできるよう、パーミッションは「666」にして下さい。cgi-lib.plはデコード用のplファイルです。これは読み出し専用で構いません。以下は、これら3つのファイルを同じ場所に設置したものとします。

f_chat.cgi ・・・755 f_chat.dat ・・・666 cgi-lib.pl ・・・644

このチャットの機能の概略

 記事書き込み欄と記事表示部分とを、フレーム版にする事によって分割表示しています。ですから、過去の書き込み記事が参照し易く、チャットの参加人数が多くて発言のスピードが速い場合も、無理なく書き込み内容を確認する事が出来ます。又、リロード機能も付けましたので、一々更新しなくても表示記事の更新が出来ます。ついでに、お名前の色も選べるようにしました。同じ色だけでは、ちょっと寂しいですから(^^ゞ

スクリプトの内容

 では、実際のスクリプトの内容を見て行きましょう。

初期設定  
#!/usr/local/bin/perl うちのサーバーでは「#!/usr/bin/perl」です。
(この後、必ず1行空けること。)  
require './cgi-lib.pl'; cgi-lib.plライブラリの要求。同じディレクトリ内に置いていると想定。相対パスを使用。
$maxmessage = 30; 最大メッセージ数の指定
$cgifile = './f_chat.cgi';  
$datafile = './f_chat.dat';  
$title = 'フレーム版チャット'; タイトル名を指定
$txt_color = '#000000';  
$bg_color = '#CCFFCC';  
$refresh = 45; リロードの時間を設定。単位は秒。
#==============初期設定はここまで================  
メインの設定  
&ReadParse(*in); 連想配列名の指定
if ($in{ 'mode' } eq "") { &MakeFrame; exit(0); } 変数$in{ 'mode' }の値によって処理を分岐。
elsif ($in{ 'mode' } eq "input") { &InputPage; exit(0); }  
elsif ($in{ 'mode' } eq "output") { &OutputPage; exit(0); }  
elsif ($in{ 'mode' } eq "post") { &PostMessage; exit(0); }  
else { exit(0); }  
#==============フレーム生成サブルーチン==============  
sub MakeFrame {  
 print "Content-type: text/html\n\n";  
 print <<END_OF_FRAMEPAGE; END_OF_FRAMEPAGEは、ラベルです。
<HTML><HEAD><TITLE>$title</TITLE></HEAD>  
<FRAMESET rows="25%, 75%"> フレームの上下の比率を設定。
<FRAME src="$cgifile?mode=input" name="up">  
<FRAME src="$cgifile?mode=output" name="bottom">  
</FRAMESET></HTML>  
END_OF_FRAMEPAGE ここまで「print」が活きている。
}  
#===========データ入力ページ生成サブルーチン===========  
sub InputPage {  
 print "Content-type: text/html\n\n";  
 print <<END_OF_FIRSTINPUT; END_OF_FIRSTINPUTは、ラベルです。
<HTML><HEAD><TITLE>$title</TITLE></HEAD>  
<BODY text=$txt_color bgcolor=$bg_color>  
<H3>$title</H3>  
<FORM name=form1 method=POST action=$cgifile target="bottom">  
<INPUT type=hidden name=mode value=post>  
お名前:<INPUT type=text name=name size=20 value=\"$name\">  
お名前の色:<input type=radio name=ncolor value=#0000ff checked><font color=#0000ff><b>青 </b></font> お名前の文字色を指定。
<input type=radio name=ncolor value=#ff0000><font color=#ff0000><b>赤 </b></font>  
<input type=radio name=ncolor value=#008000><font color=#008000><b>緑 </b></font>  
<input type=radio name=ncolor value=#800000><font color=#800000><b>茶 </b></font>  
<input type=radio name=ncolor value=#800080><font color=#800080><b>紫</b></font><BR> ここで改行。
メッセージ:<INPUT type=text name=message size=70>  
<INPUT type=submit value="送信"> リロード:$refresh 秒 リロードの時間も表示。
</FORM></BODY></HTML>  
END_OF_FIRSTINPUT ここまで「print」が活きている。
}  
#===========書き込み記事表示サブルーチン===========  
sub OutputPage {  
 print "Content-type: text/html\n\n";  
 print "<HTML><HEAD><TITLE>$title</TITLE></HEAD>\n";  
 print "<META HTTP-EQUIV=refresh CONTENT=$refresh;URL=$cgifile?mode=output>\n"; オートリロード処理
 print "<BODY text=$txt_color bgcolor= $bg_color>\n";  
 print "<SCRIPT language=\"JavaScript\">\n"; JavaScriptを使用。
 print "parent.up.document.form1.message.value=\"\";\n";  
 print "</SCRIPT>\n";  
 open (FILE, "$datafile");  
 while (<FILE>) { ◆ループ処理・・・<FILE>の中身がある間、ファイルの内容をブラウザに表示。
  print;
 }  
 close (FILE);  
 print "</BODY></HTML>\n";  
}  
#===========メッセージ投稿サブルーチン=============  
sub PostMessage {  
 $name = $in{'name'}; 各変数の値を取得。
 $ncolor = $in{'ncolor'};  
 $message = $in{'message'};  
 if ($message ne "") { 「メッセージが空でなければ」の意味。
  ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); ★localtime関数<ローカル時間> = localtime[time形式の値]」・・・戻り値はローカル時間が返ってきますが、この時スカラー型の変数で受け取るか、配列で受け取るかで戻ってくる値の形式が異なります。
  @dayname = (San, Mon, Tue, Wed, Thr, Fri, Sat); 曜日の指定
  $date = sprintf("%04d/%02d/%02d %s %02d:%02d:%02d", $year+1900, $mon+1, $mday, @dayname[$wday], $hour, $min, $sec); ★sprintf関数<フォーマット済み文字列> = sprintf(フォーマット定義,文字)」・・・フォーマットの定義に従って文字列のフォーマットを行い返します。
  $tmp = "<FONT color=$ncolor><B>$name</B></FONT>"; 変数$tmpにデータを順々に並べて格納する。
  $tmp = $tmp . " : $message" ;  
  $tmp = $tmp . "<FONT size=-1 color='green'> ($date)</FONT><HR>\n"; <HR>は水平線。
  open(FILE, "$datafile"); ファイルを読み込みモードで開く。
  @allbody = <FILE>;  
  close(FILE);  
  $num = unshift (@allbody, $tmp); ★unshift関数unshift <配列>, <追加する要素>」・・・配列の先頭に要素を追加します。
  if ($num > $maxmessage) { 「もしデータ数が$maxmessageより大きければ」の意味。
   pop @allbody; ★pop関数pop(配列変数)」・・・配列変数の最後の要素を取り除いて返します。この時、配列の要素は1つ減ります。
  }  
  open(FILE, ">$datafile"); ファイルを書き込みモードで開く。
  print FILE @allbody;  
  close(FILE);  
 }  
 &OutputPage;  
}  

スクリプトの全体像

 分かり易いように、上のサンプルスクリプトのソース全体を示します。実際には処理の流れがつかみ易いように、タブで字下げをして処理の塊を区別できるようにしています。

#!/usr/local/bin/perl

require './cgi-lib.pl';
$maxmessage = 30; #最大メッセージ数
$cgifile = './f_chat.cgi';
$datafile = './f_chat.dat';
$title = 'フレーム版チャット';
$txt_color = '#000000';
$bg_color = '#CCFFCC';
$refresh = 45;
#==============初期設定はここまで===================
&ReadParse(*in);
if ($in{'mode'} eq "") { &MakeFrame; exit(0); }
elsif ($in{'mode'} eq "input") { &InputPage; exit(0); }
elsif ($in{'mode'} eq "output") { &OutputPage; exit(0); }
elsif ($in{'mode'} eq "post") { &PostMessage; exit(0); }
else { exit(0);}
#==============フレーム生成サブルーチン================
sub MakeFrame {
 print "Content-type: text/html\n\n";
 print <<END_OF_FRAMEPAGE;
 <HTML><HEAD><TITLE>$title</TITLE></HEAD>
 <FRAMESET rows="25%,75%">
 <FRAME src="$cgifile?mode=input" name="up">
 <FRAME src="$cgifile?mode=output" name="bottom">
 </FRAMESET></HTML>
 END_OF_FRAMEPAGE
}
#==============データ入力ページ生成サブルーチン=================
sub InputPage {
 print "Content-type: text/html\n\n";
 print <<END_OF_FIRSTINPUT;
 <HTML><HEAD><TITLE>$title</TITLE></HEAD>
 <BODY text=$txt_color bgcolor=$bg_color>
 <H3>$title</H3>
 <FORM name=form1 method=POST action=$cgifile target="bottom">
 <INPUT type=hidden name=mode value=post>
 お名前:<INPUT type=text name=name size=20>
 お名前の色:<input type=radio name=ncolor value=#0000ff checked><font color=#0000ff><b>青 </b></font>
 <input type=radio name=ncolor value=#ff0000><font color=#ff0000><b>赤 </b></font>
 <input type=radio name=ncolor value=#008000><font color=#008000><b>緑 </b></font>
 <input type=radio name=ncolor value=#800000><font color=#800000><b>茶 </b></font>
 <input type=radio name=ncolor value=#800080><font color=#800080><b>紫</b></font><BR>
 メッセージ:<INPUT type=text name=message size=70>
 <INPUT type=submit value="送信"> リロード:$refresh 秒
 </FORM></BODY></HTML>
 END_OF_FIRSTINPUT
}
#==============書き込み記事表示サブルーチン================
sub OutputPage {
 print "Content-type: text/html\n\n";
 print "<HTML><HEAD><TITLE>$title</TITLE></HEAD>\n";
 print "<META HTTP-EQUIV=refresh CONTENT=$refresh;URL=$cgifile?mode=output>\n";
 print "<BODY text=$txt_color bgcolor=$bg_color>\n";
 print "<SCRIPT Language=\"JavaScript\">\n";
 print "parent.up.document.form1.message.value=\"\";\n";
 print "</SCRIPT>\n";
 open(FILE, "$datafile");
 while(<FILE>) {
  print;
 }
 close(FILE);
 print "</BODY></HTML>\n";
}
#==============メッセージ投稿サブルーチン===============
sub PostMessage {
 $name = $in{'name'};
 $ncolor = $in{'ncolor'};
 $message = $in{'message'};
 if ($message ne "") {
  ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
  @dayname = (San, Mon, Tue, Wed, Thr, Fri, Sat);
  $date = sprintf("%04d/%02d/%02d %s %02d:%02d:%02d", $year+1900, $mon+1, $mday, @dayname[$wday], $hour, $min, $sec);
  @dayname = (San, Mon, Tue, Wed, Thr, Fri, Sat);
  $date = sprintf("%04d/%02d/%02d %s %02d:%02d:%02d", $year+1900, $mon+1, $mday, @dayname[$wday], $hour, $min, $sec);
  $tmp = "<FONT color=$ncolor><B>$name</B></FONT>";
  $tmp = $tmp . " : $message";
  $tmp = $tmp . "<FONT size=-1 color='green'> ($date)</FONT><HR>\n";
  open(FILE, "$datafile");
  @allbody = <FILE>;
  close(FILE);
  $num = unshift (@allbody, $tmp);
  if ($num > $maxmessage) {
   pop @allbody;
  }
  open(FILE, ">$datafile");
  print FILE @allbody;
  close(FILE);
 }
 &OutputPage;
}

 *上の内容をこのまま複写しても動きません。何故なら、各コードの行頭のスペースが半角でないからです。ご注意下さい。

スペシャル掲示板 前へ

HOME

次へ