***HPクリエイターのためのCGI講座 第44回***
まず初めに、単純に書き込むだけの掲示板を作ってみましょう。
書き込む内容を入力するエリアと、書込みボタンしかありません。
単純ですが、掲示板の基本となります。
しっかりとマスターしてください。
<漢字コードの問題>
漢字コードは、厄介なことに、複数のコード種類が存在します。
HPの作成経験者であれば、シフトJISコードやJISコードといった言葉を聞いたことがあるでしょう。
同じページの中に、違った漢字コードが混在すると、文字化けの原因になります。
しかし、掲示板に書き込む人が、どのような文字コードを使うかは、こちらには分かりません。
文字コードを統一するために、書き込まれた漢字コードを判定し、必要であれば、文字コードを変換してやる必要があります。
ここでのサンプルプログラムで、漢字コードの変換処理も学びます。
<プログラムの説明>
require '../../../cgi/jcode.pl';
日本語コード変換プログラムの場所を指定
$lock_file = "../../../cgi/easy_bbs.lock";
多重アクセス禁止用ロックファイル名(ロック用ファイル名)
&in_para; # 入力パラメータの取得
入力パラメータ取得用サブルーチンをコール
入力パラメータを受け取り、デコードします。
if ($out ne ""){ # ボタンが押されて、このCGIが起動された
&log_write; # ログファイルへメッセージの書込み
}
このCGIが起動される要因として、2種類あります。
1.オープニング時に呼び出される
「サンプルはここ」と記述された「ここ」をクリックした場合
2.掲示板の書込みボタンを押した場合
書込みボタンが押された場合は、 $out に "書込み" の文字列が格納されています。
書込みボタンが押されていない場合は、 $out には何も格納されていません。
このCGIプログラムの起動要因を、 $out に文字列が設定されているか否かで判定しています。
ここからは、HTMLテキストをブラウザへ出力
print "Content-type: text/html\n\n";#
HTML文をブラウザへ出力
print "<html>\n<head>\n";
print "<title>EasyBBS</title></head>\n";
print "<FORM method=\"POST\"action=\"easy_bbs.cgi\"><TEXTAREA
rows=\"15\" cols=\"40\"
name=\"msg\"></TEXTAREA><INPUT
type=\"submit\" value=\"書 込 み\"
name=\"out\"></FORM>\n";
FORMタグ
methodはPOSTで、CGI(easy_bbs.cgi)を呼び出す
テキスト入力領域の大きさは、40文字*15行
CGIプログラムの受け取る、テキスト入力パラメータの名前はmsg
書込みボタンの名前はout
print "<hr size=2>\n";
水平線の表示。
open(LOG,"<easy_log.txt") ||
&error(0); # ロググファイルの読込みモードでのオープン
ログファイル(発言内容が記述されている)を読み込みモードでオープンします。
@log_buff = <LOG>; # ログファイルから全て、読み出し
ログファイルの内容を一度に配列@log_buffへ読み込みます。
このように、記述すると、配列の各要素にファイルの中の文字列が一行ずつ読み込まれます。
log_buff[0]・・・・1行目の文字列
log_buff[1]・・・・2行目の文字列
log_buff[2]・・・・3行目の文字列
:
:
close(LOG);
ログファイルのクローズ(読み込みが終了したので)
foreach (@log_buff){ # $_へ1行ずつ取り出す
print "$_\n";
# 取り出した1行を表示
print "<hr
size=2>\n"; #区切り用ラインの表示
}
foerchを使って@log_buffから、1要素(1行)ずつ $_ に取り出します。
ここでの1行は、1メッセージです。
取り出したメッセージを、ブラウザへ表示して、その後、hrタグを使って区切り用の水平線を出力します。
print "</html>\n";
exit;
プログラムの終了
ここからは、入力パラメータ取得サブルーチン
sub in_para {
if ($ENV{'CONTENT_LENGTH'}
> 500){
METHODがPOSTなので、環境変数CONTENT_LENGTHに文字列が格納されています。
その値をチェックし、500文字以上はエラーとします。
&error(0);
# 入力メッセージの最大長を500バイト(半角500文字)とする
}
read(STDIN, $in_buffer,
$ENV{'CONTENT_LENGTH'});# POSTなのでパラメータを標準入力から読み出す
標準入力STDINから、パラメータを取得します。
@pairs = split(/&/,$in_buffer);
# パラメータのペアを切り出す
パラメータは &
で区切って送られています。
配列@pairsの各要素に &
で区切った文字列を格納します。
foreach $pair (@pairs)
{
$pairに配列@pairsの各要素を取り出す
($name,
$value) = split(/=/, $pair); # パラメータを名前と値に分解
各パラメータは 名前=値 の形をしています。
それぞれを$nameと$valueへ格納します。
$value
=~ tr/+/ /; # コードのデコード
変換規則に従って+はブランクに置換
$value
=~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
16進文字列を、数値に置換
&jcode'convert(*value,'sjis');
# S-JIS変換
得られた文字列を、S-JISに変換
$value
=~ s/\"/"/g; # タグ文字の変換
特殊文字の変換
"(ダブルクォテーション)は"に置換
$value
=~ s/</</g;
< は< に置換
$value
=~ s/>/>/g;
> は> に置換
if($name
eq "msg"){ # 入力メッセージの処理
現在のパラメータの処理がmsg(投稿記事)の場合
$msg
= $value;
記事を$msgに格納します。
現在のパラメータの処理がmsg(投稿記事)の場合は、改行コードを<br>に置換します。
(改行コードには、次の3種類がある)
$msg
=~ s/\r\n/<br>/g; # リターンコードを<br>に置換
$msg
=~ s/\r/<br>/g; # "
$msg
=~ s/\n/<br>/g; # "
}
if($name
eq "out"){ # ボタンが押された場合
現在のパラメータの処理が書込みボタンの場合
$outに文字列(書込み)を格納します。
$out
= $value; # ボタンに表示している文字が格納される今回の場合は「書込み」
}
}
}
ここからは、投稿記事のログファイルへの書込み処理
sub log_write {
&lock; # ロック処理
多重アクセス排他処理
open(LOG,"<easy_log.txt")
|| &error(1); # ログファイルを読込みモードでオープン
ログファイルを読み込みモードでオープンします。
@log_buff = <LOG>;
# 全メッセージの読み出し
ログファイルの内容を@log_buffへ読み出します。
close(LOG);
ログファイルのクローズ
if (10 <= @log_buff){
ログファイルへの最大格納メッセージ数は10件とします。
現在のログファイルに格納されているメッセージ数が10件の場合。
pop(@log_buff);
# メッセージが10を超えれば、一番古いメッセージを削除する
一番古いメッセージを配列@log_buffから pop 命令を使って、削除します。
}
unshift (@log_buff,"$msg\n");
#入力メッセージをメッセージの最初に追加
今、取り込んだメッセージを unshift 命令を使って配列@log_buffの先頭に格納するします
open(LOG,">easy_log.txt") ||
&error(1); #
ログファイルを書込みモードでオープン
ログファイルを書込みモードでオープン
print LOG @log_buff;
# メッセージのログファイルへ書込み
配列@log_buffをログファイルへ書き出します。
close(LOG);
ログファイルをクローズする
if (-e $lock_file){
unlink($lock_file);
# ロックの解除
}
}
sub lock{ # ロック処理
$retry = 5;
while (!symlink(".",
$lock_file)){
if
(--$retry <= 0){
&error(0);
}
sleep(1);
}
}
sub error{ # エラー処理
if((-e $lock_file)
&& ($_[0] != 0)){
unlink($lock_file);
}
print "Content-type:
text/html\n\n";
print "<html>\n<body
bgcolor=#FF0000>\n";
print "<center><h3>ERROR</h3>\n";
print "</html>\n";
exit;
}
********************************************************************************
講師:ALK alk@arkland.co.jp
運営:アークランド(株) http://www.arkland.co.jp