CGIを使うメインとも言えるのが「掲示板」じゃないか?ということは、フォームから文字列を取得しなければいけない。たとえそれが日本語でも・・・。
ハッキリ言って仕組みはよくわからない。実際に使っているCGIから拝借しただけ・・・。
フォームの中身はブラウザから送信するときは、特に指定しない限り「application/x-www-form-urlencoded」で出力される(Content-Typeがこれになる)。urlに使えない文字(?)は「%hh」の形で変換(エンコード)された形式。これを元に戻す(デコード)のが次の命令。
1
|
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)」に入力される。この入力を解釈するには以下のようにする。
1
|
read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'});
|
これで、送信されたデータが「$query_string」の中に入力される。「$ENV{‘CONTENT_LENGTH’}」は入力されたバイト数を返す環境変数のようだ。「STDIN」から「$ENV{‘CONTENT_LENGTH’}」バイト分のデータを「$query_string」に代入する。とでも解釈すればいいのか・・・。
この内容は「名前1=中身1&名前2=中身2…」のようになっているため、まず「&」を区切りにして配列に入れる(配列 = split(/&/, 文字列))。次に、その文字列を「=」で区切って「名前」と「中身」に分離する((名前にする変数, 中身にする変数) = split(/=/, 分離させた文字列))。そして、「名前」を見出しにして「中身」を連想配列に入れる($連想配列名{名前} = 中身)。すると、変数の参照時に「名前」を用いる事ができる($連想配列名(見出し)で内容を参照する)ので、簡単にデータを扱う事が可能となる。詳しい事はソースを見ればわかる。と思う。この一連の流れは、連想配列への格納や参照の方法の勉強にもなる。
この他に、色々見なれない命令もあるが、そのうちわかるようになる・・・かもしれない。
ソースコード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#!/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/&/&/g; # メタ文字(?)を無効化
$value =~ s/</</g; # タグを無効化
$value =~ s/>/>/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($_)); }
}
|