CGIプログラミング(4) - データを読み込み表示する

ここでは、フォームからデータを受け取るでフォームから送られてくるデータの形式を理解したうえで、データを読み込みそれを適切に表示するCGIプログラムを作成する。

まずは、フォームの例にあるフォームをform-ex.htmlというファイル名で保存せよ。このフォームから、以下のdispdata.cgi というCGIプログラムを実行する。dispdata.cgiは、送られてきたデータを読み込んで、その内容をそのまま表示する。

dispdata.cgi - 送られてきたデータをそのまま表示する
#!/usr/bin/env perl
print "Content-Type: text/html\n\n";

&decode;

print "<html><body><h1>Display direct data which is received CGI data</h1><pre>\n";

$sports = $tags{'sports'};
print "sports = ", $sports, "\n";

$baseball = $tags{'baseball'};
$soccer = $tags{'soccer'};
$basket = $tags{'basket'};
$tennis = $tags{'tennis'};
$golf = $tags{'golf'};
print "baseball = ", $baseball, "\n";
print "soccer = ", $soccer, "\n";
print "basket = ", $basket, "\n";
print "tennis = ", $tennis, "\n";
print "golf = ", $golf, "\n";

$dept = $tags{'dept'};
print "dept = ", $dept, "\n";

$s_id = $tags{'student_id'};
print "student_id = ", $s_id, "\n";

$name = $tags{'name'};
print "name = ", $name, "\n";

$com = $tags{'comment'};
print "comment = ", $com, "\n";

print "</pre></body></html>\n";

#------------------------------------------------------------
# cgi.pl - decode CGI input.
# by ETO Kouichirou <t91069ke@sfc.keio.ac.jp>
# date 1994/05/11
#
# Usage:
#
#	&decode;
#	...
#	$name = $tags{'name'};

sub decode {
    local($args, $n_read, *terms, $tag, $value);

    if ($ENV{'REQUEST_METHOD'} eq "POST"){
        $n_read = sysread(STDIN, $args, $ENV{'CONTENT_LENGTH'});
    } else {
        $args = $ENV{'QUERY_STRING'};
    }

    @terms = split('&', $args);

    foreach (@terms) {
        ($tag, $value) = split(/=/, $_, 2);
        $otags{$tag} = $value;		 # original tags
        $tags{$tag} = &unpack($value);	 # tags is global
    }
}

sub unpack {
    local($value) = @_;
    $value =~ s/\+/ /g;
    $value =~ s/%(..)/pack("c", hex($1))/ge;
    return $value;
}

sub unspecial {
    local($value) = @_;
    $value =~ s/&/&apm;amp;/g;
    $value =~ s/</&lt;/g;
    $value =~ s/>/&gt;/g;
    return $value;
}

PerlでCGIプログラムを書く場合に便利な仕組みがライブラリやパッケージという形で色々と提供されている。ここでは、江渡 浩一朗 氏が1994年に作成したCGIパッケージを一部改変して使っている。プログラムの後半の部分がそうである。

この場合、&decode としてdecode手続きを呼び出せば、 $tags{'コントロール名'}とすると、コントロール名で指定したデータ(コントロール値)が得られる。 例えば、上の例では、フォームのラジオボタンでサッカーを選んだ場合、コントロール名は、 "sports"でコントロール値は"2"のはずであるから、cgi{'sports'}と書くと "2" という値が得られる。上の例では、$sports = $tags{'sports'}として、いったん変数$sportsに代入してから使用している。

応用

単にデータを表示するだけではおもしろくないので、表示の内容を工夫してみる。

sports.cgi - 少しはまともな表示をするプログラム
#!/usr/bin/env perl
print "Content-Type: text/html\n\n";

&decode;

print "<html><body>\n";

$sports = $tags{'sports'};
$s_id = $tags{'student_id'};
$name = $tags{'name'};

if ($s_id eq "") { $s_id = "未記入"; }
if ($name eq "") { $name = "名無し"; }

print "学籍番号", $s_id, "の", $name, "さんは、";

if ($sports) {
  @sports_a = ("野球", "サッカー", "バスケットボール", "テニス", "ゴルフ");
  print $sports_a[$sports-1];
  print "が一番お好きなのですね。\n";
} else {
  print "一番お好きなスポーツを答えていただいておりません(;_;)\n";
}
print "</body></html>\n";

#------------------------------------------------------------
# cgi.pl - decode CGI input.
# by ETO Kouichirou <t91069ke@sfc.keio.ac.jp>
# date 1994/05/11
#
# Usage:
#
#	&decode;
#	...
#	$name = $tags{'name'};

sub decode {
    local($args, $n_read, *terms, $tag, $value);

    if ($ENV{'REQUEST_METHOD'} eq "POST"){
        $n_read = sysread(STDIN, $args, $ENV{'CONTENT_LENGTH'});
    } else {
        $args = $ENV{'QUERY_STRING'};
    }

    @terms = split('&', $args);

    foreach (@terms) {
        ($tag, $value) = split(/=/, $_, 2);
        $otags{$tag} = $value;		 # original tags
        $tags{$tag} = &unpack($value);	 # tags is global
    }
}

sub unpack {
    local($value) = @_;
    $value =~ s/\+/ /g;
    $value =~ s/%(..)/pack("c", hex($1))/ge;
    return $value;
}

sub unspecial {
    local($value) = @_;
    $value =~ s/&/&amp;/g;
    $value =~ s/</&lt;/g;
    $value =~ s/>/&gt;/g;
    return $value;
}
Perlでは、文字列の比較には、if ($a eq "AAA")という風に eq という比較演算子を使う。しかし数値の比較には、JavaやCと同様に == を使う。

学籍番号や名前が未記入の場合には、例えば、if ($s_id eq "") { $s_id = "未記入"; } として、未記入という文字列を代入していることに注目せよ。また、一番好きなスポーツに何も選択していない場合は、 $sportsは、"" の値を持つ。その場合、if ($sports) { はsportsが""であるから成り立たなく、else { 〜 } の部分が実行されるのである。

Perlの配列は、配列全体をさす場合は、@array という風に @ を付ける。 しかし、配列の要素をさす場合は、$array[添字の値] と書く。

sportsが選択されている場合は、配列@sports_aを使って対応するスポーツ名を表示している。 配列の添え字は0から始まるが、この場合、野球が1、サッカーが2、 バスケットボールが3という風に1から始まっているので、$sports-1 として1を引いていることに注目せよ。

課題

  1. 上記 dispdata.cgi を実行してみよ。フォームの各コントロールに色んな選択やテキストの入力をした例を3つ用意し、それぞれのCGIの結果を報告せよ。ただし、選択肢で何も選択しない場合やテキストに何も入力しない場合も例に含めること。
  2. 上記 sports.cgi を実行してみよ。スポーツを選択した場合、選択しない場合、学籍番号や名前を記入しない場合の結果を報告せよ。
  3. 上記 sports.cgi を元に、名前を記入していない場合に、名前を記入してくださいと表示するようなCGIを作成せよ。

東京情報大学情報システム学科
大見 嘉弘(Yoshihiro OHMI)