読者です 読者をやめる 読者になる 読者になる

It's raining cats and dogs.

無駄なことなんてないはず

携帯(ガラケー)サイトで、PHP5.2以下から5.3以上へのバージョンアップ時にmb_output_handlerを使った文字コード変換でハマった時のメモ

php

前回のエントリでも触れたけど、とある携帯(ガラケー)サイトを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_encodingEUC-JP、mbstring.http_outputShift_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_mimetypesmb_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的なphpmbstring.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では動いたのかもしれない)