カラクリサイクル

『輝かしい青春』なんて失かった人の雑記

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の公開のためのサイトですが全然できてません。 記法作るのに時間がかかってるよ。今月中には公開したい。