掲示板をつくる

■ 掲示板をつくる

◆ 掲示板をつくる

CGI の応用編として、CGI による掲示板を実際に作っていきましょう。作成するのは次の 2つのファイルです。

ファイル説明
bbs.cgi掲示板の CGI 本体です。内容は下記で説明します。通常の CGI の設置方法に従って設置してください。
bbs.txt掲示板に書き込まれたメッセージを記録するファイルです。最初は中身は空でかまいません。bbs.txt と同じフォルダに設置し、CGI実行ユーザ が書き込み可能(下記参照)となるように設定してください。
◆ CGI実行ユーザが書き込み可能にするには

UNIX系 OS で、CGI が nobody などの権限で動作する場合は、bbs.txt の パーミッション を 666(rw-rw-rw-)にしてください。CGI が自分自身の権限で動作する場合は、644(rw-r--r--)にしてください。Windows NT系 + IIS の場合は IUSER_マシン名 のユーザに対して書き込み権を設定してください。Windows 95系の場合は、特に設定は必要ありません。

◆ 実行例
★★ 簡易掲示板 ★★
名前:

たなか 2002/06/04 18:44:53
簡易掲示板です。

すずき 2002/06/04 20:08:21
こんにちわ。

やまだ 2002/06/04 22:11:02
おじゃまします。
◆ bbs.cgi の中身

bbs.cgi の内容を次のように作成してください。

bbs.cgi
#!/usr/bin/perl

require "jcode.pl";  # 漢字コード変換ライブラリを読み込む(→ jcode.pl)

# 漢字コード
# (EUCにする場合は、$charset="euc-jp" と $kcode="euc" を設定)
$charset = "Shift_JIS";
$kcode = "sjis";

# 現在の時刻($time)を求めておく
($sec, $min, $hour, $mday, $mon, $year) = localtime();
$time = sprintf("%04d/%02d/%02d %02d:%02d:%02d",
    $year + 1900, $mon + 1, $mday, $hour, $min, $sec);

# フォームデータを読み込む(→ CGIでフォームに・・・)
read(STDIN, $buf, $ENV{'CONTENT_LENGTH'});
foreach (split(/&/, $buf)) {
    ($name, $value) = split(/=/);
    $value =~ tr/+/ /;
    $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg;
    $value =~ s/&/&/g;
    $value =~ s/</&lt;/g;
    $value =~ s/>/&gt;/g;
    $value =~ s/"/&quot;/g;
    jcode::convert(*value, $kcode);    # 漢字コードを変換しておく
    $FORM{$name} = $value;
}

# メッセージの改行を <br> に置換する
$FORM{'MESG'} =~ s/(\r\n|\n|\r)/<br>\n/g;

# ファイルに追加書き込みする
if ($FORM{'MESG'} ne "") {
    $msg = "<hr>\n"
         . "<div class=header>\n"
         . "<span class=name>$FORM{'NAME'}</span>\n"
         . "<span class=time>$time</span>\n"
         . "</div>\n"
         . "<div class=mesg>$FORM{'MESG'}</div>\n";
    open(OUT, ">> bbs.txt") || ErrorExit("書き込み失敗。");
    print OUT $msg || ErrorExit("書き込み失敗。");
    close(OUT) || ErrorExit("書き込み失敗。");
}
# ファイルの内容を読みこむ
open(IN, "bbs.txt");
@body = <IN>;
close(IN);

# 結果を書き出す
print <<END_OF_DATA;
Content-type: text/html

<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=$charset">
<title>簡易掲示板</title>
<style type="text/css">
<!--
.name { color: #ff0000; font-weight: bold; }
.time { color: #666666; }
.mesg { color: #666600; }
-->
</style>
</head>
<body>
<h3>★★ 簡易掲示板 ★★</h3>
<form method="POST" action="$ENV{'SCRIPT_NAME'}">
<div>名前:<input type="text" name="NAME"></div>
<div><textarea name="MESG" cols=40 rows=6></textarea></div>
<div><input type="submit" value="送信"></div>
</form>
@body
<hr>
</body>
</html>
END_OF_DATA

■ 掲示板の書き込みを新しいもの順に並べる

◆ 書き込みを新しいもの順に並べる

メッセージは書きこんだ順に下側に追加されていきますが、これを、新しいものほど上に表示させるようにするには、bbs.cgi の「# ファイルに追加書き込みする」の個所を上記のものに置き換えてください。

# ファイルに追加書き込みする
if ($FORM{'MESG'} ne "") {
    open(FILE, "+< bbs.txt") || ErrorExit("書き込み失敗");
    @lines = <FILE>;
    unshift(@lines,
        "<hr>\n",
        "<div class=header>\n",
        "<span class=name>$FORM{'NAME'}</span>\n",
        "<span class=time>$time</span>\n",
        "</div>\n",
        "<div class=mesg>$FORM{'MESG'}</div>\n");
    seek(FILE, 0, 0);
    print(FILE @lines) || ErrorExit("書き込み失敗");
    close(FILE) || ErrorExit("書き込み失敗");
}
◆ 説明

Perl ではファイルの先頭に追記するという手段は無いので、ファイルの内容を配列としてすべて読み取り、その先頭に新メッセージを追加し、再度ファイルにすべて書きこむことにより実現しています。

■ 掲示板の再表示で二重投稿されないようにする

◆ メッセージ二重投稿の防止

ブラウザで再表示を行うと、書き込みが二重に投稿されてしまうことがあります。これを防ぐには、「# ファイルの内容を読みこむ」の前に上記の記述を挿入してください。

# 二重投稿を抑制する
if ($FORM{'MESG'} ne "") {
    print "Location: http://$ENV{'HTTP_HOST'}$ENV{'SCRIPT_NAME'}\n\n";
    exit(0);
}
◆ 説明

CGI の Content-type ヘッダの代わりに Location ヘッダが書き出されると、Location で指定したページにジャンプします。ジャンプする際に、フォームに書きこんだデータを破棄するため、再読み込みしてもフォームデータが二重投稿されなくなります。


Copyright (C) 2002 杜甫々