mod_perl その2

とりあえず自作モジュールをuseで読み込めなかった原因がわかった。

その前に。

Apachemod_perlを追加する際に設定した部分を書いておきます。

conf/httpd.conf
LoadFile "D:/usr/bin/perl58.dll"
LoadModule perl_module modules/mod_perl.so
<IfModule mod_perl.c>
	Include conf/mod_perl.conf
</IfModule>
conf/mod_perl.conf
<Directory "D:/web">
	<Files *.pl>
		SetHandler perl-script
		PerlHandler ModPerl::Registry
		PerlSendHeader On
	</Files>
</Directory>

原因

自作モジュールをuseで読み込めなかった原因。
調べてみると、mod_perlからmod_perl2になったとき色々変更があって、
PerlHandler ModPerl::Registryとしている場合、
カレントディレクトリがスクリプトがあるディレクトリじゃなくなったためらしい。
ためしに、mkdirでhogehogeを作ってみると、Apacheのインストール先にhogehogeができていた。
つまり標準のままだと、mod_perlApacheディレクトリをカレントディレクトリとして動作するわけです。
そのため、スクリプトと同じ階層にあるモジュールを読み取ることができなかったわけです。


また、PerlHandler ModPerl::RegistryPreforkとすると回避できるらしいのですが、
Windows環境ではできないのか、エラーログを吐かれ、うまくいきませんでした。
多分なんか設定がおかしいのかもしれません。

解決策

chdirで移動するのが手っ取り早いです。
ただ移動するにも、スクリプト毎にいちいちフルパスを指定するのはめんどくさいので、
環境変数を信じて適当にほいほい移動することに。一応移動にミスった時のエラー処理も。

test.pl
#!/usr/bin/perl

BEGIN{
	if(exists $ENV{MOD_PERL}){
		chdir( substr($ENV{SCRIPT_FILENAME}, 0, rindex($ENV{SCRIPT_FILENAME}, "/")) ) or die 'ディレクトリ移動失敗';
	}
}

# 以下に自作モジュールを読み込んだり、普通に処理を書いたり。

流れ。

一応CGImod_perlで動くハイブリットな動作になります。
僕のApacheの設定なら、webディレクトリ以下のどこにおいても動作します。多分。


BEGINというサブルーチンは、(多分)どこにあっても必ず最初に実行されます。
また、use 〜;もスクリプト中のどこにあっても最初に実行されます。
(evalで文字列をPerl文として評価する場合は除く。)
BEGINサブルーチンとuseの優先度は同じなので、上にある物から実行されます。


if(exists $ENV{MOD_PERL}){ }はmod_perlで稼動しているかどうかをチェックします。
ここで変数の初期化をしてもいいかもしれません。


環境変数の"$ENV{SCRIPT_FILENAME}"は、実行したスクリプトまでのフルパスがあるので、
そこからスクリプト名を削り、カレントディレクトリにします。
もし、ディレクトリの移動に失敗した場合、移動失敗とエラーを出して死にます。

注意したいところ

このカレントディレクトリはmod_perl環境で共通で使われるらしい。
確かめるため、そのスクリプト自身が作ったことがわかるファイル書き出すスクリプトを2個作った

/perl/test.pl(1.txtを書き出す)
# 1
BEGIN{ 
	chdir( substr($ENV{SCRIPT_FILENAME}, 0, rindex($ENV{SCRIPT_FILENAME}, "/")) ); 
}

use strict;
open(FP,">1.txt");
close(FP);
/perl/test/test.pl (2.txtを書き出す)
# 2

BEGIN{ 
	chdir( substr($ENV{SCRIPT_FILENAME}, 0, rindex($ENV{SCRIPT_FILENAME}, "/")) ); 
	sleep(10);
}

use strict;
open(FP,">2.txt");
close(FP);


/perl/test/test.plを実行し、sleepに入った後、/perl/test.plを実行した。
本来のPerlで実行すれば、それぞれの階層に1.txtと2.txtができるはずだけど、
mod_perl上で動作させた場合、/perlに1.txtと2.txtが書き出されていた。


mod_perlを使ったプログラムが1個だけなら問題ないけど、
違う階層で複数動かす場合はコレに対する対策を考えないといけません。


参考になったところ。
http://adiary.blog.abk.nu/07
http://www.y2sunlight.com/ground/?ActivePerl5.8%2F6.mod_perl