掲示板をやってみる

いっこうに動いてくれないアクセスカウンタはきっぱりあきらめ,さていよいよメインイベント,掲示板の登場である.

いきなりサンプルが載ってるけど,やっぱりけっこう長い.しかもアクセスカウンタでは全然出てこなかったようなのがいっぱい出てくる〜〜〜.

たとえば,キャッシュの話.掲示板なんかの場合,キャッシュを無効にしないと,せっかく書き込んでも,キャッシュに保存されているファイルが表示されてしまって,新しいのが全然表示されないことがあるんだそうだ.これはブラウザの設定によるので,強制的にキャッシュを無効にするという処理が必要になる.

よくはわかんないけど,「Content-type」でおなじみのHTTPヘッダを使って,最終更新日時が今ですよ(Last-Modified),ということと,このドキュメントは無効だから再ロードしてください(Expires),ということをブラウザに伝えてやるみたい.

それから,環境変数$ENVの話.じつは,ホームページを訪れた人の情報って,けっこうだだ漏れなのである.たとえば,

$ENV{'REMOTE_ADDR'} には,IPアドレス,
$ENV{'HTTP_REFERER'} には,このページを見る前に見ていたURL,
$ENV{'REMOTE_HOST'} には,リモートホスト名

ほかにも,$ENVにはいろんな情報が格納されているらしい.そーいや,前,どっかのホームページで,あなたのはこういう情報を垂れ流しています,ってかいてるページを見たな.

あなたの吐き出している情報
http://cgi.mobile-pc.com/user/x68k/sch/index1b.html

・・・なんかめちゃくちゃいっぱいあるやん.何でこんないっぱい送らないかんのやっ!

この環境変数を使って,いろんなことができる.アクセスカウンタの場合はホームページに訪れた人のIPアドレスを保存しておいて,同じ人から何度もアクセスがあってもカウントしないってのがふつうだし,掲示板の荒らし対策も環境変数を使っている.

ちなみに,環境変数ENVの内容を全部書き出すプログラムはコレ.アクセスするとあなたがあちこちで流しまくっている情報が見られます.proxy使うと多少はましになるらしいけどね.
http://www6.tkcity.net/~yuri/cgi-bin/env/env.cgi

しかし,わからないことばっかで,いっこうに掲示板本体にたどりつけないんデスけど・・・.

データを受け取る

ああやっと掲示板へのデータ送信の話までたどり着いた・・・.

ちょっと前に,メールマガジンのサンプルプログラムが「更新」を押したら投稿されちゃう! って話を書いたけど,これに関係ありそーな話である.

CGIプログラムへのデータの送り方の話だ.送る方法として「POSTメソッド」と「GETメソッド」というものがある.

このうち,「GET」のほうは,URLに送信するデータを埋め込んでCGIプログラムに渡すのである.そう,

http://www6.tkcity.net/~yuri/cgi-bin/mybbs/mybbs.cgi?name=yuri&subject=&mail=&url=&content=test&act=regist

というやつだ.

この場合,すぐ上に出てきた環境変数ENVの「REQUEST_METHOD」が「GET」になり,「QUERY_STRING」に送信データが入った状態で送信される.

一方,「POST」のほうはURLにはデータは入らない.つまり「更新」を押しても送信されない・・・と思う.多分.「REQUEST_METHOD」は当然ながら「POST」,「CONTENT_LENGTH」に送信したデータの長さが入り,「QUERY_STRING」には何のデータも入らない.

じゃあ肝心のデータはどうやって送信されているのかというと,これは環境変数ではなく,標準入力「STDIN」というもので送られるそうだ.

以下のフォームに何か適当に書き込んで,送信ボタンをクリックすると,上で書いた環境変数の中身が見られるが,POSTとGETで内容が変わっているのがわかる.また,GETで送信した場合,URLの後ろにデータがくっついているのもわかる.

GETでデータを送信します
POSTでデータを送信します

URLエンコーディングのナゾ

ところが上のフォームで日本語や半角スペースを入力すると,おかしくなる.

半角スペースは「+」になっちゃうし,「はろー」は「%A4%CF%A4%ED%A1%BC」なんてわけのわからないものになってしまう! 誰もそんなこと頼んでないのに日本語が勝手に16進数の文字コードに変換されているのだ.これをURLエンコーディングという.「は」が「A4CF」,「ろ」が「A4ED」,「ー」が「A1BC」である.

そこで,エンコーディングされたデータを戻してやらなければ,せっかくの掲示板が何がなんだかわからない〜〜〜ということになる.

どうやって戻すかというと・・・

変数$valueにURLエンコーディングされた日本語が入っているとする.たとえば「%A4%CF%A4%ED%A1%BC」だ.この$valueにこんな処理をする.

$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('C', hex($1) )/ge;

アクセスカウンタのところでも出てきた,パターンマッチングである.「s///」は文字列の置換だったけれど,「tr///」は文字の変換で,まずは一行目で「+」を半角スペースに戻している.

二行目でいよいよわけのわからない文字コードを日本語に戻してやる.

%([a-fA-F0-9][a-fA-F0-9])は,「%」の後に二桁の16進数が続くもの,たとえば「%A4」をさす.さらに,「()」で囲まれているから,「A4」の部分だけグループ化されていて,hex()の引数である「$1」もこの「A4」をさす.

hex($1)で16進数を10進数に直す.つまり「A4」なら「164」になり,この結果をpack関数に渡す.pack('C',データ)により,データに示された文字が返り,この文字をもとの「%A4」と置換する.こうして,

「%A4%CF」は「は」に,
「%A4%ED」は「ろ」に,
「%A1%BC」は「ー」に,めでたく変換しなおされる.

いちばん最後の,パターン修飾子の「e」は,外すと,pack()やhex()などの関数が実行されずに,関数名が文字列としてそのまま出力されてしまう.つまり,関数をちゃんと実行するためのものらしい.

文字コードの処理

日本語のデータのやり取りができるようになった・・・のだけれど,問題はまだ,もうひとつ残っている.

aska.cgiにもトクトクのメールマガジンにも出てきたjcode.pl.JISとかシフトJISとかEUCといった,文字コードの変換ライブラリだ.なんか日本語使うには必須らしいね.この掲示板でも,やっぱりこれを使用する.これをやらないと恐怖の文字化け・・・なのかな?

あり? なんか,jcodeの呼び出し方が違う・・・.

aska.cgiと,書籍についてるサンプルプログラムは,

&jcode'convert(*変数名,'euc');

なのに,トクトクのメールマガジンでは,

jcode::convert(\$変数名,'euc');

となっている.なんでだろ〜〜?

jcode.plをエディタで開いてみると,ありがたいことに,上のほうにjcodeの呼び出し方の説明がついている.

説明によると,「PERL4」の場合「&jcode'convert(,)」で呼び出し,「PERL5」の場合「jcode::convert(,)」で呼び出すらしい.4とか5とかいうのはバージョン番号なんだろうか.

よくわかんないけど,とりあえず「PERL4」のほうを使うことにする・・・.

「連想配列」って何?

本には,「受け取ったデータを連想配列に格納しています」という一文があった.はて? 連想配列ってなんだろ〜〜? 普通の配列と何が違うのかな?

端的に言うと,添字番号を使わなくていい配列のことらしい.

普通,配列っていうと,

$pc_name[0]="PC9801"
$pc_name[1]="Mebius"
$pc_name[2]="Endeavor"

と,添字には数字しか使えないけど,連想配列の場合は,

$pc_name{'nec'}="PC9801"
$pc_name{'sharp'}="Mebius"
$pc_name{'epson_direct'}="Endeavor"

と,数字じゃなくてキー値で管理できるのだ.キー値を直接内容に結び付けられるからけっこうわかりやすいみたい.

考えてみたら,今まで全然意識してなかったけど,環境変数$ENVだって,$ENV{'REMOTE_ADDR'}でIPアドレスを得ることができるんだから,連想配列なわけだ.

ま,こんな感じであっちこちつまづきながら,わけのわからないperlプログラムをじ〜〜っと目で追っていくと,ようやくHTMLタグが現れた.HTMLタグも,最初見たときはずいぶん難しく感じたものだが,CGIプログラムの中で見ると,なんだかほっとする.少なくとも,出力結果の予想はつくもんな〜〜〜.

HTMLタグを書き出す方法として,普通はprint文を使うけれど,ヒアドキュメントというものを使うともっと簡単になる.

print << "HDOC";
Content-type: text/html
<html>
<head>
<title>たいとる</title>
</head><body>
***こんな感じで,ここにタグを直接書いていく***
</body></html>
HDOC

これで,最初のHDOCから最後のHDOCまでの間,printが不要になる.

  3

TO HOME