携帯(ガラケー)サイトで、PHP5.2以下から5.3以上へのバージョンアップ時にmb_output_handlerを使った文字コード変換でハマった時のメモ
前回のエントリでも触れたけど、とある携帯(ガラケー)サイトをPHP5.2から5.4にバージョンアップ対応していた時にまたハマった。※文字多めのエントリ
ガラケーといえば、3キャリア対応するためにShift_JISでページを作るのは鉄板。やり方はいろいろあるけど、このサイトはmb_output_handler
で文字コード変換していた。mb_output_handler
はざっくり言うと、ob_start
でバッファリングした出力をmbstring.internal_encoding
で指定した文字コードから、mbstring.http_output
で指定した文字コードによろしく変換してくれるというすぐれものだ。
ただ、このmb_output_handler
には罠があって、
http://php.net/manual/ja/function.mb-output-handler.php
にも書かれている通り、
デフォルトの MIME 型が text/ で始まる
という条件で発動するらしい。
で、今回何にハマったのかというと、
このサイトではapache側でphp_valueを使って、mbstring.internal_encoding
がEUC-JP、mbstring.http_output
がShift_JISで設定されていた。でもってhtmlのテンプレートは基本EUC-JPで書かれていて、それをtext/html
で出力していたので、mb_output_handler
が効いていたために、特に問題なくShift_JISに変換されて表示されていたのだけど、何故か一部のページが文字化けしてしまっていた。PHP5.2の環境だと問題なく表示されるのに。
よくよく調べてみると、文字化けしていたページはなぜかはわからないけどapplication/xhtml+xml
が使われていてShift_JISで書かれていた。(たぶん何かの装飾をしたかったのだろう)
ただ、mb_output_handler
の仕様上、mimeタイプがtext/
でなければ、文字コード変換は行われず、普通にShift_JISとして表示されるはずだし、実際PHP5.2の環境では問題なく表示できていた。
ではなぜ文字化けが起きたのか。
PHP5.3からはmbstring.http_output_conv_mimetypes
という設定が追加されている。
http://php.net/manual/ja/migration53.ini.php
ここでも書かれている通り、
このディレクティブは mb_output_handler() 関数が呼び出された場合に使う Content-Type の正規表現パターンを指定します。
要はmbstring.http_output_conv_mimetypes
にmb_output_handler
で変換対象にしたいContent-Typeの正規表現を書くことで、text/
以外でも変換できるとのこと。
で、mbstring.http_output_conv_mimetypes
のデフォルト値が^(text/|application/xhtml\+xml)
だったために、今まで変換されないはずであったapplication/xhtml+xml
で出力していたShift_JISのページがmb_output_handler
で変換されてしまい文字化けてしまっていたのだった。(Shift_JISのページをEUC-JPとして解釈してShift_JISに変換していた)
対応としては、application/xhtml+xml
のページをEUC-JPにするなどを考えたけど、影響範囲を調査するのが手間だったので、auto_prepend_fileで起動されるbootstrap的なphpでmbstring.http_output_conv_mimetypes
の正規表現をtext/
でのみ文字コード変換されるように変更することにした。
<?php ini_set('mbstring.http_output_conv_mimetypes', 'text/*');
相変わらず設定値にはハマりますね。
ちなみに
http://php.net/manual/ja/migration53.ini.php
ではmbstring.http_output_conv_mimetype
と書かれているけど、実際にはmbstring.http_output_conv_mimetypesのようにs
を付けないと動かない。(もしかしたら5.3では動いたのかもしれない)