Perlによる掲示板の作り方
文字のデコード
フローチャート(新しいウィンドウで開きます)
この図を見ながら読むと、多少はわかりやすいかと思います。
ブラウザからのデータ
ブラウザからデータが送られてくる時の形式がPOST形式とGET形式と2つあり、POST形式の場合には、標準入力にデータが送られてきます。
ですから、データの長さを参照して、その長さの分だけを格納します。
GET形式の場合には、送られてきたデータは環境変数というブラウザから送られてくる変数に格納されているので、それを読み取ります。
データ形式 | データの場所 |
---|---|
POST | 標準入力 |
GET | QUERY_STRING |
まずどちらで送られてきたかを判断しないといけません。
具体的には、ifという関数を使って場合分けをします。
ifの使い方は
if(条件){本文1}else{本文2}
と書きます。条件があっているなら本文1を違っているなら本文2を実行します。
read(STDIN, $b_dat, $ENV{'CONTENT_LENGTH'});
}
else {
$b_dat = $ENV{'QUERY_STRING'};
}
ここで、$ENV{'REQUEST_METHOD'}というのは環境変数の一つで、ここにデータをPOST形式かGET形式のどちらで送ったか書いてあります。
eqと言うのは文字列で比較して同じだった場合、つまり$ENV{'REQUEST_METHOD'}がPOSTの場合を指します。
これでブラウザからのデータを受け取る事ができました。
しかし、ブラウザからのデータは実際には%4f%53&%25%3a=%3e%b6&%11%21というように&や=で連結されて送られてきます。次はこれを分割しましょう。
データの分割
foreach $second (@first) {
($name, $value) = split(/=/, $second);
}
ブラウザからはname=data&name=dataのような形で送られてくるので、初めにsplit命令で「&」の部分でname=dataという形式に分けます。
ここで、データの状態がname=dataという状態になっているので、これを更に配列@firstの要素の数だけforeach命令で「=」の部分で分ける事を繰り返し、nameとdataに分けます。
次に、これらの文の中に「"」や「+」があると、Perlの中で文字指定の「"」などと判断できなくなってしまうなど、不具合がおきる可能性があるので、これらを置換関数s///を使って置換しておきます。
そして、掲示板の中でタグを使われると悪質な悪戯が出来てしまうので「<」や「>」なども変換します。
これまでのプログラムをまとめると、
read(STDIN, $b_dat, $ENV{'CONTENT_LENGTH'});
}
else {
$b_dat = $ENV{'QUERY_STRING'};
}
#&で分割
@first = split(/&/,$b_dat);
foreach $second (@first) {
#さらに=で分割
($name, $value) = split(/=/, $second);
# 変換演算子tr + をスペースに置換
$value =~ tr/+/ /;
# 変換演算子 s///で文字コードから文字へ変換
$value =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
# " を " に変換
$value =~ s/"/"/g;
# <を < に変換
$value =~ s/</</ig;
# > を > に変換
$value =~ s/>/>/ig;
#\n を "" に変換
$value =~ s/\n//g;
}
デコード
次に、いよいよ文字列を日本語に変換します。
デコードするためにはjcode.plというライブラリを使用します。
ライブラリを使用するにはプログラムの一番最初の#!/usr/bin/perlとプログラム本文の間に
require "./jcode.pl";
と記述します。この" "の中はjcode.plのある場所を入れてください。
「./」というのは現在CGIがある場所と同じ場所を指します。
こうする事により、jcode.plの中にある、&jcode'convert(*変数名,"文字コードタイプ");という命令が使えるようになります。
ここでは文字コードタイプにShift-jisを選択しようと思います.
次に後で変数を呼び出す時にわかりやすいように、送られてきたdataとnameを関連付けて置きましょう。
$FORM{$name} = $value;
そして、このデコードというのは頻繁に使うのでサブルーチンにしてしまいましょう。
サブルーチンにすると
&サブルーチン名
という記述で呼び出せるので、プログラムが解りやすくなります。
Perlでは、サブルーチンの定義を
sub サブルーチン名{}
と記述する事になります。
今までのプログラムをあわせるとこうなります。
require './jcode.pl';
$MAIN_TITLE = "掲示板";
$max = 50;
$file = "bbs.log";
sub decode {
if ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN, $b_dat, $ENV{'CONTENT_LENGTH'});
}
else {
$b_dat = $ENV{'QUERY_STRING'};
}
@first = split(/&/,$b_dat);
foreach $second (@first) {
($name, $value) = split(/=/, $second);
$value =~ tr/+/ /;
$value =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s/"/"/g;
$value =~ s/</</ig;
$value =~ s/>/>/ig;
$value =~ s/\n//g;
# デコード処理(Shift-jisへ変換)
&jcode'convert(*value,'sjis');
&jcode'convert(*name,'sjis');
$FORM{$name} = $value;
}
}