cgiでウェブページを送る方法
cgiでは今回perlを使っています。perlの出力、例えばprint文で出力した内容は、サーバによってクライアントに送信されます。ですから、html文書をprint文で出力すれば良いということです。ただし、いきなりhtml文書を書くのではなく、最初にhttpヘッダ、次に空行を出力してからhtml文書を出力しなければなりません。cgiで出力するhttpヘッダ
cgiで出力するhttpヘッダは、Content-type が主で、それ以外にもLocationとStatusがありますが、ほとんど使わないでしょう。print "Content-type: text/html; charset=utf-8\n";このようにperlのprint文で書きます。以下の内容はtext/htmlすなわちhtml文書だよ、ということを表しています。この書き方はMIMEという書き方で、他にはtext/plainはテキスト文書、image/jpegはjpeg画像などがあります。しかし、text/htmlとすることがほとんどだと思います。後半のcharsetは文字コードを指定するものです。日本語にはいろいろなコードがありますので、自分の使った文字コードを指定します。もしもシフトJISを使ったなら、charset=Shift_JISと書きます。このhttpヘッダの出力の後に必ず空行を出力してください。これを忘れるとcgiは動きません。
サンプルプログラム
サンプルとして、式を入力してもらい、その式をperlのeval文で評価し、答えを返すというスクリプトを示します。#!/usr/bin/perl #=========================================================== # 簡易電卓 0.1 # testCALC.cgi #=========================================================== if ($ENV{'CONTENT_LENGTH'} > 0) { read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'}); @a = split(/&/, $query_string); foreach $x (@a) { ($name, $value) = split(/=/, $x); $value =~ tr/+/ /; #スペースの復元 $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; #特殊文字,日本語の復元 $FORM{$name} = $value; } $answer = eval($FORM{'EXPRESSION'}); } print "Content-type: text/html; charset=utf-8\n"; print "\n"; print "<HTML>\n"; print "<HEAD>\n"; print "<TITLE>簡易電卓</TITLE>\n"; print "</HEAD>\n"; print "<BODY>\n"; if ($ENV{'CONTENT_LENGTH'} > 0) { print encodehtml("$FORM{'EXPRESSION'} = $answer")."<BR>\n"; print "<BR>\n"; } print "<FORM action=\"testCALC.cgi\" method=\"POST\" accept-charset=\"UTF-8\">\n"; print " <INPUT type=\"text\" name=\"EXPRESSION\"><BR>\n"; print "<BR>\n"; print " <INPUT type=submit value=\"送信\">\n"; print "</FORM>\n"; print "\n"; print "</BODY>\n"; print "</HTML>\n"; exit(); # # htmlの特殊文字(&"<>)を無効化 # sub encodehtml() { my $s = shift; $s =~ s/&/&/g; $s =~ s/"/"/g; $s =~ s/</</g; $s =~ s/>/>/g; return $s; }
サンプルプログラムの解説
まず、POSTデータを取り込む部分です。if ($ENV{'CONTENT_LENGTH'} > 0) { read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'}); @a = split(/&/, $query_string); foreach $x (@a) { ($name, $value) = split(/=/, $x); $value =~ tr/+/ /; #スペースの復元 $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; #特殊文字,日本語の復元 $FORM{$name} = $value; } $answer = eval($FORM{'EXPRESSION'}); }Perlでは、環境変数は$ENV{環境変数名}で参照することが出来ます。これは連想配列です。 CONTENT_LENGTH は、POSTデータの長さを示しています。これが0より大きければ、POSTデータがあるということになります。
read関数で、標準入力から CONTENT_LENGTH の大きさのデータを変数$query_stringに取り込みます。変数名は他の名前でも構いません。
splitを使って、& を区切りとしてデータを分け、配列aに代入します。
for文で配列 a の要素ごとに = を区切りとして、$name と$value に分けて代入します。$nameに入るのは、FORMタグのinput要素の名前ですから、これはアルファベットなどで、URLエンコーディングは関係ありません。それに対して $value はURLエンコーディングでデータが変わっている可能性があるので、デコードします。デコードしたデータは連想配列 $FORM に格納します。
evalを用いて式を計算して、$answer に代入します。
次は出力部分です。
そこで、CONTENT_LENGTH が正、すなわちPOSTデータがあった場合は、式(すなわち$FORM{'EXPRESSION'})イコール 答(すなわち$answer)を出力します。このとき、HTMLでは特殊な役割を持っている文字(&, ", <, >)をHTMLで表示できる形に変換(encodehtml関数)します。
print "Content-type: text/html; charset=utf-8\n"; print "\n"; print "<HTML>\n"; print "<HEAD>\n"; print "<TITLE>簡易電卓</TITLE>\n"; print "</HEAD>\n"; print "<BODY>\n"; if ($ENV{'CONTENT_LENGTH'} > 0) { print encodehtml("$FORM{'EXPRESSION'} = $answer")."<BR>\n"; print "<BR>\n"; } print "<FORM action=\"testCALC.cgi\" method=\"POST\" accept-charset=\"UTF-8\">\n"; print " <INPUT type=\"text\" name=\"EXPRESSION\"><BR>\n"; print "<BR>\n"; print " <INPUT type=submit value=\"送信\">\n"; print "</FORM>\n"; print "\n"; print "</BODY>\n"; print "</HTML>\n"; exit();最初の行は HTTPヘッダです。空行を出してから、HTML文書の出力になります。ヘッダ部分を出力し、ボディに入ります。
そこで、CONTENT_LENGTH が正、すなわちPOSTデータがあった場合は、式(すなわち$FORM{'EXPRESSION'})イコール 答(すなわち$answer)を出力します。このとき、HTMLでは特殊な役割を持っている文字(&, ", <, >)をHTMLで表示できる形に変換(encodehtml関数)します。
最後は入力用の FORM タグと、INPUT タグを出力して終わります。Perlでは、文字列を表すのに「'」(シングルクォート)と「"」(ダブルクォート)のどちらも使えますが、ダブルクォートの文字列中にダブルクォートは使えません。その場合は「¥"」とエスケープ文字の「¥」を付ければOKです。