Perlでの特に簡素なCGIフレームワーク。
CPANで最新のCGI::Applicationモジュールに埋め込まれているPODドキュメントを読むことができます。
CGI::Application 4.04版のドキュメントを和訳しました。4.06版までは、ドキュメントの内容に変更はありません。間違い等ありましたら、ぜひご指摘をお願いします。
| CGI::Application | HTML形式 | POD形式 | 原文(4.04版) |
この他に、日本語の情報としては、川合さんの河馬屋二千年堂でCGI::Applicationモジュール v.1.2 の和訳ドキュメントを見ることができます。上記の4.04版のドキュメント和訳にあたっても、参考にさせていただきました。
CGI::ApplicationモジュールのSYNOPSISにあるサンプルでは、CGIファイルとモジュールを"webapp.cgi"と"WebApp?.pm"の2ファイルに分けています。
実際のアプリケーション作りではこうなっていたほうが(再利用性や柔軟性などから)良いと思いますが、ちょっとCGI::Applicationを試してみるなどという時には、ライブラリパスなどを考えなくて済むように、1ファイルにまとめたいと思うこともあります。この時は、単純に次のようにするだけで実現できます。
!#/usr/bin/perl
### 元"webapp.cgi"の内容...
package main;
# use WebApp;
my $webapp = WebApp->new();
$webapp->run();
### 元"WebApp.pm"の内容...
package WebApp;
use base 'CGI::Application';
# (一般的なケースではにsetup()はスキップ可能。以降のドキュメント参照。)
sub setup {
my $self = shift;
$self->start_mode('mode1');
$self->mode_param('rm');
$self->run_modes(
'mode1' => 'do_stuff',
'mode2' => 'do_more_stuff',
'mode3' => 'do_something_else'
);
}
sub do_stuff { ... }
sub do_more_stuff { ... }
sub do_something_else { ... }
1;
CGI::ApplicationモジュールのSYNOPSISと見比べてみてください。基本的には、webapp.cgiの内容をmainというパッケージに(明示的に)入れ、mainの"use WebApp?;"という行をコメント化し、つないだだけです。
もちろんこの後で、確認作業に満足しこれをベースに本格的に開発するとなったら、逆をしてやることもできます。webapp.cgiとWebApp?.pmという2ファイルに分け、webapp.cgiのコメント化した"use WebApp?;"という行の行頭の"#"を外せば、SYNOPSIS(を元にした形)に戻ります。
CGI::Application 3.31版ではcgi_prerun、cgi_postrunなど、様々なタイミングで共通処理を組み込める仕組みがあります。 これを利用して、スクリプト中では(あまり)文字コードを意識しなくてもすむようにすることもできます。
まず、CGI::Applicationを継承するクラスに、次のようなcgiapp_postrunメソッドを作成します。
sub cgiapp_postrun {
my $self = shift;
my $bodyref = shift;
my $charset = uc($self->param('charset'));
my $charmap = { 'ISO-2022-JP' => 'jis', 'SHIFT_JIS' => 'sjis', 'EUC-JP' => 'euc', 'UTF-8' => 'utf8' };
if (defined($charset) and defined($charmap->{$charset})) {
$self->header_add('-charset', $self->param('charset'));
my $encode = $charmap->{$charset};
my @lines = map { Jcode->new($_)->$encode } split(/\n/, $$bodyref);
$$bodyref = join("\n", @lines);
}
}
後は、このモジュールを利用するCGIスクリプトで以下の様にして出力キャラクタセットを指定するだけです。 キャラクタセットは、'ISO-2022-JP'(JIS)、'Shift_JIS'(シフトJIS)、'EUC-JP'(EUC)、'UTF-8'(Unicode)を指定できます。
$obj->param('charset' => 'Shift_JIS');
cgiapp_postrunは、HTMLデータが生成されて、HTTPヘッダが生成される直前に実行されます。 渡される引数はHTMLデータの文字列リファレンスです。 そこで、上記のいずれかのキャラクタセットが指定されていれば、cgiapp_postrunで以下を行っています。
この作業で、runで生成されたHTMLデータの文字コードが何でも、また複数の文字コードが混在していても、$obj->param('charset')に指定された文字コードに変換されて出力されるわけです。
なお、この方式を採るときは、以下の点に注意してください。
CGI::Applicationは、以下の図の順番で、サブクラスのメソッドを呼び出します。 本図は、CGI::Application 3.31版に基づいています。
CGI::Applicationを使う利点の一つに、CGIファイルに設定、モジュールファイルにロジックと分けられることが挙げられます。 例えば、CGIファイル側でデータディレクトリをパラメータとして指定するようにし、モジュール側ではパラメータ値を参照する、といった形です。
この時、パラメータを設定するタイミングに注意が必要です。例えば、cgiapp_initやsetupはnewメソッドから呼び出されます。 このため、次のようなコードを書いても、この「data_dir」パラメータはcgiapp_initやsetupでは参照できません。 これらのメソッドで使用するパラメータであれば、newメソッドで指定しないと間に合わないわけです。
use CGI::Application;
my $cgi = CGI::Application->new; # この時点でcgiapp_initやsetupも実行されている
$cgi->param('data_dir' => './data');
$cgi->run;
CGI::Application 3.21版以降では、CGI::Application::Plugin::Sessionモジュールを併用することで、セッション管理機能を組み込むことができます。
以下はサンプルです。 まず以下のソースを「SessionTest.cgi」として保存します。パーミッション、改行コードなどは適宜整えてください。
#!perl
use lib qw(.);
use SessionTest;
my $SessionTest = SessionTest->new(PARAMS => {'data_dir' => './data'});
$SessionTest->run();
同じディレクトリに、以下のソースを「SessionTest.pm」として保存します。改行コードは適宜整えてください。文字コードはUTF-8で化けないようにヘッダをいじってあります。
package SessionTest;
use base 'CGI::Application';
use CGI::Application::Plugin::Session;
sub cgiapp_init {
my $self = shift;
# Configure the session
my $sess_dir = $self->param('data_dir') . '/session';
die unless (-d $sess_dir);
$self->session_config(
CGI_SESSION_OPTIONS => [ ("driver:File", $self->query, {Directory=>$sess_dir}) ],
COOKIE_PARAMS => { -expires => '+24h', -path => '/', },
SEND_COOKIE => 1,
);
}
sub setup {
my $self = shift;
$self->start_mode('main');
$self->mode_param('mode');
$self->run_modes(
'main' => \&process_main,
);
$self->header_add( -type => 'text/html; charset=UTF-8' );
}
sub process_main {
my $self = shift;
my $query = $self->query;
# 訪問回数の取得とカウントアップ
my $count = $self->session->param('times') + 1;
$self->session->param('times' => $count);
# コンテンツの出力
my $meta_header = $self->query->meta({-http_equiv => 'Content-Type', -content => 'text/html; charset=UTF-8'});
my $html_header = $self->query->start_html( '-head' => $meta_header, '-charset' => 'UTF-8', '-encoding' => 'UTF-8', '-lang' => 'ja',);
my $html_body = "<h1>CGI::Application::Plugin::Session test</h1>\n表示回数 : ${count}回\n";
my $html_footer = $self->query->end_html;
return $html_header . $html_body . $html_footer;
}
1;
"./data/session"ディレクトリを作成した後、「SessionTest.cgi」に繰り返しアクセスすると、表示回数が増えていきます。
セッション関連の作業は、sub cgiapp_initメソッド内でセッションの設定をしているだけです。 これで、CGI::Applicationオブジェクトではsessionメソッドで現在のセッションを取得できるようになり、セッションIDなどは自動的にCookieで受け渡されるようになります。