FORMタグを使って送られるデータはどのような形をしているのか、調べて見ましょう。
(例) フォームから送られたデータを表示するCGIプログラム「print.cgi」
#!/usr/local/bin/perl $form = <STDIN>; # 標準入力から1行読み取って変数$formに代入(実はちょっと手抜きです) &header; # HTML ヘッダー print $form; # 変数$formの値を表示するHTMLをprint文で表示。 &footer; # HTML フッター # HTML ヘッダー sub header { print "Content-type: text/html\n\n"; print <<"EOM"; <html> <head> <META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS"> </head> <body> EOM } # HTML フッター sub footer { print "</body>\n</html>\n"; }CGIプログラムにデータを送信するフォーム「form.htm」
<HTML> <HEAD> </HEAD> <BODY> <FORM METHOD="POST" ACTION="print.cgi"> 名前:<INPUT TYPE="text" NAME="name"><BR> 会員番号:<INPUT TYPE="number" NAME="number" VALUE="KK-"><BR> パスワード:<INPUT TYPE="password" NAME="pass" SIZE=20><BR> ご意見・ご感想をお待ちしております。<P> <TEXTAREA ROWS=8 COLS=40 NAME="message"> ひとことどうぞ </TEXTAREA> <INPUT TYPE=submit VALUE="送信"> </FORM>動作テスト
form.htm のフォームに下記のような入力をして送信してみます。
名前: shio masayuki
会員番号: KK-123!
パスワード: xyz
テキストエリア: ひとことどうぞ
実行結果
name=shio+masayuki&number=KK-123%21&pass=xyz&message=%82%D0%82%C6%82%B1%82%C6%82%C7%82%A4%82%BC%0D%0Aが表示されます。
上記の結果から
- 「NAME属性」=「その入力内容」 が 「&」で1行につながれている
- 全角文字や特殊文字は「%**」の形で置き換えられている
- 空白が「+」に置き換わっている
のがわかります。このままでは分かりにくいので、受け取ったデータを分かりやすい形に直さなければいけません。
INPUTタグのNAME属性に全角文字を使った場合にも「%**」で置き換わってしまうので、安全のためにNAME属性は半角英数字を使用するほうがいいです。
NAME1=値1&NAME2=値2&…
(NAME*はINPUTタグで使用したNAME属性、値*はそれに対応する値)という形の長い文字列として与えられます。以後、
$form = <STDIN>;で変数$formに受け取った文字列を代入したものとして話を進めます。
FORMタグから受け取った文字列には大きく分けて以下の2つの作業が必要です。
- &で結ばれた「NAME=値」部分の切り分け
- 値部分の文字列を変換
順に説明しましょう。
&を区切り文字として文字列を分割するにはsplitを使います。
@array = split(/&/, $form);これにより、変数$formの値を&で区切って配列@arrayに代入します。
「値」にはフォームの内容に以下のような操作を加えられたものが与えられています。
- 半角の空白文字は「+」に
- URLとして都合の悪い文字は、%と16進数(%HH)の形に
- 全角文字は、%HH形式に
このため、操作を加える前の値に変換する必要があります。具体的には、
foreach (@array) { # 配列@arrayの要素の数だけ繰り返し tr/+/ /; # +を半角の空白文字に変換 ($key, $val) = split (/=/); # =で区切って名前と値を分割 $key =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("c",hex($1))/ge; # %HH形式を16進数に $val =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("c",hex($1))/ge; # %HH形式を16進数に $val =~ s/\r\n/\n/g; # 改行コードの統一 $in{$key} = $val; # 連想配列%inに代入 }
のような操作を行います。
前回のprint.cgiを以下のプログラムに置き換えて、前回のform.htmに文字を入力してみましょう。
#!/usr/local/bin/perl $form=<STDIN>; @array = split(/&/,$form); # $formの内容を&で区切って配列@arrayに格納 foreach (@array) { # 配列@arrayの要素の数だけ繰り返し tr/+/ /; # +を半角の空白文字に変換 ($key, $val) = split (/=/); # =で区切って名前と値を分割 $key =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("c",hex($1))/ge; # %HH形式を16進数に $val =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("c",hex($1))/ge; # %HH形式を16進数に $val =~ s/\r\n/\n/g; # 改行コードの統一 $in{$key} = $val; # 連想配列%inに代入 } &header; # HTML ヘッダー $,=','; # print文の文字区切りを「,」に設定 print %in; # 連想配列%inの値を表示。 &footer; # HTML フッター (以下、ヘッダーとフッターのサブルーチン定義)