PHPでの文字化けというかコード変換に関する注意

追記

いぇーい。ツッコんでもらえたぜ。id:elf:20070905 ハードコードしたやつをそのままechoしたらアカンでというメモだったんだけど、ちゃんと突っ込んでもらえた。mb_regex_encoding()というのは、気付いていませんでした。ありがとうございます。でもほとんどの場面で、preg_match()を使用しているのでどういう使い方をするか迷うところです。

本文

EUC-JPだけで文字化け知らずでいたのだが、UTF-8で多国語対応にするのにはまってしまった。
まずは結論から。

PHPの http_output(), mb_internal_encoding()とかの mb_string系の設定はわけわからん。したがって自動変換をしないようにするのが最も早い解決法だ。*1

HTMLのヘッダでのエンコード宣言と実際の出力コードの違いが、混乱の元になっていたように思う。きちんと統一しようぜというのが結果です。

  1. スクリプトEUC-JP でオケ。
  2. htmlテンプレートは UTF-8 にしておこうぜ。
  3. mbstring.internal_encoding とスクリプトのコードはそろえなくても平気。
    • ただし、ハードコードしている時には気を付けようぜ。mb_convert_encoding()やmb_ereg()などを使う時には、文字列をスクリプト文字コードからinternal_encoding に変換してから渡してやる必要がある。要するにひと手間かかる場合もあるということ。外部から渡されるコード、スクリプト内でハードコードしているコードがごっちゃになるので評価する時には統一してから評価しようぜ。
  4. mbstring.encoding_translation 自動変換は使わない。
    • internal_encoding に勝手に変換してくれるのだが、自分のいつもの設定(php.iniにてeuc-jpにしている)のせいか、UTF-8をinternal_encodingにしているのに勝手に EUC-JP に変換してしまう。

PostgreSQL = UTF-8、入出力 = UTF-8スクリプト = EUC-JP の場合

default_charset = UTF-8

mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = UTF-8
mbstring.detect_order = UTF-8,eucjp-win,sjis-win,ISO-2022-JP,ASCII
mbstring.encoding_translation = Off
mbstring.substitute_character = none
  • default_charset = UTF-8
    • httpヘッダの charset として使われる。無いと困る。
  • mbstring.language = Japanese
    • mb_send_mail()のみ使用?ようわからんが無いと困る。
  • mbstring.internal_encoding = UTF-8
    • mbstring系の関数で全般的に使用する。scriptとそろえる必要は無い。*2
  • mbstring.http_input = auto
    • 決め打ちしたほうがいいけど、ま、どっちでも大丈夫そうだね。
  • mbstring.http_output = UTF-8
    • ob_stert('mb_output_handler') && text/ の時に headerで出力されるエンコード指定。大抵は output_handler = 'mb_output_handler' しているので出力バッファ時にコード変換を自動でしてしまいます。したがって正しく宣言しておいたほうが良い。
  • mbstring.detect_order = UTF-8,eucjp-win,sjis-win,ISO-2022-JP,ASCII
    • そうそう当てには出来ないが、やられては困る判定を後ろに追いやるべき。*3
  • mbstring.encoding_translation = Off
    • POSTとかで受け取る値を internal_encoding に自動で変換してくれる。ここをOffにするというのは、要するに決め打ちでトラブルを抑えるという意味なんですがね。
    • 別件、ini_set()で値を上書きできないんです。どういうことなんすかね。兎に角、php.ini で正しくOffにしてやる必要がある。
  • mbstring.substitute_character = none
    • 余計な文字を消してブラウザ側での文字化けを抑える設定らしいが、余計にややこしくなりそうなので殺しておく。

*1:ini_set(), mb_internal_encoding()などによる設定の上書きも意味があるのかないのか。どっちかってと効いてない

*2:しかし、そろえておくとスクリプト内で出力文字列をハードコードしちゃう場面では、出力する前に変換するという手順を省けるので楽チンだね。

*3:つか ASCII とか書かなくていいじゃん。