フリーCGIスクリプト配布サイト。
これまで作成したプログラムを改造し、今回は掲示板を作成してみます。プログラムは少々複雑になりますが、じっくりと処理の流れを追っていってください。
前回までの内容で、フォームから入力された内容を順に記録していくプログラムが作成できたので、まずは入力された内容を一覧表示するプログラムを作成してみます。
投稿内容は一件を一行とし、ハンドルネームとメッセージをタブ区切りで記録するようにしていました。具体的には、以下のような形式です。
ないと 掲示板の作成中です。
ヤマダタロウ テスト投稿をしてみます。
ヤマダハナコ 作成がんばってください!
基本的な流れは、複数行のデータがあるファイルの内容をすべて表示するプログラムと同じです。CGIファイルの名前は、bbs.cgi
とし、ログファイルの名前は bbs.txt
とします。
#!/usr/local/bin/perl
print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>掲示板</title></head>\n";
print "<body>\n";
if (open(FH, "bbs.txt")) {
while ($data = <FH>) {
print "<p>$data</p>\n";
}
close(FH);
} else {
print "<p>ファイルを読み込めません。</p>";
}
print "</body>\n";
print "</html>\n";
exit;
これで bbs.txt
の内容をすべて表示することができます。ただ、現在は単純にファイルの内容を表示しているだけです。もう少し掲示板らしくするために、今度は
投稿者:ないと
メッセージ:掲示板の作成中です。
投稿者:ヤマダタロウ
メッセージ:テスト投稿をして見ます。
投稿者:ヤマダハナコ
メッセージ:作成がんばってください!
このような表示ができるように変更してみたいと思います。
上のような表示を行うようにしたプログラムは以下になります。
#!/usr/local/bin/perl
print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>掲示板</title></head>\n";
print "<body>\n";
if (open(FH, "bbs.txt")) {
while ($data = <FH>) {
($handle, $message) = split(/\t/, $data);
print "<p>\n";
print "投稿者:$handle<br>\n";
print "メッセージ:$message\n";
print "</p>\n";
}
} else {
print "<p>ファイルを読み込めません。</p>";
}
print "</body>\n";
print "</html>\n";
exit;
変更があるのは、while
でファイルの内容を表示していく部分です。変更前は
while ($data = <FH>) {
print "<p>$data</p>\n";
}
となっていました。ファイルの内容を一行ずつ $data
に代入し、そのまま表示していく処理です。この部分を以下のように変更しています。
while ($data = <FH>) {
($handle, $message) = split(/\t/, $data);
print "<p>\n";
print "投稿者:$handle<br>\n";
print "メッセージ:$message\n";
print "</p>\n";
}
split
は、文字列を指定した文字で区切り、配列として返す関数でした。例えば $data
に
ないと 掲示板の作成中です。
という文字列が格納されていた場合、
@logs = split(/\t/, $data);
と記述すると $data
の内容が \t
(タブ)で区切られ、@logs
に代入されます。上のプログラムでは
($handle, $message) = split(/\t/, $data);
となっていますが、このように左辺にコンマ区切りで変数を記述すると、順に値が代入されていきます。つまり、$handle
には ないと
が代入され、$message
には 掲示板の作成中です。
が代入されます。(関数の意味や代入方法を忘れてしまった場合、配列の復習をしましょう。)
値が取り出せたら、あとはそれぞれを表示するだけです。
bbs.cgi
は投稿内容を表示するだけのCGIでしたが、今度は記事一覧の上に投稿フォームを表示させてみます。表示させるのみでまだ投稿はできませんが、これで掲示板らしくなります。
#!/usr/local/bin/perl
print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>掲示板</title></head>\n";
print "<body>\n";
#投稿フォームの表示
print "<form method=\"post\" action=\"bbs.cgi\">\n";
print "<p>\n";
print "ハンドルネーム<br>\n";
print "<input type=\"text\" name=\"handle\" size=\"20\" value=\"\"><br>\n";
print "メッセージ<br>\n";
print "<input type=\"text\" name=\"message\" size=\"20\" value=\"\">\n";
print "</p>\n";
print "<p><input type=\"submit\" value=\"送信する\"></p>\n";
print "</form>\n";
#記事の一覧表示
if (open(FH, "bbs.txt")) {
while ($data = <FH>) {
($handle, $message) = split(/\t/, $data);
print "<p>\n";
print "投稿者:$handle<br>\n";
print "メッセージ:$message\n";
print "</p>\n";
}
} else {
print "<p>ファイルを読み込めません。</p>";
}
print "</body>\n";
print "</html>\n";
exit;
投稿フォームを表示させてみました。print
関数によって表示させているだけなので、難しいところはないと思います。ただ、"
を表示させるには \"
と書かなければならない事に注意してください。
また、フォームの送信先は bbs.cgi
です。つまり、自分自身を呼び出すようにしています。
前回の内容で、送信ボタンを押すと自分自身を呼び出すように設定しました。つまり、bbs.cgi
自身が値を受け取るCGIになります。
ですがこのままでは値を受け取ってくれません。専用の処理が必要になります。値を受け取ることができるようにしたプログラムは以下のようになります。
#!/usr/local/bin/perl
#投稿された値を受け取る
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
read(STDIN, $alldata, $ENV{'CONTENT_LENGTH'});
} else {
$alldata = $ENV{'QUERY_STRING'};
}
foreach $data (split(/&/, $alldata)) {
($key, $value) = split(/=/, $data);
$value =~ s/\+/ /g;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('C', hex($1))/eg;
$value =~ s/\t//g;
$in{"$key"} = $value;
}
#ヘッダの表示
print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>掲示板</title></head>\n";
print "<body>\n";
#投稿フォームの表示
print "<form method=\"post\" action=\"bbs.cgi\">\n";
print "<p>\n";
print "ハンドルネーム<br>\n";
print "<input type=\"text\" name=\"handle\" size=\"20\" value=\"\"><br>\n";
print "メッセージ<br>\n";
print "<input type=\"text\" name=\"message\" size=\"20\" value=\"\">\n";
print "</p>\n";
print "<p><input type=\"submit\" value=\"送信する\"></p>\n";
print "</form>\n";
#記事の一覧表示
if (open(FH, "bbs.txt")) {
while ($data = <FH>) {
($handle, $message) = split(/\t/, $data);
print "<p>\n";
print "投稿者:$handle<br>\n";
print "メッセージ:$message\n";
print "</p>\n";
}
} else {
print "<p>ファイルを読み込めません。</p>";
}
#フッタの表示
print "</body>\n";
print "</html>\n";
exit;
プログラムの先頭に、値を受け取るための決まり文句を追加しています。
これで $in{'handle'}
や $in{'message'}
と記述する事で値を受け取ることができるのでしたね。ですが、まだ値を受け取るのみです。この内容をファイルに記録していく必要があります。
それでは、投稿内容を保存していく処理を加えて、掲示板を完成させましょう。記事を保存する処理は、フォームから値を受け取るところで説明した処理が利用できます。
#!/usr/local/bin/perl
#投稿された値を受け取る
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
read(STDIN, $alldata, $ENV{'CONTENT_LENGTH'});
} else {
$alldata = $ENV{'QUERY_STRING'};
}
foreach $data (split(/&/, $alldata)) {
($key, $value) = split(/=/, $data);
$value =~ s/\+/ /g;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('C', hex($1))/eg;
$value =~ s/\t//g;
$in{"$key"} = $value;
}
#ヘッダの表示
print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>掲示板</title></head>\n";
print "<body>\n";
#受け取ったデータをファイルに書き込む
if ($in{'handle'} ne '' && $in{'message'} ne '') {
if (open(FH, "bbs.txt")) {
@file = <FH>;
close(FH);
unshift(@file, "$in{'handle'}\t$in{'message'}\n");
if (open(FH, ">bbs.txt")) {
print FH @file;
close(FH);
} else {
print "<p>ファイルに書き込めません。</p>";
}
} else {
print "<p>ファイルを読み込めません。</p>";
}
}
#投稿フォームの表示
print "<form method=\"post\" action=\"bbs.cgi\">\n";
print "<p>\n";
print "ハンドルネーム<br>\n";
print "<input type=\"text\" name=\"handle\" size=\"20\" value=\"\"><br>\n";
print "メッセージ<br>\n";
print "<input type=\"text\" name=\"message\" size=\"20\" value=\"\">\n";
print "</p>\n";
print "<p><input type=\"submit\" value=\"送信する\"></p>\n";
print "</form>\n";
#記事の一覧表示
if (open(FH, "bbs.txt")) {
while ($data = <FH>) {
($handle, $message) = split(/\t/, $data);
print "<p>\n";
print "投稿者:$handle<br>\n";
print "メッセージ:$message\n";
print "</p>\n";
}
} else {
print "<p>ファイルを読み込めません。</p>";
}
#フッタの表示
print "</body>\n";
print "</html>\n";
exit;
受け取ったデータをファイルに書き込む
の箇所が、今回追加した処理です。記事の保存処理は以前に出てきたものと同じなのですが、処理全体を
if ($in{'handle'} ne '' && $in{'message'} ne '') {
で囲っている事に注目してください。$in{'handle'}
には入力されたハンドルネームが、$in{'message'}
には入力されたメッセージが格納されています。if
文は『$in{'handle'}
の内容がカラでなく、なおかつ $in{'message'}
の内容がカラでなければ』です。つまり、名前とハンドルネームが入力されていれば という条件になっています。
これにより、フォームから投稿された場合にのみファイルにデータが保存されます。この処理を行わないと、bbs.cgi
にアクセスする度、ファイルにカラのデータが一行ずつ追加されてしまいます。