mod_perl時の注意点 †
以下は 「Apacheをmod_perl対応にする」 で設定した環境下で確認できた事象です。
◆カレントディレクトリがルート( / )になる。
確認用CGI : /path/to/cgi-bin/directory.cgi
#!/usr/bin/perl
print "Content-type: text/plain\n\n";
print "カレントディレクトリ : " . `pwd` . "\n";
exit(0);
Apacheの実行ディレクトリになるとの情報も有ったが、自宅サーバでは / になっていた。
なのでモジュール検索PATH @INC 等を変更する時は、注意が必要だな。と思っていたら
そもそも モジュール検索PATH をイジル事ができないらしい。※次を参照。
◆unshift、push で変更を加えた @INC(モジュール検索PATH)が使用されない。
→ http://mt.endeworks.jp/d-6/2010/02/incuse.html によると認識が違うそうです。
が、誤りから学んだ事を残しておくという意味で''以下のメモはそのまま残すが信じちゃダメ'!'
上記URLでは「認識が違う」と柔らかめの指摘を頂いてるが、そもそもperlの勉強不足だった。。ハズかしぃ〜!
詳しくは perlモジュールの検索PATHについて を参照。
確認用CGI : /path/to/cgi-bin/lib_search.cgi
#!/usr/bin/perl
(my $owndir = $0) =~ s/^(.+)\/(.+?)\.(.+?)$/$1/;
use lib qw(./pm); # これだとカレントがApacheの実行ディレクトリになるので無意味だが。。
unshift @INC, "$owndir/pm"; # こっちでもダメだった。
use MyClass;
print "Content-type: text/plain\n\n";
print "MyClassが見つかりました\n";
my $myclass = new MyClass();
print "MyClassのインスタンスを生成できました\n";
$myclass->printName();
$myclass = undef;
exit(0);
上記のcgiから呼び出されるCGI : /path/to/cgi-bin/pm/MyClass.pm
#!/usr/bin/perl
package MyClass;
sub new{
my $class = shift;
bless { name => "MyClass",} , $class;
}
sub printName {
my $self = shift;
print $self->{name} . "のprintNameを実行しました\n";
}
1;
上記のcgiにアクセスすると
http://example.com/cgi-bin/lib_search.cgi ...OK
http://example.com/cgi-perl-run/lib_search.cgi ...Internal Server Error が発生
【エラーログ】
Can't locate MyClass.pm in @INC (@INC contains: ./pm /usr/lib/perl5/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/5.8.0 /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.0 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.0 /usr/lib/perl5/vendor_perl . /usr/local/apache2)
at /home/system/htdocs/web/mod_perl/lib_search.cgi line 8.
BEGIN failed--compilation aborted at /path/to/cgi-bin/lib_search.cgi line 8.
|
unshift で追加した @INC が反映されていない。
但し、use は効いている模様。
※useでフルPATH指定すれば問題なさげ。
↓
eval("use lib '$owndir/pm'"); でOK。
◆起動されるスクリプトのグローバル変数は使いまわされる(Registry)
確認用CGI : /path/to/cgi-bin/global_var.cgi
#!/usr/bin/perl
print "Content-Type: text/plain\n\n";
my $cnt = 0;
for (1..5) {
increment($cnt);
}
sub increment {
$cnt++;
print "Count is $cnt\n";
}
exit(0);
http://example.com/cgi-bin/global_var.cgi(通常版)への2回目のアクセス時
Count is 1
Count is 2
Count is 3
Count is 4
Count is 5
http://example.com/cgi-perl-run/global_var.cgi(PerlRun版)への2回目のアクセス時
Count is 1
Count is 2
Count is 3
Count is 4
Count is 5
http://example.com/cgi-registry/global_var.cgi(Registry)への2回目のアクセス時
Count is 6
Count is 7
Count is 8
Count is 9
Count is 10
以下のように global変数を使用せず、名前空間をしっかり管理すればOK。
#!/usr/bin/perl
print "Content-Type: text/plain\n\n";
my $cnt = 0;
for (1..5) {
$cnt = increment($cnt);
}
sub increment {
my $cnt = $_[0];
$cnt++;
print "Count is $cnt\n";
return $cnt;
}
exit(0);
◆キャッシュされたスクリプトのmain処理(?)は実行されない (Registry、PerlRunも?)
確認用CGI : /path/to/cgi-bin/use_require.cgi
#!/usr/bin/perl
print "Content-Type: text/plain\n\n";
(my $owndir = $0) =~ s/^(.+)\/(.+?)\.(.+?)$/$1/;
require "$owndir/pm/sub_module.pl";
subModule::argPrint(time);
while (my ($key,$val) = each(%INC)) {
print "$key=$val\n";
}
exit(0);
requireされるCGI : /path/to/cgi-bin/pm/sub_module.cgi
:!/usr/bin/perl
package subModule;
argPrint("モジュール自身のファイルからの呼び出し");
sub argPrint {
print "受け取った引数は(". $_[0] .")ですか?\n";
}
1;
とした時 Registry版だと、起動されるスクリプトから明示的に呼び出されていない処理は実行されない。
※「受け取った引数は("モジュール自身のファイルからの呼び出し")ですか?」は表示(実行)されない。
( PerlRun はなぜか実行されたり、されなかったりする。。)
起動されるスクリプトから明示的に、メソッドで呼び出されているものは確実に実行される。
※「受け取った引数は(1238777288)ですか?」のみ実行される。
※ メソッド呼び出しをすると、PerlRun では
「受け取った引数は("モジュール自身のファイルからの呼び出し")ですか?」も表示される事がある?(良く分からん!)
基本的に requireされるファイルには main処理(と言っていいのかな?)を記述せず、全てメソッドで実装し、明示的に呼び出す。
◆requireされたファイルを変更しても、キャッシュされている為、すぐに反映されない事がある。
【解決方法】
BEGIN { delete $INC{"/path/to/cgi-bin/sub_module.pl"} };
を記述して、ロード済みモジュールリストから消してから、再度 require する。
◆exit、die を使うとプロセス(子)が落ちる。。らしい
:!/usr/bin/perl
・
・
・
exit;
とするとApacheのプロセスが落ちるとの情報があったが、実験してみても落ちなかった。
だと問題ないようなので exit は全てこの記述に統一する。