=encoding euc-jp
=head1 名前
CGI - 簡単なCGI(Common Gateway Interface)クラス
=head1 概要
# 画面一杯のフォームを作成し、その値をエコーバックする
# CGIスクリプト
use CGI qw/:standard/;
print header,
start_html('A Simple Example'),
h1('A Simple Example'),
start_form,
"What's your name? ",textfield('name'),p,
"What's the combination?", p,
checkbox_group(-name=>'words',
-values=>['eenie','meenie','minie','moe'],
-defaults=>['eenie','minie']), p,
"What's your favorite color? ",
popup_menu(-name=>'color',
-values=>['red','green','blue','chartreuse']),p,
submit,
end_form,
hr;
if (param()) {
print "Your name is",em(param('name')),p,
"The keywords are: ",em(join(", ",param('words'))),p,
"Your favorite color is ",em(param('color')),
hr;
}
=head1 要約
このperlライブラリは簡単にWebのフォームを作成し、その内容を解析する
ためperl5オブジェクトを使っています。このパッケージはCGIオブジェクト、
現在の問い合わせ文字列の値が入ったエンティティ、そしてその他の状態変数を
定義します。CGIオブジェクトのメソッドを使って、スクリプトに渡された
キーワードやパラメータの値をチェックしたり、現在の取り合わせから
取得した値で初期化したフォームを作成することが出来ます(これによって
状態情報を保存します)。このモジュールはHTMLを生成し、入力と
コーディング・エラーを減らす短い名前の関数を提供します。またファイルの
アップロード、カスケーディング・スタイル・シート、サーバ・プッシュ、
フレームを含めたCGIスクリプトのいくつかのさらに進んだ機能も提供します。
CGI.pmはオブジェクト指向の機能を必要としない人たちのために、簡単な
関数指向プログラミング・スタイルも提供します。
CGI.pmの現在のバージョンは以下のサイトから利用できます:
http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html
ftp://ftp-genome.wi.mit.edu/pub/software/WWW/
=head1 説明
=head2 プログラミング・スタイル
CGI.pmでは2つのプログラミング・スタイル、オブジェクト指向スタイルと
関数指向スタイルがあります。オブジェクト指向スタイルでは、1つまたは
複数のCGIオブジェクトを作成し、ページのさまなざな要素を作成するために
オブジェクト・メソッドを使います。各オブジェクトはサーバーによって
スクリプトに渡された名前付きパラメータのリストが出発点となります。
オブジェクトを変更したり、ファイルやデータベースに格納し、それを元に
戻すことが出来ます。というのも各オブジェクトはCGIスクリプトの
"状態"(state)に対応しており、各オブジェクトのパラメータ・リストは、
その他のものとは独立しているため、スクリプトの状態を保存し後から
取り出すこともできるのです。
以下にオブジェクト指向スタイルを使って、簡単な"Hello World"HTMLページを
どのように作成するかの例を示します:
#!/usr/local/bin/perl -w
use CGI; # CGIルーチンのロード
$q = new CGI; # 新しいCGIオブジェクトの作成
print $q->header, # HTTPヘッダの作成
$q->start_html('hello world'), # HTMLの開始
$q->h1('hello world'), # レベル1のヘッダ
$q->end_html; # HTMLの終わり
関数指向スタイルでは、直接扱うことがまずない、1つのデフォルトの
CGIオブジェクトがあります。CGIパラメータを取り出し、HTMLタグを作成し、
クッキーを管理する等々のために、代りに関数を単に呼び出します。
これは、よりすっきりしたプログラミング・インタフェースを提供しますが、
一度に1つのCGIオブジェクトしか使えないよう制限します。以下の例
は同じページで関数指向インターフェースを使っています。大きな違いは
今度は名前空間に関数のセット(通常は"standard"の関数群)をインポートする
必要があること、そしてCGIオブジェクトを作成する必要がないことです。
#!/usr/local/bin/perl
use CGI qw/:standard/; # 標準(standard)のCGIルーチンをロードする
print header, # HTTPヘッダの作成
start_html('hello world'), # HTMLの開始
h1('hello world'), # レベル1のヘッダ
end_html; # HTMLの終わり
このドキュメントの例では主にオブジェクト指向スタイルを使います。
CGI.pmでの関数指向プログラミングについての重要な情報は「関数のインポート方法」を
ご覧下さい。
=head2 CGI.PMルーチンの呼び出し
ほとんどのCGI.pmルーチンはさまざまな引数を受け取ります。中には20もの
オプションの引数を受取るものもあります!このインターフェースを簡単に
するため、すべてのルーチンは以下のような名前付き引数呼び出しスタイルを
使います:
print $q->header(-type=>'image/gif',-expires=>'+3d');
各引数の名前の前にはダッシュがつきます。引数リストでは大文字/小文字や、
順番は問題になりません。-type、-Type、-TYPEのすべてが受取られます。
実際には、最初の引数だけがダッシュから始まる必要があります。最初の
引数にダッシュがあれば、CGI.pmは後のものにもダッシュがあるものとします。
さまざまなルーチンは一般に1つの引数だけで呼ばれます。それらのルーチンの
場合、引数名なしに1つの引数を与えることが出来ます。header()は、そうした
ルーチンの1つです。この場合、1つの引数はドキュメント・タイプです。
print $q->header('text/html');
他のそのようなルーチンは下記で記述しています。
名前付き引数はあるときはスカラを期待し、あるときは配列へのリファレンス、
あるいはハッシュへのリファレンスを期待します。多くの場合、どんな種類の
引数も渡すことができ、ルーチンはそれに対して最も適切なことを行います。
例えばparam()ルーチンはCGIパラメータに1つあるいは複数の値を設定する
ために使われます。2つのケースを以下に示します:
$q->param(-name=>'veggie',-value=>'tomato');
$q->param(-name=>'veggie',-value=>['tomato','tomahto','potato','potahto']);
CGI.pmのルーチンの多くがモジュール内で特に定義されておらず、必要に応じて
自動的に生成されます。これらは動的に生成されるページで使われ、HTMLを
生成する"HTMLショートカット"ルーチンです。HTMLタグは属性(タグ自身に
入っている属性="値"の組)と内容(開始と終了の組の間の部分)の両方を持ちます。
属性と内容とを区別するため、CGI.pmはHTML属性をハッシュ・リファレンスで最初の
引数として、そして内容があればその後の引数として、渡すような約束を使っています。
それは以下のように機能します:
コード 作成されるHTML
---- --------------
h1()
h1('some','contents'); some contents
h1({-align=>left});
h1({-align=>left},'contents'); contents
HTMLタグについては後で詳しく記述します。
CGIを使い始めたばかりの人の多くが、HTMLタグ属性を囲む曲括弧を必要とする
HTMLショートカットの呼び出し方と、曲括弧無しに属性の生成を管理する他の
ルーチンの呼び出し方との違いに惑わされます。混乱しないで下さい。便宜上、
曲括弧はHTMLを除くすべてでオプションです。もし好きであれば、名前付き
引数を取る全てのルーチンも呼び出すときに曲括弧を使うことが出来ます。
例えば:
print $q->header( {-type=>'image/gif',-expires=>'+3d'} );
B<-w>スイッチを使うと、いくつかのCGI.pm引数はPerl組込関数と名前が
ぶつかっていることを警告されるでしょう。これらのほとんどは、
複数の値を持つメニュー(multi-valued menu)、ラジオボタン(radio button)、
クラスター(cluster)などを作成するために使われる-values引数です。
この警告を回避するためには、いくつかの選択肢があります:
=over 4
=item 1.
もし他の名前が使えれば、引数に他の名前を使う。
例えば-valueは-valuesのための別名です。
=item 2.
先頭を大文字化する。例. -Values
=item 3.
引数名の周りをクォートで囲む。 例. '-values'
=back
多くのルーチンが理解できない名前付き引数についても、なんらかの有効なことを
行います。例えば、名前付きの引数として与えることにより標準ではない
HTTPヘッダ・フィールドを作成することが出来ます:
print $q->header(-type => 'text/html',
-cost => 'Three smackers',
-annoyance_level => 'high',
-complaints_to => 'bit bucket');
これは以下の標準ではないHTTPヘッダを作成します:
HTTP/1.0 200 OK
Cost: Three smackers
Annoyance-level: high
Complaints-to: bit bucket
Content-type: text/html
アンダースコアが自動的にハイフンに変換される方法について注意してください。
HTML作成ルーチンは異なる変換をします。
この機能はHTTPとHTMLの"標準"に迅速に追いかけることを可能にします。
=head2 新しい問い合わせオブジェクトの作成(オブジェクト指向スタイル):
$query = new CGI;
これは(POSTとGETメソッドの両方からの)入力を解析し、
$queryと呼ばれるperl5オブジェクトに格納します。
=head2 入力ファイルからの新しい問い合わせオブジェクトの作成
$query = new CGI(INPUTFILE);
もしファイル・ハンドルをnew()メソッドに与えると、ファイル(またはSTDINでもなんでも)
からパラメータを読み込みます。デバッグ中、ファイルには以下に説明する
形式ならば、何にでもすることができます(つまり改行で区切られたタグ=値の組が機能します)。
便利なことに、このファイルのタイプはsave()メソッドにより作成されます。
複数のレコードを保存し、元に戻すことが出来ます。
Perl純粋主義者はこの文法がファイル・ハンドルを、ファイルハンドル・グロブさえも
受取ることを知って喜ぶでしょう、これはファイルハンドルを渡す"公式の"方法です:
$query = new CGI(\*STDIN);
CGIオブジェクトをFileHandleまたはIO::Fileオブジェクトで初期化することも
出来ます。
関数指向インターフェースを使っていて、CGI状態をファイル・ハンドルで
初期化したければ、Bでおこないます。これはデフォルトの
CGIオブジェクトを指定されたファイル・ハンドルで(再)初期化します。
open (IN,"test.in") || die;
restore_parameters(IN);
close IN;
連想配列リファレンスから問い合わせオブジェクトを初期化することも出来ます:
$query = new CGI( {'dinosaur'=>'barney',
'song'=>'I love you',
'friends'=>[qw/Jessica George Nancy/]}
);
あるいは適切にフォーマットされた、URLエスケープされた問い合わせ文字列から:
$query = new CGI('dinosaur=barney&color=purple');
あるいは既に存在しているCGIオブジェクトから(現在、これはパラメータ・リストの
複製を作りますが、autoescapingのようなオブジェクト特有のフィールドは
複写しません):
$old_query = new CGI;
$new_query = new CGI($old_query);
空の問い合わせを作成するためには、空文字列または空のハッシュで初期化します:
$empty_query = new CGI("");
-または-
$empty_query = new CGI({});
=head2 問い合わせからのキーワードのリストの取り出し:
@keywords = $query->keywords
検索の結果としてスクリプトが呼び出されれば、解析されたキーワードは
keywords()メソッドを使って配列として取得することが出来ます。
=head2 スクリプトの渡された全てのパラメータの名前の取り出し:
@names = $query->param
パラメータ付きでスクリプトが呼び出されると(例えば"name1=value1&name2=value2&name3=value3")、
param()メソッドはパラメータ名をリストで返します。もしスクリプトがスクリプトとして
呼び出され、アンパサンドのない文字列が入っていれば(例えば、"value1+value2+value3")、
"+"で区切られたキーワードが入った"keywords"という名前の1つのパラメータになります。
注意:バージョン1.5では、パラメータ名の配列はブラウザにより実行されたのと
同じ順番でした。通常、この順序はパラメータがフォームで定義された順と
同じです(しかしながら仕様には入っていないため保証はされません。)
=head2 1つの名前つきパラメータの値を取り出す:
@values = $query->param('foo');
-または-
$value = $query->param('foo');
名前付きパラメータの値を取り出すためにparam()メソッドに1つの引数を
渡してください。もしそのパラメータが複数の値を持っていれば
(例えばスクローリング・リスト(scrolling list)での複数の選択から)、
配列で受取るようにすることが出来ます。そうでなければ、このメソッドは
1つの値を返します。
もし値が問い合わせ文字列で与えられなければ、つまり問い合わせで
"name1=&name2=""または"name1&name2"であれば、空文字列を返します。
これは2.63での新機能です。
=head2 名前つきパラメータへの値の設定:
$query->param('foo','an','array','of','values');
これは名前付きパラメータ'foo'の値として値の配列を設定します。これは、
スクリプトが前に一度呼び出された後にフィールドの値を変更するための1つの
方法です。(もう1つの方法はフォーム要素を作成するすべてのメソッドで
受取られる -overrideパラメータを使うことです)
param()は下記でさらに詳しく記述する呼び出しの名前付きパラメータ形式も
理解します:
$query->param(-name=>'foo',-values=>['an','array','of','values']);
-あるいは-
$query->param(-name=>'foo',-value=>'the value');
=head2 名前つきパラメータに値を追加する:
$query->append(-name=>'foo',-values=>['yet','more','values']);
これは値または値のリストを名前付きパラメータに追加します。
既にあれば、その値はパラメータの最後に追加されます。そうでなければ
パラメータが作成されます。このメソッドは名前付き引数呼び出し書式しか
理解しないことに注意してください。
=head2 すべてのパラメータの名前空間へのインポート:
$query->import_names('R');
これは一連の変数を'R'名前空間に作成します。例えば$R::foo、@R:fooのように。
キーワード・リストでは、変数@R:keywordがあります。名前空間が指定されなければ、
この引数は'Q'を想定します。警告:'main'には何もインポートしないこと。
それはセキュリティ上、大きな危険性があります!!!
古いバージョンでは、このメソッドはBと呼ばれていました。
バージョン2.20では、組込PerlモジュールB演算子とぶつかることを
避けるため、この名前は完全に削除されました。
=head2 パラメータを完全に削除する:
$query->delete('foo','bar','baz');
これは完全にパラメータをクリアします。それはスクリプト呼び出しの間で、
渡されたものが欲しくないパラメータをリセットするのに便利なこともあります。
関数呼び出しインターフェースを使っているのであれば、Perlの組込み演算子delete
との衝突を避けるため、代りに"Delete()"を使ってください。
=head2 すべてのパラメータを削除する:
$query->delete_all();
これはCGIオブジェクトを完全にクリアします。これはフォームを作成するときに、
すべてのデフォルトが取られることを保証するために便利です。
関数呼び出しインターフェースを使っているならば、代りにDelete_all()を使って
ください。
=head2 パラメータリストへの直接アクセス:
$q->param_fetch('address')->[1] = '1313 Mockingbird Lane';
unshift @{$q->param_fetch(-name=>'address')},'George Munster';
パラメータ・リストへアクセスする必要があれば、これまでのメソッドでは
カバーされていません。その名前でBを呼び出すことにより、
それへの直接のリファレンスを取得することが出来ます。これは名前付き
パラメータへの配列リファレンスを返します。それは好きなように扱うことが
出来ます。
B<-name>を使って、名前付き引数スタイルを使うことも出来ます。
=head2 パラメータリストのハッシュでの取り出し:
$params = $q->Vars;
print $params->{'address'};
@foo = split("\0",$params->{'foo'});
%params = $q->Vars;
use CGI ':cgi-lib';
$params = Vars;
多くの人がすべてのパラメータリストを、CGIパラメータの名前をキーとし、
そのパラメータの値を値とするハッシュとして取り出しがります。
これをVars()メソッドが行います。スカラコンテキストで呼ばれると、
タイされたハッシュ・リファレンスとしてパラメータリストを返します。
キーを変更すると、元になっているCGIパラメータリストでのパラメータの
値を変更します。配列コンテキストで呼ばれると、それは通常のハッシュ
としてパラメータリストを返します。これによりパラメータリストの内容を
読むことが出来ますが、変更することはできません。
これを使うとき、複数の値を持つCGIパラメータについて気をつけなければ
いけません。ハッシュはスカラーと配列のコンテキストを区別しないので、
複数の値をもつパラメータは"\0"(null)文字で区切られた、パックされた
文字列で返されます。それぞれの値を取り出すためにはパックされた
文字列を分割しなければなりません。このやり方はPerlバージョン4のための
cgi-lib.plモジュールで、Steve Brrennerによって導入されました。
Vars()を関数として使いたければ、関数呼び出しセット :cgi-lib を
インポートしてください。(CGI-LIBとの互換性についてのセクションも
ご覧下さい)
=head2 スクリプトの状態をファイルに保存する:
$query->save(FILEHANDLE)
これはフォームの現在の状態を指定されたファイルハンドルに
書き込みます。new()メソッドにファイルハンドルを与えることにより
読み戻すことが出来ます。ファイルハンドルは、ファイル、パイプ、
その他何にでもにすることが出来ることに注意してください!
保存されるファイルの形式は以下の通りです:
NAME1=VALUE1
NAME1=VALUE1'
NAME2=VALUE2
NAME3=VALUE3
=
名前と値の両方がURLエスケープされます。複数の値を持つCGIパラメータは
名前を繰り返すことにより表すことができます。セッション・レコードは
single=symbolによって範囲を決められます。何回もBを呼ぶことにより、
複数のレコードを書き出し、読み戻すことが出来ます。追記(append)モードで
ファイルを開くことにより、複数のセッションにまたがって、これを行うことが
出来ます、これにより原始的なゲスト・ブックやユーザの質問の履歴を
作成することが出来ます。以下は複数のセッション・レコードを作成する
短い例です:
use CGI;
open (OUT,">>test.out") || die;
$records = 5;
foreach (0..$records) {
my $q = new CGI;
$q->param(-name=>'counter',-value=>$_);
$q->save(OUT);
}
close OUT;
# 読み込みのために再オープン
open (IN,"test.out") || die;
while (!eof(IN)) {
my $q = new CGI(IN);
print $q->param('counter'),"\n";
}
保存/復帰に使われるファイル・フォーマットはWhitehead Genome Centerの
データ交換フォーマット"Boulderio"に使われているものと同じで、
Boulderioユーティリティを使って扱ったり、さらにはデータベース化する
ことができます。さらなる詳細は
http://stein.cshl.org/boulder/
をご覧下さい。
関数指向(非OO)からこの関数を使いたいのであれば、エクスポートされる
このメソッドの名前はBです。
=head2 CGIエラーの取り出し
ユーザ入力を処理して切る間、特にアップロードされたファイルを処理している
間にエラーが発生することがあります。これらのエラーが発生したとき、CGIは
処理を止め、空のパラメータリストを返します。エラーの存在とその性質を
I関数を使って調べることが出来ます。エラーメッセージは
HTTPステータスコードのようにフォーマットされます。HTMLページに
そのエラー・テキストを入れたり、HTTPステータスの値として使うことが
できます:
my $error = $q->cgi_error;
if ($error) {
print $q->header(-status=>$error),
$q->start_html('Problems'),
$q->h2('Request not processed'),
$q->strong($error);
exit 0;
}
関数指向インターフェース(次のセクションをご覧下さい)を使うとき、
エラーは最初にIを呼んだときにだけ発生します。
これに備えてください!
=head2 関数指向インターフェースの使い方
関数指向インタフェースを使うためには、どの CGI.pmルーチンまたは
関数群をスクリプトの名前空間にインポートするかを指定しなければいけません。
このインポートに関連して少しオーバーヘッドがありますが、大したことはありません。
use CGI <メソッドのリスト>;
リストに入れられたメソッドは現在のパッケージにインポートされます;
CGIオブジェクトを最初に作成することなく直接呼び出すことが出来ます。
この例ではどのようにBとBメソッドをインポートし、それらを
直接使うかを示しています:
use CGI 'param','header';
print header('text/plain');
$zipcode = param('zipcode');
さらに多くの場合、名前でグループを参照することにより一般的な関数の組を
インポートします。すべての関数の組の前には":html3"(HTML3標準で定義されたタグ用)
のように、前に":"がつきます。
以下にインポートできる関数の組のリストを示します:
=over 4
=item B<:cgi>
B, Bのような、CGIを扱うすべてのメソッドをインポート
します。
=item B<:form>
Bのような、フォームを作成するメソッドをインポートします。
=item B<:html2>
HTML 2.0 標準要素を作成するすべてのメソッドをインポートします。
=item B<:html3>
HTML 3.0 標準要素を作成するすべてのメソッドをインポートします。
(、 そしてのような)
=item B<:html4>
HTML 4 標準要素を作成するすべてのメソッドをインポートします。
(, そして のような)
=item B<:netscape>
Netscape特有のHTML拡張を作成するすべてのメソッドをインポートします。
=item B<:html>
すべてのHTML作成ショートカットをインポートします(つまり'html2' +
'html3' + 'netscape')...
=item B<:standard>
"標準"の機能をインポートします。, 'html2', 'html3', 'html4', 'form'
そして 'cgi'。
=item B<:all>
利用可能なすべてのメソッドをインポートします。全体のリストはCGI.pmの
コードをご覧下さい。%EXPORT_TAGSという変数が定義されています。
=back
CGI.pmの一部ではない関数名をインポートすると、モジュールはそれを
新しいHTMLタグとして扱い、適切なサブルーチンを作成します。そこで
他のHTMLタグと同じように使うことが出来ます。これは急速に発展する
HTMLの"標準"を提供するためです。例えばMicrosoftはという
新しいタグを発表しています(これはマシンをリブートするまで、
ユーザのデスクトップを回転する斜線でいっぱいにします)。新しい
バージョンのCGI.pmを待つ必要はありません、それをすぐに使って
みてください:
use CGI qw/:standard :html3 gradient/;
print gradient({-start=>'red',-end=>'blue'});
実行スピードの点から、CGI.pmはロード・シンボルを指定するための
標準のLの書式を使わないことに注意してください。これは将来
変更されるかもしれません。
もし状態管理CGI、またはフォーム作成メソッドのいずれかをインポート
すると、あることを要求するメソッドのいずれかを最初に使ったときに、
デフォルトのCGIオブジェクトが自動的に作成され初期化されます。
これにはB, B, B などが含まれます。
(直接CGIオブジェクトにアクセスする必要があれば、
グローバル変数B<$CGI::Q>があります)。CGI.pmメソッドをインポートする
ことによって、以下のようにエレガントなスクリプトを書くことが出来ます:
use CGI qw/:standard/;
print
header,
start_html('Simple Script'),
h1('Simple Script'),
start_form,
"What's your name? ",textfield('name'),p,
"What's the combination?",
checkbox_group(-name=>'words',
-values=>['eenie','meenie','minie','moe'],
-defaults=>['eenie','moe']),p,
"What's your favorite color?",
popup_menu(-name=>'color',
-values=>['red','green','blue','chartreuse']),p,
submit,
end_form,
hr,"\n";
if (param) {
print
"Your name is ",em(param('name')),p,
"The keywords are: ",em(join(", ",param('words'))),p,
"Your favorite color is ",em(param('color')),".\n";
}
print end_html;
=head2 プラグマ
関数セットに加えて、多くのプラグマをインポートすることができます。
プラグマの前には常にハイフンがつき、多くの方法でCGI.pm関数の動きを
変更します。プラグマ、関数セットそして個々の関数はすべて同じuse()行で
インポートすることができます。例えば、以下のuseステートメントは標準の
関数セットをインポートし、デバッグ・モードを不可能にします
(プラグマ -no_debug):
use CGI qw/:standard -debug/;
プラグマの現在の一覧を以下に示します:
=over 4
=item -any
I