<< Webチャット >>
じゃぁ調子に乗って今度はWebチャット作っちゃえ!
しかもフレームを使っちゃいます。
フレームを使う場合、それを定義するHTMLファイルが必要なので、
サンプルを「.txt」の形式で置いておきます。もちろん実際使用するときは
拡張子を「.html」に変えてね。
それではメモ帳を起動!ファイルに名前をつけようね。
「chat.cgi」とか。
メモ帳で編集してる間は、拡張子を「.txt」にしておくといいかもね。
じゃ、始めましょうか。
そうそう、「一行伝言板」で説明したことは、いちいち
説明しなおさないと思うので、そっちも必ず見てね。
| #!/usr/local/bin/perl |
「一行伝言板」でも説明しましたが、この部分は、
Perl(CGIを動かす言語)のありかを示すものです。
あなたの加入しているプロバイダによって違うので注意!
(ビワローブなら、このままで大丈夫です。)
ただ、これは必ず一行目に置くこと。この行の前に改行だけの行とかあっても
エラーが出ますよ。
| # chat v0.1 by 1999 Deihaz |
はい、「#」はコメントの記号です。
プログラムはその部分を無視してくれます。
(一行目の「#!」は例外なので省略不可ですが。)
この行では、チャットの名前・バージョン・著作権を明示してます。
| require 'jcode.pl'; |
はい、日本語チャットにしたいならこれは必須ですね。
「jcode.txt」を置いておきますので、DLしたあと
拡張子を「.pl」にかえてご利用ください。
# 設定 $title = 'Webチャット'; $homepage = 'http://www.biwa.ne.jp/~bighair/'; $max = 25; $method = 'POST'; $script = 'chat.cgi'; $logfile = 'chat.log'; # 設定終わり |
ここは、いろんな準備をしているところです。
「$」というのは、「変数」を意味しております。
詳しくは、「一行伝言板」の説明を参考にしてね。
ちなみに、変数の名前は大文字と小文字が区別されるのでご注意を。
$title:チャットの名前
$homepage:ホームページのアドレス(チャットから脱出するためのアドレス)
$max:メッセージを何行蓄えておくか。つまりこれだと25行
$method:データを送信する方法。「POST」か「GET」ですな
$script:このスクリプトのファイル名
$logfile:ログを保存しておくためのファイルのファイル名
$maxに入れる「25」は数値ですから、「'」では囲みません。
「POST」「GET」については、詳しく説明しませんが、
まあ必要がない限り、「POST」にしておいて下され。
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}
else {
$buffer = $ENV{'QUERY_STRING'};
}
|
はい、お決まりの部分です。
フォームから送られてきたデータを「POST」「GET」で場合分けして、
「$buffer」という変数に入れているわけです。
では「if」のおさらいね。
if (条件1) {処理A} elsif (条件2) {処理B} else {処理C}
もし条件1が成立しているなら処理Aを実行し、
そうでなくとも、もし条件2が成立しているなら処理Bを実行し、
どれにもあてはまらなければ、処理Cを実行する、という構文でした。
| &decode; |
「&」は、サブルーチンに飛んでいく記号でした。
この場合、「&decode;」ですから、スクリプトの後ろの方の
sub decode {・・・}
に飛んでいくわけですな。
ちなみに「sub decode」では、送られてきたデータを使えるように変換するという
作業をしております。
サブルーチンが終わると、またここに戻ってきます。
if ($form{'mode'} eq 'init') {
&initform;
}
elsif ($form{'mode'} eq 'enter') {
&msgform;
}
elsif (($form{'mode'} eq 'msg') and $form{'comment'}) {
®ist;
}
elsif ($form{'mode'} eq 'leave') {
&finish;
}
&viewlog;
|
はい。「$form{'mode'}」の内容によって行き先を変えてます。
「init」なら、「sub initform」(名前入力フォームを表示)へ、
「enter」なら、「sub msgform」(メッセージ入力フォーム表示)へ、
「msg」なら、「sub regist」(ファイルへ書き込む)へ、
「leave」なら、「sub finish」(退室処理)へ飛びます。
その後、「sub viewlog」に飛ぶわけですが、
「&initform;」「&msgform;」「&finish;」はここには戻ってきませんので、
「&viewlog;」にたどり着くのは、「®ist;」に行った場合と、if文がすべて
成立しなかった場合だけです。
sub initform {
&header1;
&header2;
print <<"EOH";
<p><font size="5" color="blue"><b>$title</b></font></p>
<table><tr>
<td><form method="$method" action="$script" target="form">
<p><input type="hidden" name="mode" value="enter">
<input type="hidden" name="reload" value="10">
お名前(タグ可)<input type="text" name="name" size="20"><br>
<input type="submit" value="入室してみる"></p>
</form></td>
<td><form action="$homepage" target="_top">
<input type="submit" value="ホームへ戻る"></p>
</form></td>
</tr></table>
</body>
</html>
EOH
exit;
}
|
さて、サブルーチンの解説にいきますか。
sub initform {・・・}は、サブルーチンの宣言です。
「&initform」から、ここに飛んでくるわけですね〜。
で、今回は「&header1;」「&header2;」と、
ヘッダを記述するサブルーチンが2つあるけど、
JavaScriptを使うときにこの2つの間にはさめるように
2つに分けただけだよん。
「print <<"EOH";」ですが、
この次の行から「EOH」まで(ヒアドキュメントという)を、
まとめて出力するという命令であります。
「EOH」が出てくるまではHTMLの記述です。
もちろん、このまま出力されるので、好きなようにいじることが出来ますよん。
ここでは、名前入力フォームの記述をしています。
<form>タグに、「target」というのが出てきてますが、
これは<a href=・・・>で使う「target」と役目は一緒です。
このチャットではフレームを使用しているので、「target」の指定が
重要になってくるわけです。
「target="form"」で、次のターゲットを上半分のフレームにします。
「target="_top"」で、フレームを解除します。
ついでに「target="_blank"」だと、新しいウィンドウで開きます。
はい。フォームを出力すれば後は用はないので、
「exit;」でCGIの実行を終わります。
「ついでにログも表示させればいいのに」と思う方もいらっしゃるでしょうが、
CGIが一度に出力できるHTMLは1ページ分だけなんですねぇ。
だからこのサブルーチンはこれで終わり。
sub msgform {
®ist('in');
&header1;
print <<"EOH";
<SCRIPT LANGUAGE="JavaScript">
<!--
function clr() {
document.mform.comment.value = "";
document.mform.comment.focus();
}
// -->
</SCRIPT>
EOH
&header2;
print <<"EOH";
<p><font size="5" color="blue"><b>$title</b></font></p>
<table><tr>
<td><form name="mform" method="$method" action="$script" target="log" onSubmit="setTimeout("clr()", 10)">
<p><input type="hidden" name="mode" value="msg">
<input type="hidden" name="name" value="$form{'name'}">
台詞:<input type="text" name="comment" size="50"><br>
<input type="submit" value="発言/リロード"><input type="reset" value="クリア">
リロード:
<select name="reload">
<option value="0">手動
<option value="10" selected>10秒
<option value="30">30秒
<option value="60">1分
</select></p>
</form></td>
<td><form method="$method" action="$script" target="form">
<input type="hidden" name="mode" value="leave">
<input type="hidden" name="name" value="$form{'name'}">
<input type="submit" value="退室しとく">
</form></td>
</tr></table>
</body>
</html>
EOH
exit;
}
|
うわ〜長いねぇ。
でもメッセージ入力フォームを書いてるだけだから、
むろんHTML分かってる人は、理解出来る事でしょう。
JavaScriptは、発言自動消去をするためのものです。
理解できない人はあまり気にしないように。つまりそこはいじらないように。
リロードの辺りとかは、「option value」のところの数字を
てきとーにいじって、好きな時間でリロード出来るようにするとよいでしょう。
はい、説明終わるよ!
sub viewlog {
open LOG, "$logfile" or &error('Logfile cannot be opened');
@lines = <LOG>;
close LOG;
&header1;
if ($form{'reload'} != 0) {
print qq(<META HTTP-EQUIV="refresh" CONTENT="$form{'reload'};URL=$script?reload=$form{'reload'}">\n);
}
&header2;
print qq(<div align="right">リロード:);
if ($form{'reload'} == 0) {
print qq(手動);
}
else {
print qq($form{'reload'}秒);
}
print qq(\n</div>\n);
foreach $line (@lines) {
($date, $name, $comm) = split(/\"/, $line);
print qq(<b>[$name]</b> $comm <small>\($date\)</small><br>\n);
}
print qq(</body>\n</html>\n);
exit;
}
|
これは、ログの表示ね。
一行伝言板でやったのとほぼ一緒です。
違うのは、自動リロードをするかしないかの部分だけです。
sub regist {
($sec, $min, $hour, $mday, $mon, $year) = localtime(time);
$mon++;
if ($hour < 10) {
$hour= "0$hour";
}
if ($min < 10) {
$min = "0$min";
}
if ($sec < 10) {
$sec = "0$sec";
}
$date = "$mon/$mday\ $hour:$min:$sec";
if ($_[0] eq 'in') {
$form{'comment'} = "<b><i>$form{'name'}さんが来ました</i></b>";
$logname = '<font color=gray><i>謎の声</i></font>';
}
elsif ($_[0] eq 'fin') {
$form{'comment'} = "<b><i>$form{'name'}さんは去りました</i></b>";
$logname = '<font color=gray><i>謎の声</i></font>';
}
else {
$logname = "$form{'name'}";
}
open LOG, "$logfile" or &error('Logfile cannot be opened');
@lines = <LOG>;
close LOG;
@newlines = @lines;
unshift (@newlines, "$date\"$logname\"$form{'comment'}\"$ENV{'REMOTE_HOST'}\n");
if (@newlines > $max) {
pop (@newlines);
}
open LOG, ">$logfile" or &error('Logfile cannot be written');
eval 'flock(LOG, 2);';
print LOG @newlines;
close LOG;
}
|
はい。ファイルへの書き込みサブルーチンです。
入室時、退室時には、「来ました」「去りました」などのメッセージを
書き込むようになってます。
sub finish {
®ist('fin');
&header1;
&header2;
print qq(<p>$form{'name'}さん、また来て下さい。</p>\n);
print qq(<p><a href="$homepage" target="_top">ホームページへ</a></p>\n);
print qq(</body>\n</html>\n);
exit;
}
|
退室処理。
「®ist('fin')」で、「〜は去りました」を表示してます。
あとはあいさつをして、「exit;」で終わってます。
sub header1 {
print qq(Content-type: text/html\n\n);
print qq(<html>\n<head>\n);
}
sub header2 {
print qq(</head>\n);
print qq(<body text="#000000" bgcolor="#EEEEFF">\n);
}
|
はい。HTMLを表示する頭の部分ですね。
JavaScriptやリロードの設定がある場合は、
「header1」と「header2」の間にそれがはさまります。
sub decode {
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s/\"//g;
$value =~ s/<!--(.|\n)*-->//g;
$value =~ s/<html(.|\n)*>//ig;
$value =~ s/<body(.|\n)*>//ig;
$value =~ s/<script(.|\n)*>//ig;
$value =~ s/<table(.|\n)*>//ig;
$value =~ s/<form(.|\n)*>//ig;
$value =~ s/<img(.|\n)*>//ig;
$value =~ s/\r\n//g;
$value =~ s/\r|\n//g;
&jcode'convert(*value, 'sjis');
$form{$name} = $value;
}
if ($form{'name'} eq '') {
$form{'name'} = '???';
}
}
|
え〜と、伝言板にも出てきた、デコード処理です。
今回は、名前の入力がなかった場合、名前を強制的に「???」にしています。
「???」を「だれかさん」とかにしてみるのも面白いかも。
sub error {
&header1;
&header2;
print qq(<font color=red><p>システムエラーが発生しました!</p>\n);
print qq(<p><b>$_[0]</b></p></font>\n);
print qq(</body>\n</html>\n);
exit;
}
|
おなじみエラー処理です。
伝言板のやつとまったく同じ事をやっとります。
さて、ログファイル「chat.log」も作っておきましょう。
メモ帳などで空のファイルを作り、ファイル名を「chat.log」に変更するだけです。
「chat.cgi」をCGIサーバにアップするときに一緒にアップしましょ〜ね。
はいお疲れ様。どうでしたか?
これでチャットも出来ました。
ぜひ使いやすいチャットを研究して、あなたのHPに設置しましょう!