WEBサービス創造記

WEBサービスを作ったり保守したりしてる人のメモブログです。

PHPのマルチバイト環境と文字化けに関する問題のまとめ

      2012/12/13

PHPと文字化け

PHPと文字化けについて興味深い記事を拝見したので、その記事の内容を実践しつつPHPもマルチバイト環境の復習を行いたいと思います。

PHPの文字化けを本気で解決する – ぎじゅっやさん

default_charsetディレクティブの誤解

参考記事にもあるようにphp.iniディレクティブの“default_charset”は、デフォルトの文字コードという意味ではない。

default_charsetはデフォルトの文字コードのことではない。
非常に誤解しやすい内容。
default_charsetというパラメータはご存じの人も多いと思う。
それに大抵の初心者本にはこれを設定するように書いてあるが、
むしろ逆である。
default_charsetとは

出力時にHTTPヘッダとして送信する文字コード名

のこと。

PHPの文字化けを本気で解決する – ぎじゅっやさん

ちなみに”default_charset”の既定値は””(空文字)が指定されています。

また、別のphp.iniディレクティブに”default_mimetype”というディレクティブがあり、これには既定値で”text/html”が設定されているため、

以下のようなHelloWorldを出力するだけのスクリプトを実行してhttpヘッダーを監視して”Content-type”の値を確認してみます。

test.php
<?php
echo 'Hello World!';
結果:Content-Type: text/html

続いてini_set関数で”default_charset”にUTF-8を指定した場合。

test.php
<?php
ini_set('default_charset', 'UTF-8');
echo 'Hello World!';
結果:Content-Type: text/html; charset=UTF-8

“default_charset”・”default_mimetype”ともに空文字に指定した場合

test.php
<?php
ini_set('default_charset', '');
ini_set('default_mimetype', '');
echo 'Hello World!';
結果:Content-Typeは出力されず

つまり“default_charset”・”default_mimetype”は自動で「Content-type」を生成する機能です。しかもその値は指定された値で固定されてしまうということになります。
個人的にはこれら両方設定しないでheader関数を利用して手動でContent-Typeを出力したほうがいいのではないかと思います。
携帯サイトの制作だと出力文字コードをエンドユーザのキャリア合わせて変更することも多いですし、MIMETYPEに関してもCSVやXMLを出力する機会もあると思いますので。

内部文字エンコーディングの誤解

php.iniの”mbstring.internal_encoding”ディレクティブは、内部文字エンコーディングのデフォルト値を定義するものです。
また、PHPマニュアルによると、mb_internal_encoding関数は「内部文字エンコーディングを設定あるいは取得する」とあります。

この「内部文字エンコーディング」という言葉は非常に誤解を招きやすく、これは実は単に「mbstring関数を利用するときのデフォルト文字コード」に過ぎないようです。
つまり、”mbstring.internal_encoding”の値は、mb_convert_kana関数やmb_strwidth関数の引数に文字コードを省略した場合のデフォルト値として利用されるだけで、他の役割はありません。

文字化け対策としては、この“mb_internal_encoding”ディレクティブの値はソースコードの文字コードと揃えておくと無難かと思われます。

mbstring.detect_orderの定義

php.iniの”mbstring.detect_order”のディレクティブでは、文字コード自動検出の優先順位を定義します。

この”mbstring.detect_order”の既定値は”auto”という値になっており、”auto” は “ASCII,JIS,UTF-8,EUC-JP,SJIS”の順に展開されます。
参考記事にも記載されているようにマルチバイト文字を扱う際にASCIIが先頭にある時点で問題であるので、”UTF-8,EUC-JP,SJIS,JIS,ASCII”のように出力する文字コードを優先して設定するようにします。

mbstring.language の誤解

php.iniの”mbstring.language”ディレクティブは、mbstringで使用される言語のデフォルト値を定義するものです。

“mbstring.language”には”Japanese”や”ja”などを指定するわけですが、”Japanese”といっても具体的にどの文字コードが設定されるのか、例えばUTF-8が設定されるのかEUC-JPが設定されるかは不明で、実際に具体的な文字コードを指定するには”mbstring.internal_encoding”を利用します。
従って、”mbstring.language”を設定する意味がよくわかりません。

この”mbstring.language”ディレクティブは主にmb_send_mail関数で利用されます。
mb_send_mail関数では使用する文字コードを”mbstring.language”で判断するそうですが、前述したように”mbstring.language”に”Japanese”を指定したところで、ISO-2202-JPで送るのか、UTF-8で送るのか、またはSJISで送るのか全く不明です。

その上、mb_send_mail関数では文字コードの変換を指定できませんので、この関数は利用しないほうが無難です。
日本語を利用したメールの送信時は、PEAR::Mailやフレームワークのメールコンポーネントを利用したほうがいいでしょう。

mb_http_output の誤解

mb_http_output関数は、HTTP 出力文字コードを指定するものです。
このmb_http_output関数で文字コードを指定しておけば、自動的に指定した文字コードに変換されて出力がされるとよく誤解されていますが、実はこの関数で文字コードを指定しただけでは何も動作しません。

これは”mb_output_handler”が実行された時の出力エンコードであり、具体的には下記のステートメントが実行される時にはじめて変換が有効化されます。

ob_start("mb_output_handler")

さらに、もうひとつのよくある誤解として、mb_http_output関数での変換はすべての出力に適用されると思われがちですが、そうではありません。
このmb_http_outputの動作条件は、出力がtext/htmlであることで、application/xmlなど他のコンテンツタイプだと動作しません。

従ってこの自動変換は利用しないほうが無難で、利用するにしても前述の使用を念頭に置いて組み込むといいと思われます。

マルチバイト設定の確認

なお、マルチバイト環境の設定を確認するには、mbstring の内部設定値を取得する関数であるmb_get_infoが便利です。

test.php
&lt;?php
echo "<pre>\n";
print_r(mb_get_info());
echo "</pre>\n";

  • “default_charset”・”default_mimetype”によるHTTPヘッダーのContent-Typeの自動出力は行わない。header関数で手動で出力する
  • “mbstring.internal_encoding”で設定する「内部文字エンコーディング」とは「mbstring関数を利用するときのデフォルト文字コード」という意味である
  • “mbstring.detect_order”は必ず指定する
  • mb_send_mail関数は利用しない。代わりにPEAR::Mailやフレームワークのメールコンポーネントで代替する
  • mb_http_outputは自動で変換が行われるわけではなく、その上コンテンツタイプがtext/htmlの場合でしか動作しない

 - PHP , , , ,