by Hippo2000(2000/8/15)
CGIモジュールは、名前のとおりCGIのためのモジュールなのです。元ネタがかなり巨大な上に2.52から2.70へのバージョンアップにも対応したので、訳がボケているかもしれませんが(そりゃいつもか)
原本の著作権はLincoln D. Stein.氏がお持ちです。詳しくは著作権情報をご覧ください。
内容等が間違っていたら修正します。ご連絡ください。
=変更履歴=
2002/9/18 Keigo%加藤さんのご指摘を受けて、CGIエラーの取り出しの誤字を修正
CGI - 簡単なCGI(Common Gateway Interface)クラス
# フォームを作成し、その値をエコーバックする # 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;
}
この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/
CGI.pmでは2つのプログラミング・スタイル、オブジェクト指向スタイルと関数指向スタイルがあります。オブジェクト指向スタイルでは、1つまたは複数のCGIオブジェクトを作成し、ページのさまなざな要素を作成するためにオブジェクト・メソッドを使います。各オブジェクトはサーバーによってスクリプトに渡された名前付きパラメータのリストが出発点となります。オブジェクトを変更したり、ファイルやデータベースに格納し、それを元に戻すことが出来ます。というのも各オブジェクトはCGIスクリプトの"状態"(state)に対応しており、各オブジェクトのパラメータ・リストはその他のものとは独立しているため、スクリプトの状態を保存し、後から取り出すこともできるのです。
以下にオブジェクト指向スタイルを使って、簡単な"Hello World"HTMLページをどのように作成するかの例を示します:
#!/usr/local/bin/perl
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での関数指向プログラミングについての重要な情報は「関数のインポート方法」をご覧下さい。
ほとんどの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>
h1('some','contents'); <H1>some contents</H1>
h1({-align=>left}); <H1 ALIGN="LEFT">
h1({-align=>left},'contents'); <H1 ALIGN="LEFT">contents</H1>
HTMLタグについては後で詳しく記述します。
CGIを使い始めたばかりの人の多くが、HTMLタグ属性を囲む曲括弧を必要とするHTMLショートカットの呼び出し方と、曲括弧無しに属性の生成を管理する他のルーチンの呼び出し方との違いに惑わされます。混乱しないで下さい。便宜上、曲括弧はHTMLを除くすべてでオプションです。もし好きであれば、名前付き引数を取るルーチンを呼び出すすべてのときに曲括弧を使うことが出来ます。例えば:
print $q->header( {-type=>'image/gif',-expires=>'+3d'} );
-w スイッチを使うと、いくつかのCGI.pm引数はPerl組込関数と名前がぶつかっていることを警告されるでしょう。これらのほとんどは、複数の値を持つメニュー(multi-valued menu)、ラジオボタン(radio button)、クラスター(cluster)などを作成するために使われる-values引数です。この警告を回避するためには、たくさんの選択肢があります:
多くのルーチンが理解できない名前付き引数についてもなんらか有効なことをします。例えば、名前付きの引数として与えることにより標準ではない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の"標準"にすばやくついていくことを可能にします。
$query = new CGI;
これは(POSTとGETメソッドの両方からの)入力を解析し、$queryと呼ばれるperl5オブジェクトに格納します。
$query = new CGI(INPUTFILE);
もしファイル・ハンドルをnew()メソッドに与えると、ファイル(またはSTDINでもなんでも)からパラメータを読み込みます。デバッグ中、ファイルには以下に説明する形式ならば、何にでもすることができます(つまり改行で区切られたタグ=値の組が機能します)。便利なことに、このファイルのタイプはsave()メソッドにより作成されます。複数のレコードを保存し、元に戻すことが出来ます。
Perl純粋主義者はこの文法がファイル・ハンドルを、ファイルハンドル・グロブさえも受取ることを知って喜ぶでしょう、これはファイルハンドルを渡す"公式の"方法です:
$query = new CGI(\*STDIN);
CGIオブジェクトをFileHandleまたはIO::Fileオブジェクトで初期化することも出来ます。
関数指向インターフェースを使っていて、CGI状態をファイル・ハンドルで初期化したければ、restore_parameters()でおこないます。これはデフォルトの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({});
@keywords = $query->keywords
<ISINDEX>検索の結果としてスクリプトが呼び出されれば、解析されたキーワードはkeywords()メソッドを使って配列として取得することが出来ます。
@names = $query->param
パラメータ付きでスクリプトが呼び出されれば(例えば、"name1=value1&name2=value2&name3=value3")、param()メソッドはパラメータ名をリストで返します。もしスクリプトが<ISINDEX>スクリプトとして呼び出され、アンパサンドのない文字列が入っていれば(例えば、"value1+value2+value3")、"+"で区切られたキーワードが入った"keywords"という名前の1つのパラメータになります。
注意:バージョン1.5では、パラメータ名の配列はブラウザにより実行されたのと同じ順番でした。通常、この順序はパラメータがフォームで定義された順と同じです(しかしながら仕様には入っていないので、保証はされません。)
@values = $query->param('foo');
-または-
$value = $query->param('foo');
名前付きパラメータの値を取り出すためにparam()メソッドに1つの引数を渡してください。もしそのパラメータが複数の値を持っていれば(例えばスクローリング・リスト(scrolling list)での複数の選択から)、配列で受取るようにすることが出来ます。そうでなければ、このメソッドは1つの値を返します。
もし値が問い合わせ文字列で与えられなければ、つまり問い合わせで"name1=&name2=""または"name1&name2"であれば、空文字列を返します。これは2.63での新機能です。
$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');
$query->append(-name=>'foo',-values=>['yet','more','values']);
これは値または値のリストを名前付きパラメータに追加します。既にあれば、その値はパラメータの最後に追加されます。そうでなければパラメータが作成されます。このメソッドは名前付き引数呼び出し書式しか理解しないことに注意してください。
$query->import_names('R');
これは一連の変数を'R'名前空間に作成します。例えば$R::foo、@R:fooのように。キーワード・リストでは、変数@R:keywordがあります。名前空間が指定されなければ、この引数は'Q'を想定します。警告:何も'main'にインポートしないこと、これはセキュリティ上、大きな危険性があります!!!
古いバージョンでは、このメソッドは import()と呼ばれていました。バージョン2.20では、組込Perlモジュールimport演算子とぶつかることを避けるため、この名前は完全に削除されました。
$query->delete('foo');
これは完全にパラメータをクリアします。それはスクリプト呼び出しの間で、渡されたものが欲しくないパラメータをリセットするのに、ときどき便利です。
関数呼び出しインターフェースを使っているのであれば、Perlの組込みdelete演算子との衝突を避けるため、代りに"Delete()"を使ってください。
$query->delete_all();
これはCGIオブジェクトを完全にクリアします。これはフォームを作成するときに、すべてのデフォルトが取られることを保証するために便利です。
関数呼び出しインターフェースを使っているならば、代りにDelete_all()を使ってください。
$q->param_fetch('address')->[1] = '1313 Mockingbird Lane';
unshift @{$q->param_fetch(-name=>'address')},'George Munster';
パラメータ・リストへアクセスする必要があれば、これまでのメソッドではカバーされていません。その名前でparam_fetch()を呼び出すことにより、それへの直接のリファレンスを取得することが出来ます。これは名前付きパラメータへの配列リファレンスを返します。それは好きなように扱うことが出来ます。
-nameを使って、名前付き引数スタイルを使うことも出来ます。
$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との互換性についてのセクションもご覧下さい)
$query->save(FILEHANDLE)
これはフォームの現在の状態を指定されたファイルハンドルに書き込みます。new()メソッドにファイルハンドルを与えることにより読み戻すことが出来ます。ファイルハンドルは、ファイル、パイプ、その他何にでもにすることが出来ることに注意してください!
保存されるファイルの形式は以下の通りです:
NAME1=VALUE1
NAME1=VALUE1'
NAME2=VALUE2
NAME3=VALUE3
=
名前と値の両方がURLエスケープされます。複数の値を持つCGIパラメータは名前を繰り返すことにより表すことができます。セッション・レコードはsingle=symbolによって範囲を決められます。何回もnewを呼ぶことにより、複数のレコードを書き出し、読み戻すことが出来ます。追記(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)からこの関数を使いたいのであれば、このメソッドのエクスポートされた名前はsave_parameters()です。
ユーザ入力を処理して切る間、特にアップロードされたファイルを処理している間にエラーが発生することがあります。これらのエラーが発生したとき、CGIは処理を止め、空のパラメータリストを返します。エラーの存在とその性質をcgi_error() 関数を使って調べることが出来ます。エラーメッセージは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;
}
関数指向インターフェース(次のセクションをご覧下さい)を使うとき、エラーは最初にparam() を呼んだときにだけ発生します。これに備えてください!
関数指向インタフェースを使うためには、どの CGI.pmルーチンまたは関数群をスクリプトの名前空間にインポートするかを指定しなければいけません。このインポートに関連して少しオーバーヘッドがありますが、大したことはありません。
use CGI <メソッドのリスト>;
リストに入れられたメソッドは現在のパッケージにインポートされます;CGIオブジェクトを最初に作成することなく、直接呼び出すことが出来ます。この例ではどのようにparam() と header()メソッドをインポートし、それらを直接使うかを示しています:
use CGI 'param','header';
print header('text/plain');
$zipcode = param('zipcode');
さらに多くの場合、名前でグループを参照することにより一般的な関数の組をインポートします。すべての関数の組の前には":html3"(HTML3標準で定義されたタグ用)のように、前に":"がつきます。
以下にインポートできる関数の組のリストを示します:
CGI.pmの一部ではない関数名をインポートすると、モジュールはそれを新しいHTMLタグとして扱い、適切なサブルーチンを作成します。そこで他のHTMLタグと同じように使うことが出来ます。これは急速に発展するHTMLの"標準"を提供するためです。例えばMicrosoftは<GRADIENT>という新しいタグを発表しています(これはマシンをリブートするまで、ユーザのデスクトップを回転する斜線でいっぱいにします)。新しいバージョンのCGI.pmを待つ必要はありません、それをすぐに使ってみてください:
use CGI qw/:standard :html3 gradient/;
print gradient({-start=>'red',-end=>'blue'});
実行スピードの点から、CGI.pmはロード・シンボルを指定するための標準のExporterの書式を使わないことに注意してください。これは将来変更されるかもしれません。
もし状態管理CGI、またはフォーム作成メソッドのいずれかをインポートすると、あることを要求するメソッドのいずれかを最初に使ったときに、デフォルトのCGIオブジェクトが自動的に作成され、初期化されます。これにはparam(), textfield(), submit() などが入ります(直接CGIオブジェクトにアクセスする必要があれば、グローバル変数$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;
関数セットに加えて、多くのプラグマをインポートすることができます。プラグマの前には常にハイフンがつき、CGI.pm関数の動きを多くの方法で変更します。プラグマ、関数セットそして個々の関数はすべて同じuse()行でインポートすることができます。例えば、以下のuseステートメントは標準の関数セットをインポートし、デバッグ・モードを不可能にします(プラグマ -no_debug):
use CGI qw/:standard -debug/;
プラグマの現在の一覧を以下に示します:
use CGI qw(-any);
$q=new CGI;
print $q->gradient({speed=>'fast',start=>'red',end=>'blue'});
anyを使うとタイプを間違えたメソッド名がHTMLタグとして解釈されるので、使うときには注意するか、まったく使わないかのどちらかにしてください。
use CGI qw(-compile :standard :html3);
または以下のようにさえも
use CGI qw(-compile :all);
このようにして-compile プラグマを使うことは、常にコンパイルされた関数が現在の名前空間にインポートされる効果を持つことに注意してください。インポートすることなしにコンパイルしたければ、代りにcompile()メソッドを使ってください。(下記をご覧下さい)
?name=fred;age=24;favorite_color=3
セミコロン区切りの問い合わせ文字列は常に受取られますが、 -newstyle_urls プラグマが指定されなければ、self_url()やquery_string()では出力されません。
これはバージョン2.64でデフォルトになりました。
use CGI qw(-no_debug :standard);
一時ファイルが他のCGIスクリプトが読むことが出来ないことを保証するには、スクリプトを実行するためにsuEXEC または CGI ラッパを使ってください。一時ファイルはモード 0600(ワールドもグループも読むことが出来ない)で作成されます。
一時ディレクトリは以下のアルゴリズムを使って選択されます:
1. 現在のユーザ(例えば"nobody")がホーム・ディレクトリに"tmp"と
いうディレクトリを持っていれば、それを使います(Unixシステムのみ)
2. 環境変数TMPDIRがあれば、示された場所を使います
3. そうでなければ、以下の場所を当たります /usr/tmp, /var/tmp, C:\temp,
/tmp, /temp, ::Temporary Items, and \WWW_ROOT.
それぞれの場所はそれがディレクトリであるか、書きこみ可能かをチェックされます。そうでなければアルゴリズムは次の選択を挑戦します。
メソッドの多くがHTMLを作成します。下記で説明するように、タグ関数は自動的に開始と終了の両方のタグを自動的に作成します。例えば:
print h1('Level 1 Header');
は 以下のものを作成します。
<H1>Level 1 Header</H1>
ときには開始と終了タグを自分自身で作成したいときがあるでしょう。この場合、以下のようにstart_タグ名とend_タグ名の形式を使うことができます:
print start_h1,'Level 1 Header',end_h1;
いくつかの例外がありますが(下記で説明)、start_タグ名とend_タグ名関数はuse CGIしたときに自動的に作成されません。しかし、その名前の前にアスタリスクを置くか、あるいは代わりに"start_タグ名"または"end_タグ名"をインポート・リストに要求することによって、start/end 関数を作成したいタグを指定することができます。
例:
use CGI qw/:standard *table start_ul/;
この例では、標準の関数に加えて以下の関数が作成されます:
CGI.pmの関数ほとんどは実行中にドキュメントを作成することを扱います。一般的にはまずHTTPヘッダを作成し、その後にドキュメントそのものがつきます。CGI.pmはHTMLを作成するのと同じくらい、多くのさまざまなHTTPヘッダを作成するための関数を提供します!GIFイメージの作成については、GD.pmモジュールをご覧ください。
これらの関数のそれぞれはHTMLやHTTPの一部を作成します。それらは直接出力できるので、ブラウザ・ウィンドウに表示したり、文字列を追加したり、後で使うようにファイルに保存したりといったことができます。
通常、CGIスクリプトで最初にやることはHTTPヘッダを出力することです。これはブラウザに予想されるドキュメントのタイプを伝え、言語や有効期限、ドキュメントをキャッシュするかどうかといった他のオプションの情報を与えます。ヘッダは、サーバー・プッシュやペイ・パー・ビューといった特別な目的のために使われることもあります。
print $query->header;
-または-
print $query->header('image/gif');
-または-
print $query->header('text/html','204 No response');
-または-
print $query->header(-type=>'image/gif',
-nph=>1,
-status=>'402 Payment required',
-expires=>'+3d',
-cookie=>$cookie,
-charset=>'utf-7',
-attachment=>'foo.gif',
-Cost=>'$2.00');
header()はContent-type:ヘッダを返します。もし選択すれば、独自のMIMEタイプを作成することができます。そうでなければデフォルトはtext/htmlです。オプションの2番目のパラメータはステータス・コードと人間が読むことができるメッセージを指定します。例えば、204、"No response"を指定すると、ブラウザに何もしないように伝えるスクリプトを作ることができます。
最後の例は、CGIメソッドへ引数を渡すための名前付き引数スタイルを示しています。理解されるパラメータは-type, -status, -expires, そして -cookieです。他の名前がついたパラメータはすべて、最初のハイフンを落とされて、ヘッダ・フィールドに変えられます、あなたが望むすべてのHTTPヘッダを指定することが可能です。内部のアンダースコアはハイフンに変換されます:
print $query->header(-Content_length=>3002);
ほとんどのブラウザはCGIスクリプトからの出力をキャッシュしません。スクリプトが新たに呼び出されるたびに、ブラウザはページをリロードします。この動きは-expiresで変更することができます。このパラメータで絶対または相対の有効期間を指定すると、いくつかのブラウザとプロキシー・サーバは指定された有効期限まで、そのスクリプトの出力をキャッシュします。以下の形式はすべて、-expiresフィールドに対して適切です。
+30s 今から30秒
+10m 今から10分
+1h 今から1時間
-1d 昨日(つまり、できるだけ早く!)
now 直後に
+3M 3ヶ月間
+10y 10年間
Thursday, 25-Apr-1999 00:40:33 GMT 指定された時刻と日付
-cookie パラメータはブラウザに、この後このスクリプトとのすべてのトランザクション間、"魔法のクッキー"を提供することを伝えます。Netscapeクッキーは有効期限のような面白い属性が入った特別なフォーマットを持っています。セッション・クッキーを作成し、取り出すためにはcookie()メソッドを使ってください。
-nph パラメータがtrue値に設定されれば、それはNPH(no-parse-header)スクリプトで機能するための正しいヘッダを出力させます。そのすべてのスクリプトがNPHであることを期待する、ある種のサーバで使うことは重要です。
-charset パラメータはブラウザに送信される文字セットを制御するために使うことが出来ます。与えられなければ、デフォルトはISO-8859-1です。副作用として、これはcharset()メソッドも設定します。
-attachment パラメータは添付にページを切り替えるために使うことが出来ます。ページを表示する代りに、ブラウザによってはファイルに保存するためのプロンプトを表示します。引数の値は保存されるファイルのための提案される名前です。これが機能するためには、-typeを"application/octet-stream"にしなければいけないかもしれません。
print $query->redirect('http://somewhere.else/in/movie/land');
ときには、ドキュメントをあなた自身が作成するのではなく、おそらくURLは時刻やユーザの識別子をベースにより選択しながら、単にブラウザをどこかにリダイレクトしたいだけかもしれません。
redirect()関数はブラウザを他のURLにリダイレクトします。もしこのようなリダイレクトを使えば、headerも出力してはいけません。
私が提案できる、1つのヒントはあなたのサイトの別のドキュメントへのリダイレクトを作成したとき、相対リンクは正しく機能しません。これは、いくつかのサーバが使うよく考えられた最適化によるものです。それを解決する方法はリダイレクトするドキュメントの(http:部分も含めた)フルのURLを使うことです。
名前付き引数も使うことができます:
print $query->redirect(-uri=>'http://somewhere.else/in/movie/land',
-nph=>1);
-nph パラメータがtrue値に設定されれば、それはNPH(no-parse-header)スクリプトで機能するための正しいヘッダを出力させます。Microsoft Internet Information Server (訳者注:原文では Internet Explorer)のように、そのすべてのスクリプトがNPHであることを期待する、ある種のサーバで使うのは重要です。
print $query->start_html(-title=>'Secrets of the Pyramids',
-author=>'fred@capricorn.org',
-base=>'true',
-target=>'_blank',
-meta=>{'keywords'=>'pharaoh secret mummy',
'copyright'=>'copyright 1996 King Tut'},
-style=>{'src'=>'/styles/style1.css'},
-BGCOLOR=>'blue');
HTTPヘッダを作成した後、ほとんどのCGIスクリプトはHTMLドキュメントの出力を始めます。start_html()ルーチンはページの見た目や動きを制御するたくさんのオプションの情報とともに、ページの先頭を作成します。
このメソッドは閉じられたHTMLヘッダと開かれた<BODY>タグを返します。全てのパラメータはオプションです。名前付きパラメータ形式で、理解されるパラメータは-title, -author, -base, -xbase そして -targetです(下記の説明をご覧ください)。Netscapeの非公式のBGCOLOR属性ような、指定されたすべての追加のパラメータは<BODY>タグに追加されます。追加のパラメータは前にハイフンをつけなければいけません。
引数-xbase は<BASE>タグを現在の位置から変えるためにHREFを提供することを許します。
-xbase=>"http://home.mcom.com/";
すべての相対リンクは、このタグからの相対と解釈されます。
引数 -target はすべてのリンクとページ上のフォームのためのデフォルトのターゲット・フレームを指定することができます。これはNetscapeブラウザでのみ機能する標準でないHTTP機能です。これをどのように扱うかの詳細については、Netscapeのフレームについてのドキュメントをご覧ください。
-target=>"answer_window"
すべての相対リングはこタグの相対だと解釈されます(訳者注:おそらく不要(?_?))。-meta 引数でヘッダに任意のメタ情報を追加します。この引数はメタ情報の名前/値の組が入った連想配列へのリファレンスを期待します。これらは以下のような、ヘッダでの一連の<META>タグに変わります:
<META NAME="keywords" CONTENT="pharaoh secret mummy">
<META NAME="description" CONTENT="copyright 1996 King Tut">
<META>タグのHTTP-EQUIVタイプを作るためには、以下で詰めイする-headを使ってください。
-styleタグはあなたのコードにカスケーディング・スタイルシートを入れるために使われます。さらに詳細な情報は「カスケーディング・スタイルシート」のセクションをご覧ください。
-lang 引数は<HTML>タグにlanguage属性を入れるために使われます。指定されなかったときのデフォルトはUS Englishのための"en-US"です。例:
print $q->header(-lang=>'fr-CA');
-headタグで他の任意のHTML要素を<HEAD>セクションに置くことができます。例えば、あまり使われない<LINK>要素をHEADセクションに置くには、これを使ってください:
print start_html(-head=>Link({-rel=>'next',
-href=>'http://www.capricorn.com/s2.html'}));
HTML要素を<HEAD>セクションに入れるためには、単に配列リファレンスを渡してください:
print start_html(-head=>[
Link({-rel=>'next',
-href=>'http://www.capricorn.com/s2.html'}),
Link({-rel=>'previous',
-href=>'http://www.capricorn.com/s1.html'})
]
);
そしてここでHTTP-EQIV<META>タグの作成法を示します:
print header(-head=>meta({-http_equiv => 'Content-Type',
-content => 'text/html'}))
JAVASCRIPTING: -script, -noScript, -onLoad, -onMouseOver, -onMouseOut そして -onUnload パラメータがNetscape JavaScript呼出しをページに追加するために使われます。-scriptはJavaScript関数定義が入ったテキストのブロックを示さなければなりません。このブロックは(HTTPではなく)<HTML>の内部の<SCRIPT>ブロックに置かれます。たとえページが完全にロードされる前にユーザがストップ・ボタンを押したとしても、すべてのJavaScript関数が置かれるチャンスをあなたのページに与えるために、そのブロックはヘッダに置きます。CGI.pmはJavaScriptを知らないブラウザがそのコードで窒息しないような方法で、そのスクリプトをフォーマットしようとします:それにも関らず、残念ながらChimera for Unixのように混乱してしまうブラウザがいくつかあります。
-onLoad と-onUnload パラメータは、それぞれブラウザによってそのページが開かれたときと閉じられたときに実行されるJavaScriptコードを示します。通常これらのパラメータは-script フィールドで定義された関数を呼びます:
$query = new CGI;
print $query->header;
$JSCRIPT=<<END;
// Ask a silly question
function riddle_me_this() {
var r = prompt("What walks on four legs in the morning, " +
"two legs in the afternoon, " +
"and three legs in the evening?");
response(r);
}
// Get a silly answer
function response(answer) {
if (answer == "man")
alert("Right you are!");
else
alert("Wrong! Guess again.");
}
END
print $query->start_html(-title=>'The Riddle of the Sphinx',
-script=>$JSCRIPT);
JavaScriptを持っていないブラウザ(あるいはJavaScriptがオフになっているブラウザ)で表示されるいくつかのHTMLテキストを渡すためには-noScript パラメータを使ってください。
Netscape 3.0 は、LANGUAGEとSRCを含めて、<SCRIPT>タグの多くの属性を理解します。後者はソースを持った各ページに散乱させるのではなく、JavaScriptpコードをファイルまたはCGIスクリプトに保管することを可能にするため、特に興味深いものです。この属性を使うためには、-script パラメータに1つまたはそれ以上の-language、-srcまたは-codeが入ったハッシュ・リファレンスを渡します:
print $q->start_html(-title=>'The Riddle of the Sphinx',
-script=>{-language=>'JAVASCRIPT',
-src=>'/javascript/sphinx.js'}
);
print $q->(-title=>'The Riddle of the Sphinx',
-script=>{-language=>'PERLSCRIPT',
-code=>'print "hello world!\n;"'}
);
最後の機能は複数の<SCRIPT>セクションをヘッダに入れることを可能にします。配列リファレンスとしてスクリプト・セクションのリストを渡すだけです。これはJavaScriptの異なる方言のための異なるソースを指定することができます。例えば:
print $q->start_html(-title=>'The Riddle of the Sphinx',
-script=>[
{ -language => 'JavaScript1.0',
-src => '/javascript/utilities10.js'
},
{ -language => 'JavaScript1.1',
-src => '/javascript/utilities11.js'
},
{ -language => 'JavaScript1.2',
-src => '/javascript/utilities12.js'
},
{ -language => 'JavaScript28.2',
-src => '/javascript/utilities219.js'
}
]
);
</pre>
これがちょっとヒドいと見えれば、私のアドバイスを聞いてストレートなCGIスクリプトで我慢してください。
JavaScriptについての更なる情報については
http://home.netscape.com/eng/mozilla/2.0/handbook/javascript/
をご覧ください。
古いスタイルの位置によるパラメータは以下の通りです。
他のすべてのパラメータは<BODY>タグに入れたいものです。ここは色や壁紙のパターンのような、Netscape拡張を置くのによい場所です。
print $query->end_html
</BODY></HTML> タグを出力することでHTMLドキュメントを終らせます。
$myself = $query->self_url;
print q(<A HREF="$myself">I'm talking to myself.</A>);
self_url()は選択されたとき、今動いているすべての状態情報でこのスクリプトを再度呼び出すURLを返します。内部のアンカーを使ってドキュメントの中でジャンプしたいけれども、フォームの現在の内容を壊したくないときにとても有効です。以下のようにするとうまくいきます。
$myself = $query->self_url;
print "<A HREF=$myself#table1>See table 1</A>";
print "<A HREF=$myself#table2>See table 2</A>";
print "<A HREF=$myself#yourself>See for yourself</A>";
何を返すかを更に制御したければ、代わりにurl()メソッドを使ってください。
処理されていない問い合わせ文字列はquery_string()で取り出すこともできます:
$the_string = $query->query_string;
$full_url = $query->url();
$full_url = $query->url(-full=>1); #alternative syntax
$relative_url = $query->url(-relative=>1);
$absolute_url = $query->url(-absolute=>1);
$url_with_path = $query->url(-path_info=>1);
$url_with_path_and_query = $query->url(-path_info=>1,-query=>1);
url() はスクリプトのURLをさまざまなフォーマットで返します。何も引数がなく呼ばれれば、ホスト名とポート番号を含んだURLのフルの形式を返します。
http://your.host.com/path/to/script.cgi
You can modify this format with the following named arguments:
/path/to/script.cgi
script.cgi
$color = $query->url_param('color');
問い合わせ文字列(引数が後ろについた"?"マーク)が入ったURLへPOSTするフォームを作成することによりフォームと同じように、スクリプトにはCGIパラメータをURLで受け取ることは可能です。param() メソッドは、URLの問い合わせ文字列を無視し、常にPOSTされたフォームの内容を返します。URLパラメータを取り出すためにはurl_param()メソッドを呼び出してください。param()と同じように使ってください。大きな違いはパラメータを読むことができることで、設定はできません。
いかなる状況においても、URL問い合わせ文字列の内容がPOSTされたフォームの同じ名前のCGIパラメータを干渉することはありません。URL問い合わせ文字列とGETメソッドでサブミットされるフォームとを混ぜてみると、その結果はあなたが予想しなかったことになるでしょう。
HTML 3 とHTML 4タグですべてでなければ、CGI.pmは一般的なHTMLショートカットメソッドの大半を定義します。HTMLショートカットは1つのHTMLの後に名づけられ、出力でき、好きなように扱うことができるHTMLテキストの一部を返します。各ショートカットは文字列に追加したり、ファイルの保存したり、または最も一般的にはブラウザ・ウィンドウで表示するように出力することができるHTMLコードを返します。
この例はHTMLメソッドをどのように使うかを示します:
$q = new CGI;
print $q->blockquote(
"Many years ago on the island of",
$q->a({href=>"http://crete.org/";},"Crete"),
"there lived a Minotaur named",
$q->strong("Fred."),
),
$q->hr;
この結果は以下のHTMLコードになります(読みやすくするために改行を入れています)
<blockquote> Many years ago on the island of <a HREF="http://crete.org/";>Crete</a> there lived a minotaur named <strong>Fred.</strong> </blockquote> <hr>
HTMLショートカットの呼出しの書き方が不格好だと思えば、名前空間にインポートし、オブジェクト的な書き方を完全に無くすことができます(詳細は次のセクションをご覧ください):
use CGI ':standard';
print blockquote(
"Many years ago on the island of",
a({href=>"http://crete.org/";},"Crete"),
"there lived a minotaur named",
strong("Fred."),
),
hr;
HTMLメソッドは0、1つまたは複数の引数を受け取ります。もし引数を与えなければ、1つのタグを得ます:
print hr; # <HR>
もし1つまたは複数の文字列引数を与えれば、スペースでつなげられ、開始と終了タグに囲まれます:
print h1("Chapter","1"); # <H1>Chapter 1</H1>"
もし最初の引数が連想配列リファレンスであれば、その連想配列のキーと値はHTMLタグの属性になります:
print a({-href=>'fred.html',-target=>'_new'},
"Open a new frame");
<A HREF="fred.html",TARGET="_new">Open a new frame</A>
もしそうしたければ、属性名の前につくダッシュをはずすことができます:
print img {src=>'fred.gif',align=>'LEFT'};
<IMG ALIGN="LEFT" SRC="fred.gif">
HTMLタグ属性が引数を持たないこともあります。例えば順序付きリストはCOMPACTとして印をつけることができます。この書き方はundef文字列を示す引数になります:
print ol({compact=>undef},li('one'),li('two'),li('three'));
CGI.pmバージョン2.41より以前では、空('')文字列を属性引数として与えることはundefを与えるのと同じでした。しかし、これは<IMG ALT="">形式のタグを作りたい人たちに合わせるために変更されました。違いはこれらの2つのコードで示されます:
コード 結果
img({alt=>undef}) <IMG ALT>
img({alt=>''}) <IMT ALT="">
HTMLショートカットの素晴らしい機能の1つにそれらが分配されることがあります。リストへのリファレンスが入った引数を与えると、そのタグはリストの各要素をまたがって分配されます。例えば、順序付きのリストを作る方法の1つを以下に示します:
print ul(
li({-type=>'disc'},['Sneezy','Doc','Sleepy','Happy'])
);
これは結果として以下のようなHTML出力になります:
<UL>
<LI TYPE="disc">Sneezy</LI>
<LI TYPE="disc">Doc</LI>
<LI TYPE="disc">Sleepy</LI>
<LI TYPE="disc">Happy</LI>
</UL>
これはテーブルを作るのとにとても便利です。例えば:
print table({-border=>undef},
caption('When Should You Eat Your Vegetables?'),
Tr({-align=>CENTER,-valign=>TOP},
[
th(['Vegetable', 'Breakfast','Lunch','Dinner']),
td(['Tomatoes' , 'no', 'yes', 'yes']),
td(['Broccoli' , 'no', 'no', 'yes']),
td(['Onions' , 'yes','yes', 'yes'])
]
)
);
この小さなコードについて考えてみてください:
print blockquote(em('Hi'),'mom!'));
これは通常に、おそらく期待した文字列を返します、すなわち:
<BLOCKQUOTE><EM>Hi</EM> mom!</BLOCKQUOTE>
要素"Hi"と要素"mom!"の間のスページに注意してください。CGI.pmは配列を間に入れた場所に追加のスペースをおきます。これは特別な$"変数により制御されます。時には、例えば、一連のイメージの並べようとしているときなど、この追加のスペースはあなたの望んでいたものではありません。この場合、$"を空文字列に変更することによって簡単に変更することができます。
{
local($") = '';
print blockquote(em('Hi'),'mom!'));
}
コードをここで示したようにブロックにいれることを提案します。そうしなければ明示的にリセットするまで、$"の変更が後のコードに影響を与えます。
いくつかのHTMLタグは多様性のために標準パターンに従いません。
comment() はHTMLコメント(<!-- comment -->)を作成します。以下のように呼び出してください
print comment('here is my comment');
組み込みPerl関数とぶつかるので、以下の関数は先頭の文字が大文字になります:
Select
Tr
Link
Delete
Accept
Sub
さらにstart_html()、end_html()、start_form()、end_form()、start_multipart_form()そしてすべてのフォームタグは特別です。それぞれのセクションをご覧ください。
デフォルトでは、フォーム作成関数用により作成されるすべてのHTMLはescapeHTML()という関数を通ります:
文字セットISO-8859-1(デフォルト)を指定すると、標準のHTMLエスケープのルールが使われます。"<"文字は"<"、">"は">","&"は"&"、クオート文字は"""になります。さらに0x8bと0x9b文字、これは多くのWindowsベースのブラウザは左と右の斜め括弧に解釈されるのですが、は数値のHTMLエントリ("‹"と"›")に置きかえられます。charset()メソッドを明示的に呼び出すか、header()に-charset引数を渡すことにより、手で文字設定を変更したら、CGI.pmはすべての可能性のあるエンコーディングのための検索テーブルを持たないので、すべての文字は数値エントリによりよって置きかえられます。
h1()のような自動エスケープは他のショートカットに適用されません。人々がゲストブックなどにいれるかもしれない困った書き方からあなたのページを守るために、信用できないデータにescapeHTML()を呼ぶべきです。文字セットを変更するには、charset()を使ってください。自動エスケープを完全に止めるには、autoescape()を使ってください:
デフォルトでは、これらの関数により作成されるすべてのHTMLは、改行やインデントのない1つの長い行になります。これは汚いですが、ドキュメントの大きさを10%−20%減らします。きれいな出力を取得するには、Brian Paulsenによって作成されたサブクララスであるCGI::Prettyを使ってください。
一般的な注意点 様々なフォーム・作成メソッドはすべて、呼び出し元に要求されたフォーム要素を作成するタグが入った文字列を返します。あなたはこれらの文字列を実際に出力する責任があります。それはこのように設定されるので、フォーム要素の周りにフォーマットするタグを置くことが出来ます。
他の注意点 フォームに指定するデフォルトの値は、(問い合わせ文字列がない時)スクリプトが呼び出された最初のときだけ使われます。その後のスクリプト呼び出しでは(問い合わせ文字列があるとき)、たとえ空白であっても前の値が使われます。
前の値からフィールドの値を変更したければ2つの選択肢があります:
(1) 設定するためにparam()メソッドを呼び出す。
(2) -override (別名 -force) パラメータを使う(バージョン2.15での新しい機能)。これは前の値に関係なく、デフォルトの値が使われるように強制します:
print $query->textfield(-name=>'field_name',
-default=>'starting value',
-override=>1,
-size=>50,
-maxlength=>80);
さらにもう1つの注意点 デフォルトでは、フォーム要素のテキストとラベルはHTMLルールにしたがってエスケープされます。つまりボタンのためのラベルとして"<CLICK ME>"を安全に使うことが出来ます。しかしそのために、フィールドにÁ のような特殊なHTML文字の並びをいれることができません。自動的なエスケープをオフにしたければ、CGIオブジェクトを作成したすぐあとにautoEscape()メソッドをfalseで呼び出してください:
$query = new CGI; $query->autoEscape(undef);
print $query->isindex(-action=>$action);
-または-
print $query->isindex($action);
<ISINDEX> タグを出力します。あまり面白くはありません。パラメータ -actionは、問い合わせを処理するスクリプトのURLを指定します。デフォルトでは現在のスクリプトで問い合わせを処理します。
print $query->start_form(-method=>$method,
-action=>$action,
-enctype=>$encoding);
<... さまざまなフォームの内容 ...>
print $query->endform;
-または-
print $query->start_form($method,$action,$encoding);
<... さまざまなフォームの内容 ...>
print $query->endform;
startform()は<FORM>タグを指定したオプションのメソッド、アクション、フォーム・エンコーディングと一緒に返します。デフォルトは以下の通りです:
method: POST
action: このスクリプト
enctype: application/x-www-form-urlencoded
endform()は</FORM>タグを返します。
startform()のenctype引数はブラウザがフォームをサーバに送信する前にフォームの様々なフィールドをどのようにパッケージするかを伝えます。以下の2つの値が指定できます:
注意: このメソッドは以前startform()という名前でした。そしてstartform()はまだエリアスとして理解されます。
CGI.pmやそれらを扱うように設計されているほかのライブラリを使わなければ、CGIスクリプトはこのタイプのエンコーディングを使うフォームを簡単には解釈できません。
互換性のため、start_form()メソッドはデフォルトでは古い形を使います。デフォルトで新しい形式を使いたければ、start_form()の代りにstart_multipart_form() を呼ぶことが出来ます。
JAVASCRIPTING: -name と -onSubmit パラメータがJavaScriptでの使用のために提供されています。-nameパラメータはJavaScript関数によって識別され、扱えるようにフォームの名前を与えます。-onSubmitはフォームがサーバにサブミットされる直前に実行されるJavaScript関数を示さなければなりません。この機会を使って、フォームの内容に矛盾がないか、すべて入っているかをチェックすることができます。何かおかしな事を見つけたら、アラートボックスを表示したり、自分でそれを修正するかもしれません。この関数からfalseを返すことによってサブミットを中止することが出来ます。
通常JavaScriptの固まりはHTMLヘッダでの<SCRIPT>ブロックで定義され、-onSubmitはこれらの関数呼び出しの1つを指します。詳細についてはstart_html()をご覧下さい。
print $query->textfield(-name=>'field_name',
-default=>'starting value',
-size=>50,
-maxlength=>80);
-または-
print $query->textfield('field_name','starting value',50,80);
textfield()はテキスト入力フィールドを返します。
これらすべてのメソッドでは、フィールドはそのスクリプトの以前の呼び出しからの内容で初期化されます。フォームが処理されたとき、テキスト・フィールドの値は以下のように取り出すことが出来ます:
$value = $query->param('foo');
そのスクリプトが1度呼び出された後に初期値でリセットしたければ、以下のようにすることが出来ます:
$query->param('foo',"I'm taking over this value!");
2.15での新機能:フィールドをその前の値にしたくなければ、-override(別名 -force)パラメータを使うことにより、現在の値に強制することが出来ます。
print $query->textfield(-name=>'field_name',
-default=>'starting value',
-override=>1,
-size=>50,
-maxlength=>80);
JAVASCRIPTING: JavaScriptイベント・ハンドラを登録するために、-onChange、 -onFocus、-onBlur、-onMouseOver、-onMouseOutそして-onSelect パラメータを提供することが出来ます。onChangeハンドラはユーザがテキスト・フィールドの内容を変更するといつでも呼び出されます。よければテキストの有効性チェックをすることができます。onFocusとonBlurはそれぞれ、挿入ポイントがテキスト・フィールドに入ったとき、テキスト・フィールドから抜けたときに呼ばれます。onSelectは選択されているテキストの部分を変えたときに呼ばれます。
print $query->textarea(-name=>'foo',
-default=>'starting value',
-rows=>10,
-columns=>50);
-or
print $query->textarea('foo','starting value',10,50);
textarea()は、まるでテキストフィールドのようですが、複数行テキスト入力ボックスのために行と列を指定することが出来ます。そのフィールドに開始する値を与えることができます。それは長くしたり、複数行にすることができます。
JAVASCRIPTING: -onChange, -onFocus, -onBlur , -onMouseOver, -onMouseOut, そして -onSelect パラメータが理解されます。textfield()をご覧下さい。
print $query->password_field(-name=>'secret',
-value=>'starting value',
-size=>50,
-maxlength=>80);
-または-
print $query->password_field('secret','starting value',50,80);
password_field()は、その内容がwebページでは星印で表示されることを除いては、textfiled()と同じです。
JAVASCRIPTING: -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut そして -onSelect パラメータが理解されます。textfield()をご覧下さい。
print $query->filefield(-name=>'uploaded_file',
-default=>'starting value',
-size=>50,
-maxlength=>80);
-または-
print $query->filefield('uploaded_file','starting value',50,80);
filefield()はNetscape2.0ブラウザのためのファイル・アップロード・フィールドを返します。利点をすべて生かすためには、そのフォームに新しいマルチパート・エンコーディング・スキームを使わなければなりません。これはエンコーディング・タイプを$CGI::MULTIPARTでstart_form()を呼び出すか、普通のstart_form()の代りに新しいメソッドstart_multipart_form()を呼び出すかのどちらかで行うことが出来ます。
セキュリティ上の理由から、ブラウザはこのフィールドには注意を払いません、そのため初期値は常にブランクになります。さらに悪いことに、フィールドはその"なかなか変わらない"動きを失い、前の内容を忘れてしまいます。しかしHTML仕様では初期値フィールドは要求されています、多分いくつかのブラウザは最終的にはそれをサポートでしょう。
フォームが処理されると、param()を呼ぶことによって入力されたファイル名を取得することが出来ます:
$filename = $query->param('uploaded_file');
ブラウザによってちょっとずつ違う名前を返します。あるブラウザはファイル名だけを返します。あるものはユーザのマシンのパスの書き方を使ったファイルへのフルパスを返します。いずれにせよ返される名前は常にユーザのマシンでのファイル名で、CGI.pmがアップロードのスプーリングのさいに作成する一時ファイルの名前には関連しません(以下をご覧ください)。
返されるファイル名はファイル・ハンドルでもあります。標準のPerlファイル読み込み呼び出しを使ってファイルの内容を読むことが出来ます:
# テキストファイルを読み込み、出力します
while (<$filename>) {
print;
}
# バイナリ・ファイルをどこか安全なところへコピーします
open (OUTFILE,">>/usr/local/web/users/feedback");
while ($bytesread=read($filename,$buffer,1024)) {
print OUTFILE $buffer;
}
しかしアップロード・フィールドの2つの性質に絡んで問題があります。use strictを使っていると、Perlは文字列をファイルハンドルとして使うと文句をいうでしょう。これはファイルの読み込みをno strictプラグマを含んだブロックにいれることで回避することが出来ます。さらに深刻なことは、リモート・ユーザがアップロード・フィールドにゴミをいれると、param()は文字列ではあっても、ファイルハンドルではない可能性があります。
安全のためには、upload()関数(バージョン2.47での新機能)を使ってください。アップロード・フィールドでこれを呼ぶと、upload()はファイルハンドル、もしくはパラメータが正しいファイルハンドルでなければundefを返します。
$fh = $query->upload('uploaded_file');
while (<$fh>) {
print;
}
これは推奨される表現です。
ファイルがアップロードされるとき、ブラウザは通常、ヘッダのフォーマットの中にいくつかの情報を一緒に送信します。その情報には通常、MIME content typeが入っています。将来のブラウザは他の情報も送信するかもしれません(変更日や大きさなのような)。この情報を取り出すためには、uploadInfo()を呼び出してください。それはすべてのドキュメント・ヘッダが入った連想配列へのリファレンスを返します。
$filename = $query->param('uploaded_file');
$type = $query->uploadInfo($filename)->{'Content-Type'};
unless ($type eq 'text/html') {
die "HTML FILES ONLY!";
}
"text"と"binary"データ・モードを理解するマシンを使っていれば、それをいつ、どのように使うかを確認してください(ラクダ本をご覧下さい)。そうでなければ、ファイル・アップロードの間にバイナリファイルがおかしくなるのを発見するでしょう。
ときどきアップロードされたファイルを解析している途中に問題が発生します。それは通常ユーザがアップロードが完了する前に"Stop"を押したときにおこります。
この場合、CGI.pmはアップロードされたファイルの名前の代りにundefをにをcgi_error()に文字列"400 Bad Request (malformed multipart POST)"を設定します。このエラーメッセージはブラウザに送信するステータス・コードに入れることができるように考えられています。例えば:
$file = $query->upload('uploaded_file');
if (!$file && $query->cgi_error) {
print $query->header(-status=>$query->cgi_error);
exit 0;
}
もしも望むなら、エラーについて不満をいうために独自のHTMLページを自由に作ることができます。
JAVASCRIPTING: -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut そして -onSelect パラメータが理解されます。詳細はtextfield()をご覧下さい。
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie');
-または-
%labels = ('eenie'=>'your first choice',
'meenie'=>'your second choice',
'minie'=>'your third choice');
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie',\%labels);
-または (名前付きパラメータ形式)-
print $query->popup_menu(-name=>'menu_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-labels=>\%labels);
popup_menu()はメニューを作成します。
フォームが処理されるとき、ポップアップ・メニューの選択された値は以下のようにして取り出すことが出来ます:
$popup_menu_value = $query->param('menu_name');
JAVASCRIPTING: popup_menuは以下のイベント・ハンドラを理解します:-onChange, -onFocus, -onMouseOver, -onMouseOut, そして-onBlur。いつこれらのハンドラが呼ばれるかの詳細はtextfield()をご覧下さい。
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true');
-または-
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true',
\%labels);
-または-
print $query->scrolling_list(-name=>'list_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-size=>5,
-multiple=>'true',
-labels=>\%labels);
scrolling_list()はスクローリング・リストを作成します。
このフォームが処理されるとき、選択されたリスト要素はパラメータ名'list_name'でのリストとして返されます。選択された要素の値は以下のようにして取り出すことが出来ます:
@selected = $query->param('list_name');
JAVASCRIPTING: scrolling_list()は以下のイベント・ハンドラを理解します: -onChange, -onFocus, -onMouseOver, -onMouseOut そして -onBlur。 いつこれらのハンドラが呼ばれるかの説明はtextfield()をご覧下さい。
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-linebreak=>'true',
-labels=>\%labels);
print $query->checkbox_group('group_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],'true',\%labels);
HTML3互換ブラウザのみ:
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-rows=2,-columns=>2);
checkbox_group()は同じ名前により関連付けられたチェックボックスのリストを作成します。
返されるテーブルでの行と列のヘッダを入れるために、 -rowheaders と -colheaders パラメータを使うことが出来ます。これらは両方とも使用するヘッダの配列へのポインタを受取ります。そのヘッダは単なる飾りです。チェックボックスの解析を理解しません -- それらはまだ名前がついた1つのユニットです。
フォームが処理されるとき、すべてのチェックされたボックスはパラメータ名'group_name'のリストとして返されます。"on"の値のチェックボックスは以下のようにして取り出すことが出来ます:
@turned_on = $query->param('group_name');
checkbox_groupによって返される値は実際にはボタン要素の配列です。以下のようにして、それらを取得し、テーブル、リストその他の作成方法で使うことが出来ます:
@h = $query->checkbox_group(-name=>'group_name',-values=>\@values);
&use_in_creative_way(@h);
JAVASCRIPTING: checkbox_group()は-onClick パラメータを理解します。これは、そのグループの中のボタンのどれかをユーザがクリックするたびに実行される、JavaScriptコードの一部、あるいは関数を指定します。"this"変数を使って、クリックされたボタンの識別子を取り出すことが出来ます。
print $query->checkbox(-name=>'checkbox_name',
-checked=>'checked',
-value=>'ON',
-label=>'CLICK ME');
-または-
print $query->checkbox('checkbox_name','checked','ON','CLICK ME');
checkbox()は他とは論理的に関連付けられない分離されたチェックボックスを作成するために使われます。
チェックボックスの値は以下のようにして取り出すことが出来ます:
$turned_on = $query->param('checkbox_name');
JAVASCRIPTING: checkbox()は-onClick パラメータを理解します。さらに詳細な情報はcheckbox_group()をご覧下さい。
print $query->radio_group(-name=>'group_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-linebreak=>'true',
-labels=>\%labels);
-または-
print $query->radio_group('group_name',['eenie','meenie','minie'],
'meenie','true',\%labels);
HTML3-互換ブラウザのみ:
print $query->radio_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-rows=2,-columns=>2);
radio_group()は論理的に関連付けられたラジオボタンのセット(グループのメンバーの1つがオンになると、他はオフになります)を作成します。
返されるテーブルに行と列のヘッダを入れるために、-rowheader と -colheaderパラメータを使うことが出来ます。これらは両方とも使用するヘッダの配列へのポインタを受取ります。ヘッダは単なる飾りです。それらはラジオボタンの解析を理解しません--それらはまだ名前がついた1つのユニットです。
フォームが処理されるとき、選択されたラジオボタンは以下のようにして取り出すことが出来ます:
$which_radio_button = $query->param('group_name');
radio_group()により返される値は実際にはボタン要素の配列です。以下のようにしてそれらを取得し、テーブル、リストまたはその他の作成方法で使うことが出来ます:
@h = $query->radio_group(-name=>'group_name',-values=>\@values);
&use_in_creative_way(@h);
(訳者注:サブミット・ボタンほうに紛れ込んでいましたが、本来はここでしょう)
JAVASCRIPTING: radio_group() は-onClick
パラメータを理解します。さらなる詳細はcheckbox_groupをご覧下さい。
print $query->submit(-name=>'button_name',
-value=>'value');
-または-
print $query->submit('button_name','value');
submit()は問い合わせサブミット・ボタンを作成します。すべてのフォームはこれらのいずれかを持たなければなりません。
それぞれに異なる値を使うことによりどのボタンが押されたかを見分けることが出来ます:
$which_one = $query->param('button_name');
JAVASCRIPTING: radio_group() は-onClick
パラメータを理解します。さらなる詳細はcheckbox_groupをご覧下さい。
(訳者注:radio_groupはsubmitの間違いでしょう)
print $query->reset
reset() reset()は"リセット"ボタンを作成します。必ずしもデフォルトではなく、最後にスクリプトが呼ばれたときからの値をそのフォームに再設定することに注意してください。
これがPerlに組込まれているreset()とぶつかることに注意してください。元のreset関数を取得するにはCORE::reset()を使ってください。
print $query->defaults('button_label')
defaults()は、呼び出されたとき、フォームを完全にデフォルトにリセットし、ユーザがそれまで行ったすべての変更を洗い流させるボタンを作成します。
print $query->hidden(-name=>'hidden_name',
-default=>['value1','value2'...]);
-または-
print $query->hidden('hidden_name','value1','value2'...);
hidden()はユーザには見えないテキスト・フィールドを作成します。これはあるスクリプトの呼び出しから次へ状態変数情報を渡すのに便利です。
ヒドゥン・フィールドの値は以下のようにして取り出してください:
$hidden_value = $query->param('hidden_name');
他のすべてのフォーム要素と同じように、ヒドゥン・フィールドは"なかなか変わらない"であることに注意してください。スクリプトが一度呼び出された後に、何か他の値でヒドゥン・フィールドを置き換えたければ、手動でおこなう必要があります:
$query->param('hidden_name','new','values','here');
print $query->image_button(-name=>'button_name',
-src=>'/source/URL',
-align=>'MIDDLE');
-または-
print $query->image_button('button_name','/source/URL','MIDDLE');
image_button()はクリッカブルなイメージを作成します。クリックされると、クリックの位置がスクリプトへ"bottun_name.x"と"button_name.y"として返されます。"button_name"のところはそれに指定した名前です。
JAVASCRIPTING: image_buttonは-onClick パラメータを理解します。さらなる詳細はcheckbox_group()をご覧下さい。
このボタンの値は以下のようにして取り出してください:$x
= $query->param('button_name.x'); $y = $query->param('button_name.y');
print $query->button(-name=>'button_name',
-value=>'user visible label',
-onClick=>"do_something()");
-または-
print $query->button('button_name',"do_something()");
button()はNetscape 2.0のJavaScriptと互換性のあるボタンを作成します。-onClick パラメータで示されるJavaScriptのコードが実行されます。Netscapeではないブラウザでは、このフォーム要素は多分表示すらされないでしょう。
Netscapeブラウザ バージョン1.1以上とInternet Explorerのすべてのバージョンはブラウザ・セッションでの状態を保持することを助けるように設計された、いわゆる"クッキー"をサポートしています。CGI.pmはクッキーをサポートするさまざまなメソッドを持っています。
クッキーは、CGI問い合わせ文字列の名前付きパラメータによく似た名前=値の組みです。CGIスクリプトは1つまたは複数のクッキーを作り、HTTPヘッダに入れてブラウザに送信します。ブラウザは特定のWebサーバに所属するクッキーのリストを保持し、その後の対話の間、CGIスクリプトに返します。
必須の名前=値の組に加えて、各クッキーはさまざまなオプションの属性を持っています:
これはクッキーの有効期限を示す時刻/日付の文字列(特別なGMTフォーマットによる)です。ユーザがブラウザを終了させ、再起動したならば、この有効期限が来るまで、クッキーは保存され、スクリプトに返されます。有効期限が指定されなければ、クッキーはユーザがブラウザを終わらせるまで有効です。
これはクッキーが有効であるドメイン名の全体あるいは一部です。ブラウザはドメイン名の一部がマッチする、すべてのホストにクッキーを返します。例えば、ドメイン名に".capricorn.com"を指定すれば、ブラウザは"www.capricorn.com", "www2.capricorn.com", "feckless.capricorn.com"などのマシンのすべて実行されているWebサーバにクッキーを返します。".edu"のように最上位のドメインにマッチしようとすることを防ぐよう、ドメイン名は少なくとも2つのピリオドが入っていなければなりません、もしドメインが指定されなければ、ブラウザはクッキーが作成されたホストのサーバにだけクッキーを返します。
クッキークリプトのURLをチpath属性を与えるとブラウザは、クッキーを返す前にスェックします。例えば、パスを"/cgi-bin"と指定すれば、"/cgi-bin/tally.pl", "/そして"/cgi-bin/customer_service/complain.pl"のそれぞれのcgi-bin/order.pl", スクリプトには返されますが、"/cgi-private/site_admin.pl'"には返されません。デフォルトではパスは"/"で、これはクッキーはあなたのサイトのすべてのCGIスクリプトに送信されます。
もし"secure"属性が設定されれば、クッキーは、CGIリクエストがSSLのようなセキュアなチャンネルで発生された場合にのみ送信されます。.
HTTPクッキーへのインタフェースは cookie() メソッドです:
$cookie = $query->cookie(-name=>'sessionID',
-value=>'xyzzy',
-expires=>'+1h',
-path=>'/cgi-bin/database',
-domain=>'.capricorn.org',
-secure=>1);
print $query->header(-cookie=>$cookie);
cookie() は新しいクッキーを作成します。そのパラメータには以下のものがあります:
$cookie=$query->cookie(-name=>'family information',
-value=>\%childrens_ages);
"+1h" 今から1時間
cookie()によって作成されたクッキーは、header()メソッドによって返される文字列で、HTTPヘッダの中に入れられなければなりません:
print $query->header(-cookie=>$my_cookie);
複数のクッキーを作成するには、header()に配列リファレンスを指定してください:
$cookie1 = $query->cookie(-name=>'riddle_name',
-value=>"The Sphynx's Question");
$cookie2 = $query->cookie(-name=>'answers',
-value=>\%answers);
print $query->header(-cookie=>[$cookie1,$cookie2]);
クッキーを取り出すには、cookie()メソッドを-valueパラメータなしで呼び出すことによって名前で要求します:
use CGI;
$query = new CGI;
%answers = $query->cookie(-name=>'answers');
# $query->cookie('answers') will work too!
クッキーとCGI名前空間は分かれています。もし'answers'という名前のパラメータと'answers'という名前のクッキーを持っていれば、param()とcookie()によって取り出される値はそれぞれ独立しています。しかしながら、CGIパラメータをクッキーにしたり、その反対も簡単です:
# CGIパラメータをクッキーにする
$c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]);
# その反対
$q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
クッキーをどのように効率よく使うかについてのいくつかのアイデアについては、例のスクリプトcookie.cgi をご覧下さい。
CGI.pmスクリプトではHTML4フレーム機能を使って、たくさんのブラウザ・パネルとウィンドウに書き込むことができます。プログラム的に新しいフレームを定義するためには3つのテクニックがあります:
HTTPヘッダを出力した後、start_html()呼び出しを使って標準のHTMLドキュメントを作成する代りに、ページにフレームを定義する<FRAMESET>ドキュメントを作成します。各フレームのSRCとしてスクリプト(適切なパラメータをつけて)を指定します。
CGI.pmには<FRAMESET>セクションを作成するのに特別なサポートはありません。しかしHTMLはとても簡単に書けます。詳細についてはネトスケープのホームページにあるフレームのドキュメントをご覧ください。
http://home.netscape.com/assist/net_sites/frames.html
header()に-target を指定することが出来ます:
print $q->header(-target=>'ResultsWindow');
これはブラウザにスクリプトの出力を"ResultsWindow"という名前のフレームにロードするように伝えます。もしその名前のフレームがなければ、ブラウザは新しいウィンドウを立ち上げ、それにスクリプトのドキュメントをロードします。ターゲットに使うことが出来る特別な名前がたくさんあります。詳細についてはネットスケープのホームページにあるフレームのドキュメントをご覧ください。
FORMタグそれ自身にロードするフレームを指定することが出来ます。CGI.pmでは以下のようになります:
print $q->start_form(-target=>'ResultsWindow');
フォームによりスクリプトが再び呼び出されると、その出力は"ResultsWindow"という名前のフレームにロードされます。それがまだなければ、新しいウィンドウが作成されます。
examplesディレクトリにあるスクリプト"frameset.cgi"は、フォームとレスポンスが隣り合ったフレームに存在するページを作成する1つの方法を示しています。
CGI.pm はHTML3のカスケーディング・スタイル・シート(css)を限定付きでサポートします。スタイルシートをドキュメントに組込むためには、start_html()メソッドに-style パラメータを渡します。このパラメータの値にはスカラ、この場合は直接<STYLE>セクションに組込まれます、あるいはハッシュ・リファレンスを指定することが出来ます。後者の場合は、1つあるいは複数の-src または -codeを持ったハッシュを指定しなければいけません。-srcは完全に定義されたスタイルシートを見つけることが出来るURLを示します。-codeは<STYLE>セクションに組込まれるスカラ値を示します。-codeでのスタイルの定義は、-srcでの同じ名前のもので上書きされます。これゆえに名前が"cascading"(滝のように落ちる)なのです。
-styleによって示されるハッシュに、オプションの-type を加えることによりスタイルシートの種類を指定することも出来ます。もし指定されなければ、そのスタイルはデフォルトの'text/css'です。
ドキュメントの本体(Body)でスタイルを参照するには、HTML要素に-class を加えます:
print h1({-class=>'Fancy'},'Welcome to the Party');
もしくは、その場で-styleパラメータでスタイルを定義します:
print h1({-style=>'Color: red;'},'Welcome to Hell');
テキストのセクションにスタイルを適用するため、新しいspan()を使うことも出来ます:
print span({-style=>'Color: red;'},
h1('Welcome to Hell'),
"Where did that handbasket get to?"
);
span()メソッドを使えるようにするためには":html3"をインポートしなければいけないことに注意してください。CSS使用の簡単で汚い例を以下に示します。さらなる詳細はhttp://www.w3.org/pub/WWW/TR/Wd-css-1.html にあるCSSの仕様をご覧下さい。
use CGI qw/:standard :html3/;
#ここはページに直接組込まれるスタイルシートです
$newStyle=<<END;
<!--
P.Tip {
margin-right: 50pt;
margin-left: 50pt;
color: red;
}
P.Alert {
font-size: 30pt;
font-family: sans-serif;
color: red;
}
-->
END
print header();
print start_html( -title=>'CGI with Style',
-style=>{-src=>'http://www.capricorn.com/style/st1.css',
-code=>$newStyle}
);
print h1('CGI with Style'),
p({-class=>'Tip'},
"Better read the cascading style sheet spec before playing with this!"),
span({-style=>'color: magenta'},
"Look Mom, no hands!",
p(),
"Whooo wee!"
);
print end_html;
ドキュメントに複数のスタイルシートを組み込むためには-styleに配列リファレンスを渡してください。
コマンドラインからスクリプトを実行するか、perlデバッガのなかで実行するならば、キーワードのリストやパラメータ=値の組をコマンド行や標準入力からスクリプトに渡すことが出来ます(環境変数からスクリプトに読み込むような仕組みについて心配する必要はありません)。キーワードを以下のようにして渡すことが出来ます:
your_script.pl keyword1 keyword2 keyword3
あるいは:
your_script.pl keyword1+keyword2+keyword3
あるいは:
your_script.pl name1=value1 name2=value2
あるいは:
your_script.pl name1=value1&name2=value2
この機能をオフにするには、-no_debugプラグマを使ってください。
POSTメソッドをテストするために、-debugプラグマでフルのデバッグを可能にすることができます。これは改行で区切った名前=値の組み合わせを標準入力からスクリプトに食わせることができます。
デバッグのとき、よく知っているシェルのマナーで、文字をエスケープするためにクォートとバックスラッシュを使うことが出来ます。パラメータ=値の組で、空白や他の変わった文字を置かせるためには以下のようにします:
your_script.pl "name1='I am a long value'" "name2=two\ words"
Dump()メソッドはすべての問い合わせの名前/組が入った、ネストしたリストとしてうまくフォーマットされた文字列を作成します。こればデバッグの目的には有効です:
print $query->Dump
これは以下のようなものを作成します:
<UL>
<LI>name1
<UL>
<LI>value1
<LI>value2
</UL>
<LI>name2
<UL>
<LI>value1
</UL>
</UL>
ショートカットとして、完全なCGIオブジェクトを文字列にいれることが出来ます。そしてそれは上記に示されるきれいなHTMLダンプで置きかえられます:
$query=new CGI;
print "<H2>Current Values</H2> $query\n";
いくつかのより便利な環境変数がこのインターフェースを通して取り出すことが出来ます。メソッドを以下に示します:
Perlのaccept()関数とぶつかることを避けるために、2.43と2.44の間で先頭文字が大文字に変更されたことに注意してください。
パラメータなしで呼ばれると、raw_cookie()はパックされたクッキー構造体を返します。";"の文字並びで分割(split)することにより、ここのクッキーに分けることが出来ます。クッキーの名前をつけて呼び出すと、クッキーのアンエスケープされた形式を取り出します。名前を取得するために、通常のcookie()メソッドを使ってリ、CGI::Cookieモジュールからのraw_fetchメソッドを使うことが出来ます。
注意:Microsoft Internet Information Server は追加のパス情報の見方でおかしくなっています。Perl DLLライブラリを使うと、IISサーバはPerlスクリプトとして追加パス情報を実行しようとします。もし通常のファイル関連マッピングを使えば、パス情報は環境変数に表れますが、正しくありません。これをおこなう一番よいことは、IISで使用するようなCGIでは追加パス情報を使うのを避けることです。
変換されたパスについてもMicrosoft IISはイカレています。
例えば、この3つの例はすべて同値です:
$requested_language = $q->http('Accept-language');
$requested_language = $q->http('Accept_language');
$requested_language = $q->http('HTTP_ACCEPT_LANGUAGE');
NPH, または"解析されないヘッダ"("no-parsed-header")、では、完全なHTTPヘッダを直接ブラウザに送信することにより、スクリプトはサーバを完全にバイパスします。これはパフォーマンスの面で少し利点があります。しかしほとんどは、サーバ・プッシュやPICSヘッダのような、サーバによって直接にはサポートされていないHTTP拡張の利点を得るために使われます。
CGIスクリプトをNPHとして示すために、さまざまな約束が使われます。多くのUnixサーバはスクリプトの名前の始まりに接頭辞"nph-"があるかを見ます。これに対して、Macintosh WebSTARサーバと MicrosoftのInternet Information Serverは、スクリプト出力の先頭行をチェックすることによりNPHスクリプトであるかを判定しようとします。
CGI.pmは特別はNPHモードでNPHスクリプトをサポートします。このモードでは、CGI.pmはheader()やredirect()メソッドが呼ばれると、必要な特殊なヘッダ情報を出力します。
Microsoft Internet Information Server はNPHを必要とします。version 2.30では、CGI.pmはIISの元で実行されたとき自動的に検知し、自分自身でこのモードにします。手動でこのモードにする必要はありません。しかしそうしたからといって、何も問題はありません。
CGI.pmをNPHモードにするためにはいくつかの方法があります:
use CGI qw(:standard -nph)
CGI->nph(1)
print $q->header(-nph=>1);
CGI.pmは、サーバ・プッシュを実装するために必要な種類であるマルチパート・ドキュメントを作成するために3つの簡単な関数を提供しています。これらの関数はありがたいことに Ed Jordan <ed@fidalgo.net>によって提供されました。これらを名前空間にインポートするためには、":push"セットをインポートしなければいけません。またスクリプトをNPHモードとし、バッファリングの問題を避けるために$|を1に設定したほうがよいでしょう。
これはサーバ・プッシュをデモンストレーションする簡単なスクリプトです:
#!/usr/local/bin/perl
use CGI qw/:push -nph/;
$| = 1;
print multipart_init(-boundary=>'----------------here we go!');
while (1) {
print multipart_start(-type=>'text/plain'),
"The current time is ",scalar(localtime),"\n",
multipart_end;
sleep 1;
}
このスクリプトはmultipart_init()を呼ぶことによってサーバ・プッシュを初期化しています。そしてmultipart_start(),を呼ぶことによって新しいマルチパート・セクションを始め、現在のローカル・タイムを出力し、multipart_end()でマルチパート・セクションを終わらせているる無限ループに入ります。そして1秒スリープした後、再び開始します。
multipart_init(-boundary=>$boundary);
マルチパート・システムを初期化します。-boundary 引数はドキュメントの部分を分割するために使われるMIMEバウンダリ文字列を指定します。指定されなければ、CGI.pmはあなたに代わって合理的なバウンダリを選択します。
multipart_start(-type=>$type)
指定されたMIMEタイプを使ってマルチパート・ドキュメントの新しい部分を開始します。指定されなければ、text/htmlが想定されます。
multipart_end()
部分(part)を終わらせます。multipart_start()を呼ぶ毎にmultpart_end()を呼ぶ事を忘れては行けません。
サーバ・プッシュ・アプリケーションに興味のあるユーザはCGI::Pushモジュールも見るべきです。
CGI.pmでの潜在的な問題は、デフォルトではどんなに大きくてもPOSTされたフォームを処理しようとすることです。ずるがしこいハッカーは数メガバイトの巨大なPOSTをCGIスクリプトに送信することにより、あたなのサイトを攻撃することが出来ます。CGI.pmはPOST全体を変数に読み込もうとし、メモリがなくなるまでその大きさは巨大に成長します。スクリプトがメモリを占有しようとする間、システムは劇的に遅くなるかもしれません。これがサービス不能(DoS)攻撃の形です。
他の可能な攻撃はリモードユーザがCGI.pmに巨大なファイルのアップロードを受取ることを強要することです。CGI.pmは、例えあなたのスクリプトがアップロードされるファイルを受けることを予想していなくても、アップロードを受けつけ、それを一時ディレクトリに格納しようとします。CGI.pmはそれが終わったとき、自動的にファイルを削除します、しかしその間にリモートユーザがサーバのディスク空間をいっぱいにしてしまうかも知れません。他の問題を起こしながら。
サービス・アタックの拒否を避ける一番よい方法は、CGIスクリプトが使うことができるメモリ量、CPU時間、ディスク容量を制限することです。いつくかのWebサーバはこれを実現する組込み機能を持っています。他の場合、シェルのlimit またはulimitをCGIの資源使用に上限を設定ために使うことが出来ます。
CGI.pmはサービス・アタックの拒否に対するいくかの簡単な組込まれた保護も持っていますが、使えるようになる前に活性化させなければなりません。これらはCGI名前空間での2つのグローバル変数の形を取ります:
これらの変数を2つの方法どちらかで使うことが出来ます:
"use"ステートメントのすぐ後に、スクリプトの先頭でその変数を設定します:
use CGI qw/:standard/;
use CGI::Carp 'fatalsToBrowser';
$CGI::POST_MAX=1024 * 100; # 最大 100K POST
$CGI::DISABLE_UPLOADS = 1; # アップロードなし
CGI.pmを開き、$POST_MAXと$DISABLE_UPLOADSのための定義を見つけ、それを望んでいる値に設定します。ファイルの先頭の近く、initialize_globals()という名前のサブルーチンの中で見つけるでしょう。
$POST_MAXバイトよりも大きなPOSTを送信しようとするとparam()に空のCGIパラメータを返させます。このイベントは、CGIオブジェクトを作成した後もしくはもしくは関数指向インターフェースを使っていれば最初に<param()>を呼び出した後に、cgi_error()をチェックすることで調べることができます。もしPOSTが中断されていれば、cgi_error()は"413 POST too large"を返します。
このエラーメッセージは実際にはHTTPプロトコルで定義されており、そしてCGIスクリプトのステータス・コードとしてブラウザに返されるように考えられています。例えば:
$uploaded_file = param('upload');
if (!$uploaded_file && cgi_error()) {
print header(-status=>cgi_error());
exit 0;
}
しかしながら、すべてのブラウザが現在のところ、このステータスで何をすべきか分かっているかははっきりしません。問題のユーザに警告するHTMLページを作るだけの方がよいかもしれません。
cgi-lib.plを使っている既にあるプログラムの移植を簡単にするために、互換性ルーチン"ReadParse"が提供されています。移植は簡単です:
旧バージョン require "cgi-lib.pl"; &ReadParse; print "The value of the antique is $in{antique}.\n";
新バージョン use CGI; CGI::ReadParse print "The value of the antique is $in{antique}.\n";
CGI.pmのReadParse()ルーチンは%inという名前のタイされた変数を作成しますそれは問い合わせ変数を取得するためにアクセスされます。ReadParseのように、独自の変数を提供することも出来ます。@inと$in変数の作成のように、ReadParseのあまり頻繁には使われない機能はサポートされていません。
一度ReadParseを使うと、以下のように問い合わせオブジェクトそれ自身を取り出すことが出来ます:
$q = $in{CGI};
print $q->textfield(-name=>'wow',
-value=>'does this really work?');
これにより、始めから古いスクリプトを書きなおすことなく、CGI.pmのより興味深い機能を使い始めることが出来ます。
Copyright 1995-1998, Lincoln D. Stein. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Address bug reports and comments to: lstein@cshl.org. When sending bug reports, please provide the version of CGI.pm, the version of Perl, the name and version of your Web server, and the name and version of the operating system you are using. If the problem is even remotely browser dependent, please provide information about the affected browers as well.
(参考訳)
バグレポートとコメントは lstein@cshl.org.に送ってください。バグレポートを送るときにはCGI.pmのバージョン、Perlのバージョン、Webサーバの名前とバージョン、そして使用しているオペレーティング・システムの名前とバージョンを教えてください。もし問題が離れた場所にあるブラウザにさえも依存していれば、影響されるブラウザについての情報を教えてください。
以下の方々に感謝します:
#!/usr/local/bin/perl
use CGI;
$query = new CGI;
print $query->header;
print $query->start_html("Example CGI.pm Form");
print "<H1> Example CGI.pm Form</H1>\n";
&print_prompt($query);
&do_work($query);
&print_tail;
print $query->end_html;
sub print_prompt {
my($query) = @_;
print $query->start_form;
print "<EM>What's your name?</EM><BR>";
print $query->textfield('name');
print $query->checkbox('Not my real name');
print "<P><EM>Where can you find English Sparrows?</EM><BR>";
print $query->checkbox_group(
-name=>'Sparrow locations',
-values=>[England,France,Spain,Asia,Hoboken],
-linebreak=>'yes',
-defaults=>[England,Asia]);
print "<P><EM>How far can they fly?</EM><BR>",
$query->radio_group(
-name=>'how far',
-values=>['10 ft','1 mile','10 miles','real far'],
-default=>'1 mile');
print "<P><EM>What's your favorite color?</EM> ";
print $query->popup_menu(-name=>'Color',
-values=>['black','brown','red','yellow'],
-default=>'red');
print $query->hidden('Reference','Monty Python and the Holy Grail');
print "<P><EM>What have you got there?</EM><BR>";
print $query->scrolling_list(
-name=>'possessions',
-values=>['A Coconut','A Grail','An Icon',
'A Sword','A Ticket'],
-size=>5,
-multiple=>'true');
print "<P><EM>Any parting comments?</EM><BR>";
print $query->textarea(-name=>'Comments',
-rows=>10,
-columns=>50);
print "<P>",$query->reset;
print $query->submit('Action','Shout');
print $query->submit('Action','Scream');
print $query->endform;
print "<HR>\n";
}
sub do_work {
my($query) = @_;
my(@values,$key);
print "<H2>Here are the current settings in this form</H2>";
foreach $key ($query->param) {
print "<STRONG>$key</STRONG> -> ";
@values = $query->param($key);
print join(", ",@values),"<BR>\n";
}
}
sub print_tail {
print <<END;
<HR>
<ADDRESS>Lincoln D. Stein</ADDRESS><BR>
<A HREF="/">Home Page</A>
END
}
このモジュールは単一で巨大にまで大きくなっていまいました。URLの取り扱い、CGI入力の解析、HTMLの出力などLWPモジュールでもおこなわれていることを、さらに多くのことをしています。これはCGI::*のために捨てられるべきですが、しかしとにもかくにもこれで働くことを続けています。
-w スイッチ付きでプログラムが実行されたときの見せかけだけの警告を避けるために、このコードは本当にゆがんでいます。
CGI::Carp, URI::URL, CGI::Request, CGI::MiniSvr, CGI::Base, CGI::Form, CGI::Push, CGI::Fast, CGI::Pretty
ご意見、ご質問はこちらの掲示板で受け付けています。
またメールは河馬屋(Nifty)にお願いします。