by @nyarla

Win32なApacheでPATH_INFOがShift_JISになる

なんかここの所 Wiki ネタばっかりなので、役に立ちそうで立つのか分からないネタ。

Windows で Apache 使ってサーバ立てるのはオススメできないという話。

なんでも Shift_JIS

仕様なのかバグなのか分かりませんが、Win32 な Apache では PATH_INFO 等が _Shift_JIS _ に強制変換されるみたいです。WindowsXP + Apache1.3.34 で確認しました。というかまあ僕の開発環境なんですが、他の環境でもそうなるかと思います。Apache PATH_INFO 文字化け なんかで検索すると同じようなエントリが出てきます。

具体的にはどういうことかと言うと、CGI の PATH_INFO に日本語(マルチバイト?)な文字列を、URI エスケープして渡すと、なぜか Shift_JIS に変換されます。なので場合によっては文字化けして PATH_INFO が使い物にならなくなります。ちなみにこれは mod_rewrite を使った URI 書き換えでも起こります。

僕が遭遇したのは mod_rewrite で化けたほうが先で、PATH_INFO がおかしくなるのに気づいたのは Wiki 書き始めた時です。

まあ、遭遇した順番はどうでもいいですが、このままだと PATH_INFO が使えないので解決策を考えてみます。

環境変数 REQUEST_URI , SCRIPT_NAME を使う

REQUEST_URISCRIPT_NAMEを使えば意外と簡単にできます。というわけで例。コードは Perl です。

my ($request_uri,$script_name) =
( $ENV{'REQUEST_URI'} , $ENV{'SCRIPT_NAME'});
my $path_info = $request_uri;
$path_info =~ s!^$script_name!!;
$path_info =~ s/%( [[0-9A-Fa-f]]  [[0-9A-Fa-f]] )/pack('H2', $1)/eg;

こんな感じです。これでばっちり……と言いたい所ですが問題があったりします。このコードそのまま使うと mod_rewrite なんかで URI 書き換えた時動かねぇという事態に陥ります。

簡単な URI の書き換え、例えば CGI ファイル名を隠すというリライトなら

my ($request_uri,$script_name,$script_filename) =
( $ENV{'REQUEST_URI'} , $ENV{'SCRIPT_NAME'} , $ENV{'SCRIPT_FILENAME'});
my @tmp_filename = split m{/},$script_filename;
my $filename = pop @tmp_filename;
my $path_info = $request_uri;
if ($path_info !~ m/$filename$/){
$script_name =~ s!/$filename$!!;
}
path_info =~ s!^$script_name!!;
$path_info =~ s/%( [[0-9A-Fa-f]]  [[0-9A-Fa-f]] )/pack('H2', $1)/eg;

こんな感じのコードで対応できると思います。ただこれ以外のリライトになると、どう対応していいのか分かりません。解決策ねぇって言う状態です。Win32 で Apache 使うのやめるぐらいしか選択肢がないように思います。

まとめ

この問題を回避する選択肢としては、

  1. PATH_INFO に日本語突っ込むのをやめる
  2. Windows で Apache 使うのやめる
  3. Windows を窓から投げ捨てろ

ぐらいでしょうか。1 か 2 が妥当でしょう。3 はネタなので気にしない。いや本当に投げ捨ててもいいと思いますが。問題ないのならば。

2 に関しては lighttpd という最近はやり?のやつがあるので、そっちを試してみるのもいいかもしれません。試したこと無いので問題起こるかどうか知りませんが。

おまけ

自作 Wiki の公開のためのサイトですが全然できてません。記法作るのに時間がかかってるよ。今月中には公開したい。