« 漢字コードの変換(その2) | メイン | フォームからの入力(その2) »

フォームからの入力

CGIを使うメインとも言えるのが「掲示板」じゃないか?ということは、フォームから文字列を取得しなければいけない。たとえそれが日本語でも・・・。

ハッキリ言って仕組みはよくわからない。実際に使っているCGIから拝借しただけ・・・。

フォームの中身はブラウザから送信するときは、特に指定しない限り「application/x-www-form-urlencoded」で出力される(Content-Typeがこれになる)。urlに使えない文字(?)は「%hh」の形で変換(エンコード)された形式。これを元に戻す(デコード)のが次の命令。

s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg;
とりあえず、「pack("C", hex($1))」を実行した形式で置きかえるらしい。「$1」は正規表現で最初に出てきた「()」の中身を参照する。「hex」は文字列を16進数として解釈し、10進数に変換するようだ。どうやら「pack」は、10進数でしか機能しない関数のようだ。いや、嘘かも・・・。よくわからない。

あと、メソッド(送信形式?)にも、postやgetなどがあって、それによって受け取り方も変更しなくてはいけない。このサンプルでは「post」の形式しか使えない。

「CGI」に送信できるのはフォームの中身だけではなく、コマンド的(?)な文字列も渡すことができる。このコマンド(引数の方が相応しいかな?)を使えば、一つのCGIスクリプトで色々な処理をすることができる。このサンプルでは、引数無し(ts0016.cgi)だと「入力フォーム」を出力し、outputをつける(ts0016.cgi?output)とフォームの中身を出力するようにしている。この方法は「post」でしか使えないのか、「get」だと引数を渡すことができなかった。やり方がまずいのかもしれないけど・・・。もう少し調べてみたい。

この引数は「@ARGV」という変数(?)に渡される。2つ以上のコマンド(output+input+...のように書く)がある場合は、「@ARGV」という配列に順次渡される。先の例では「$ARGV[0]」が「output」、「$ARGV[1]」が「input」ということになる。扱い方は、通常の配列と同じようだ。つまり、コマンドが無い場合は「$#ARGV」は「-1」となる。

ところで、「ARGV」というのは、なんという単語の略なのか?覚えにくい・・・。

フォームの中身は、「post」の場合は「標準入力(STDIN)」に入力される。この入力を解釈するには以下のようにする。

read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'});
これで、送信されたデータが「$query_string」の中に入力される。「$ENV{'CONTENT_LENGTH'}」は入力されたバイト数を返す環境変数のようだ。「STDIN」から「$ENV{'CONTENT_LENGTH'}」バイト分のデータを「$query_string」に代入する。とでも解釈すればいいのか・・・。

この内容は「名前1=中身1&名前2=中身2...」のようになっているため、まず「&」を区切りにして配列に入れる(配列 = split(/&/, 文字列))。次に、その文字列を「=」で区切って「名前」と「中身」に分離する((名前にする変数, 中身にする変数) = split(/=/, 分離させた文字列))。そして、「名前」を見出しにして「中身」を連想配列に入れる($連想配列名{名前} = 中身)。すると、変数の参照時に「名前」を用いる事ができる($連想配列名(見出し)で内容を参照する)ので、簡単にデータを扱う事が可能となる。詳しい事はソースを見ればわかる。と思う。この一連の流れは、連想配列への格納や参照の方法の勉強にもなる。

この他に、色々見なれない命令もあるが、そのうちわかるようになる・・・かもしれない。

ソースコード

#!/usr/bin/perl
 
# 初期設定
# require Jcode;
# $JcodeVer = "Jcode $Jcode::VERSION";
# *Jgetcode = \&Jcode::getcode;
# *Jconvert = \&Jcode::convert;
 
require "../../../cgi-bin/jcode.pl";
$JcodeVer = "jcode.pl $jcode::version";
*Jgetcode = \&jcode::getcode;
*Jconvert = sub { &jcode::to($_[1], $_[0], $_[2]); };
 
@G_styles = ('../../ipp.css','../test.css');
$G_title = 'テスト16';
$G_myCode = &Jgetcode('漢字');
$G_Code = 'jis';
$G_Charset = 'iso-2022-jp';
%G_form=();
 
$G_scrName = $ENV{'SCRIPT_NAME'};
if($G_scrName =~ /ts[0-9]{4}/){
    $G_scrName = $&;
    $G_linkFile = "../$G_scrName.htm";
}
 
{
    &printHeader;
    print "<div class=test>\n";
    
    if($#ARGV == -1){
        &printForm;
    }elsif($ARGV[0] eq "output"){
        &formRead;
        &formWrite;
    }
    
    print "</div>\n";
    &printFooter;
    
    exit;
}
 
sub formWrite{
    local($name, $value);
    print "<table border=1>\n";
    &Jprint("<tr><th>エレメントの名前<th>エレメントの中身</tr>\n");
    while (($name, $value) = each(%G_form)){
        &JconvPrint("<tr><td>$name<td>$value</tr>\n");
    }
    print "</table>\n";
}
 
sub formRead{
    local($query_string, @elements, $elm, $name, $value, $code);
    read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'});
    @elements = split(/&/, $query_string);
    foreach $elm (@elements){
        ($name, $value) = split(/=/, $elm);
        $value =~ s/\+/ /g; # =~ tr/+/ /; と書くのが普通なのか?
        $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg;
        $code = &Jgetcode($value);
        if($code ne 'euc'){ $value = &Jconvert($value, 'euc', $code); } # とりあえずEUCに変換
        $value =~ s/&/&amp;/g;  # メタ文字(?)を無効化
        $value =~ s/</&lt;/g;   # タグを無効化
        $value =~ s/>/&gt;/g;   # タグを無効化
        $value =~ s/\r\n?/\n/g; # 改行を統一
        $value =~ s/\n/<br>/g;  # 改行を<br>に変換
        $G_form{$name} = $value;
    }
}
 
sub printForm{
    print "<form method=post action=\"$ENV{'SCRIPT_NAME'}?output\">\n";
    print "<input type=text name=tx1 value=\"tx1\"><br>\n";
    print "<input type=text name=tx2 value=\"tx2\"><br>\n";
    &Jprint("<textarea name=tx3 cols=40 rows=4>tx3 日本語 英語 どちらでも\nタグなどは無効になります。</textarea><br>\n");
    print "<input type=submit value=\"Submit!\">\n";
    print "</form>\n";
}
 
sub printHeader{
    if($G_Charset){
        print "Content-type: text/html; charset=$G_Charset\n\n";
    }else{
        print "Content-type: text/html\n\n";
    }
    print '<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">'."\n";
    print "<html lang=ja>\n<head>\n";
    if($G_Charset){ print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$G_Charset\">\n"; }
    print '<meta http-equiv="Content-Script-Type" content="text/javascript">',"\n";
    print '<meta http-equiv="Content-Style-Type" content="text/css">'."\n";
    &Jprint ("<title>$G_title</title>\n");
    foreach (@G_styles){ print "<link rel=\"stylesheet\" type=\"text/css\" href=\"$_\">\n"; }
    print "</head>\n<body>\n";
    print "<div class=head>\n";
    &Jprint ("<h1>$G_title</h1><hr>\n");
    &printlinks;
    print "<hr></div>\n";
}
 
sub printFooter{
    print "<div class=foot><hr>\n";
    &printlinks;
    print "<hr>\n";
    &Jprint("漢字コード変換 : $JcodeVer<br>\n");
    open(IN, '../../sig.txt');
    print while (<IN>);
    close(IN);
    print "</div>\n";
    print "</body></html>\n";
}
 
sub printlinks{
    print "<a href=\"../../../index.htm\">Home</a>\n";
	print "/\n<a href=\"../../\">Perl</a>\n";
	print "/\n<a href=\"../\">TestCGI Index</a>\n";
    if($G_linkFile){ &Jprint ("/\n<a href=\"$G_linkFile\">$G_titleの解説</a>\n"); }
}
 
sub Jprint{
    if($G_Code eq $G_myCode){
        foreach (@_){ print; }
    }else{
        foreach (@_){ print &Jconvert($_, $G_Code, $G_myCode); }
    }
}
 
sub JconvPrint{
    foreach (@_){ print &Jconvert($_, $G_Code, &Jgetcode($_)); }
}

カテゴリ:

トラックバック

このエントリーのトラックバックURL:

同一カテゴリの最新記事

最近のエントリー

Amazon.co.jp

Creative Commons License
このブログは、次のライセンスで保護されています。 クリエイティブ・コモンズ・ライセンス.
Powered by
Movable Type 3.36
Amazon.co.jp