- Perlプログラム
Perlは Practical Extraction and Report Language で、文字列のパターン照合と生成が得意な言語です。正規表現によるパターンパッチング、連想記憶機能、などを持ち、webと連携した小規模のサーバー側の処理(CGI)の記述によく利用されています。ここでは、Perl言語の詳細は説明できませんが、どのような処理をしているか、を中心に CGI の処理を説明します。
- CGIの主要な処理
以下が、CGIの先頭のPerlプログラミングです。最初の #!/usr/local/bin/perl は、Perlの処理系の存在する場所を示すもので、サーバーにより異なります。次の use はライブラリの指定で、strict は、厳密な変数のチェックを指示します。Perlの場合、一般には変数の宣言をしないで利用することができますが、strictはあらかじめ変数を宣言しないで利用すると、エラーとして処理します。C言語などになれている人は strict の指定を推奨します。次の use CGI は CGI でよく利用されるCGI系の関数(サブルーティン)を利用するとき、指定します。# 以後の文字は注釈として扱われます。
#!/usr/bin/perl
use strict;#定義のない変数はエラーとする
use CGI qw(:standard);#CGIライブラリを利用する
use CGI::Carp qw(fatalsToBrowser);#重要なエラーを表示する
CGI全体のソースプログラムはこちらを参照してください。
- 変数と関数呼び出し
my $postData は変数$postData を宣言します。my が変数の宣言で、Perlでは変数の先頭には必ず$が必要です。変数は文字列を記録します。数字も文字列として扱われます。
my $postData = &get_PostData();#フォームデータ取得
my $hash_ref = &set_FormData($postData);#フォームデータを連想配列に記録
my %form = %$hash_ref;#連想配列をformの名前で参照する
my $pass='1234';#パスワード
&get_PostData()は、サブルーティン(関数)の呼び出しで、サーバー経由で渡される、フォーム入力の文字列を取得します。 my
$postData = &get_PostData(); はその文字列を変数 $postData に記録します。
my $hash_ref = &set_FormData($postData); #フォームデータを連想配列に記録
my %form = %$hash_ref; #連想配列をformの名前で参照する
では、フォーム入力された文字列を、名前毎に「連想配列」に記録し、その配列を form の名前で参照することを指示します。「連想配列」の利用法は、後で説明します。
my $pass='1234' は、表示や登録で利用するパスワードを設定します。
- 隠しタグによる処理の選択
次に、CGIの処理に入ります。$form{'mode'} は、連想配列の利用で、modeの名前に対応する値を意味します。この値は、Form入力の hidden タイプで指定されています。$form{'mode'}
eq 'record' は $form{'mode'} の値が record に等しい(equal)のとき、真になります。このとき、if( ) はこの条件が満たされたとき、サブルーティン record() を実行します。
if($form{'mode'} eq 'record') {&record();} #フォームデータをファイルに保存
if($form{'mode'} eq 'view') {&view();} #名簿を表示
同様に、if($form{'mode'} eq 'view') {&view();} は、modeの値がview のときサブルーティン view() を実行します。Perlでは if() の後の実行部に必ず {..} が必要です。
- サブルーティン record()
サブルーティン recordで、名簿を記録するファイルに、Formで入力された文字を追記します。まず、
open (InFile,"adrsBook.txt");
my @cont=<InFile>;
close InFile;
で、名簿用のファイル adrsBook.txt を開き(open)、その内容を文字配列 @cont に記録し、いったんファイルを閉じます(close)。InFileはファイルを指定する特殊な変数です。@cont=<InFile> でファイルの内容がすべて @cont にコピーします。次に、項目の入力を確認します。
if(($form{'yomi'} eq "")||($form{'name'} eq "" )||
($form{'mail'} eq "")){#項目確認
&message('入力のない項目があります');
}
各必須項目が 空でないか調べ、空なら、&message('入力のない項目があります'); をホームページに表示して CGI の処理を完了します。次にパスワードをチェックします。ne はnot
equal で等しくないと 真 になります。
if(($form{'pwd'} ne $pass)){#パスワード確認
&message('入力を確認して下さい');
}
次に、フォームで入力された各文字列を、<> で区切りながら1行も文字に合成して変数 $newst に記録し、先に読み出したファイルの内容 @cont の末尾に push で追加し、これを、名簿ファイル adrsBook.txt に書き出します。
my $newst="$form{'yomi'}<>$form{'name'}<>$form{'adrs'}<>$form{'mail'}<>$form{'phone'}<>\n";
open (OutFile,">adrsBook.txt");
shift @cont; #先頭行を削除する
push (@cont,$newst); #最後に$newstを付加する
print OutFile @cont; #ファイルに記録する
close OutFile; #ファイルを閉じる
>adrsBook.txt の > はファイルに書き込むことを意味します。print OutFIle で書き込み、close でファイルを閉じます。
最後に、処理終了を示す html 記述を作成します。html作成については、次の項目で説明します。
- サブルーティン view()
サブルーティンviewでは、名簿ファイルを読み出し、表示する html 記述を生成します。まず、先頭で、パスワードをチェックし、一致しない場合、メッセージを表示し終了します。
次に、openでファイルを開き、&headerで html のヘッダ記述を生成し、&start_html('名簿')で <BODY>タグまで生成します。
while(<InFile>) でファイルから1行ずつ読みながら、各行を <> で項目に分解し、$yomi,$name..などの変数に記録します。
my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/);
printは、qq( ) の内容を標準出力に出力します。
Perlからの標準出力は、webサーバーに接続され、そのまま、ブラウザに送られます。したがって、<TABLE>以下の html タグがブラウザに送られます。これ以前の、html記述は header() や start_html() サブルーティンで送られています。header や start_htmlは CGI ライブラリで定義されているサブルーティンです。以下はファイルを読みながら、htmlは吐き出すプログラムです。
open (InFile,"adrsBook.txt");#名簿ファイルを開く
print &header(-type=>'text/html;charset=Shift_JIS');#htmlヘッダーを生成
print &start_html('名簿');#html出力を開始
while(<InFile>){
print qq(<TABLE>);#表の出力を開始
my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/);#項目に分解
print qq(<TR><TD>名前(よみ)</TD><TD>$yomi<BR></TD>);
print qq(<TR><TD>名前(漢字)</TD><TD>$name<BR></TD>);
print qq(<TR><TD>住所</TD><TD>$adrs</TD>);
print qq(<TR><TD>E-Mail</TD><TD>$mail</TD>);
print qq(<TR><TD>電話番号</TD><TD>$phone</TD>);
print qq(</TABLE><BR><BR>);
}
close InFile;
最後に、元のページに戻るリンクを作成し、end_html() で </BODY></HTML>を出力して、ページをしめます。
print qq(<a href=adrsBook.htm> 戻る</a>);
print &end_html();#html出力を終了
- ファイルとデフォルト変数
<InFile>はファイルの内容を意味し、 $st=<IN> で<IN>からの次の1行が $st に記録されます。while(<InFile>)は、while($_=<InFile>) の意味で、ファイルからの行が $_ に記録されます。変数が省略されている場合は、自動的に $_ が省略されたものとして扱われます。したがって、次の
my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/)
は
my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/,$_)
の意味で、ファイルからの1行が各変数に記録されます。
- get_PostData()
get_PostDataは、環境変数のREQUEST_METHODの値を $ENV{'REQUEST_METHOD'} で取得し、GETであれば 環境変数の $ENV{'QUERY_STRING'} から、そうでなければ(POSTなら) 標準入力:STDIN から、FORMの入力を 読みとります。
read( STDIN, $data, $ENV{'CONTENT_LENGTH'});
は、STDINから、$ENV{'CONTENT_LENGTH'} の文字数だけ、$data にデータを読みとります。
- 環境変数
環境変数は、システムからアプリケーションに渡す変数で、システム(この場合webサーバー)から種々の値が渡されます。Perlおではそれの値を連想配列 $ENV から受け取ることができます。
- set_FormData()
Formからのデータを容易に参照できるよう、連想配列に記録します。まず、引数で受け取ったFormデータの文字列を shift して、$dataに保存します。Formの各項目の値は & によって連結されていますから、これを split(/&/,$data) で分割し、各項目の値を配列 @pair に記録します。
my $data=shift;
my @pair=split(/&/,$data);
my %hash;my $key;
foreach(@pair){
my($key,$value)=split(/=/);
$key=&uri_decode($key);
$hash{$key}=&uri_decode($value);
#print "form:$key\n";
};
return \%hash;
}
各項目の値は 名前 = 値 の形式で記録されていますから、@pairの各項目ごとに(foreach)、 split(/=/) で = の前後に分割し、($key,$value)に記録します。$keyがFormのInput項目の名前、$value がその値となります。&key の値を URLデコードし(後述)、 $hash{$key}=&uri_decode($value); で、hash配列に記録します。これで、たとえば、$hash{'name'} で、'name'の名前で記録されている値を取り出すことができます。
- サブルーティンの引数
Perlでは、サブルーティンの引数を、@_ の名前の配列から受け取ります。この名前はデフォルトになっており、配列名の指定が場合は、@_が指定されたものとして扱われます。(配列でない単なる変数の場合はデフォルト変数は $_ となります)この関数で先頭の $data=shift; は $data=shift @_ ; の意味で、@_が省略されています。
- 配列とshift.push
Perlでは配列はリストとして実現されています。配列の先頭のデータを取り出すのは shift() 、先頭にデータを追加するには unshift() サブルーティンを利用します。一方、配列の最後にデータを追加するのは push()、取り出すには pop() サブルーティンを利用します。
C言語と同様、配列 @A に対して、@a[i] のような処理も可能ですが、Perlでは配列はリストで構成されていますから、配列の先頭や最後へのアクセスには、これらのサブルーティンを利用する方が効率が良いのです。
- uri_decode()
ここでは、Perlの強力な文字列のマッチング処理を用いて、指定した文字列を他の文字列に変換します。たとえば、 $str
=~ tr/+/ /g は、文字 + を 空白の文字(スペース)に変換します。/g はすべての + を置き換えることを指定します。
$str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))
は少しわかりずらい処理ですが、%で始まる16進文字に変換されている漢字を、元の漢字コードに戻します。これらは、URLエンコードされたFormデータを元に戻す処理に相当します。以下は、htmlのタグに利用されてる特殊文字を、同じ記号の表示用文字列に変換します。たとえば < は < に変換されます。この変換で、入力にタグを指定しても、htmlのタグではなく文字列と解釈されます。tr/ による処理は文字単位で、 s/ による処理より高速です。
$str =~ s/&/&/g;#タグ用記号
$str =~ s/"/"/g;#タグ用記号
$str =~ s/</</g;#タグ用記号
$str =~ s/>/>/g;#タグ用記号
- message()
このサブルーティンは、引数のメッセージをホームページとして表示し、表示後 exit で処理をうち切ります。主にエラーメッセージの表示に利用します。