2009年10月06日

PHPの文字コード設定について(1)

PHPの設定ファイルなどで設定できる文字コードの自動変換を利用しない。
具体的な文字コードの判定と変換はプログラム内部で確実に行うという考え方。
またさまざまな環境に移植する前提がある場合は、細かい設定はphp.iniではなく、.htaccessかプログラム内部で行った方が、移植先のphp.iniの設定に煩わされることがすくなく有利。
以下は推奨設定。

;; Disable Output Buffering
output_buffering = Off

;; Set HTTP header charset
; default_charset = EUC-JP

;; Set default language to Japanese
mbstring.language = Japanese

;; HTTP input encoding translation is enabled.
mbstring.encoding_translation = off

;; Set HTTP input encoding conversion to auto
mbstring.http_input = pass

;; Convert HTTP output to EUC-JP
mbstring.http_output = pass

;; Set internal encoding to EUC-JP
mbstring.internal_encoding = EUC-JP

;; Do not print invalid characters
mbstring.substitute_character = none

mbstring.detect_order = SJIS,EUC-JP,JIS,UTF-8,ASCII

以下、各パラメータに関する詳細。

■default_charset
このパラーメータは、出力時にHTTPヘッダとして送信する文字コード名を指定するものである。
名称的に紛らわしいため誤解されやすいが、これはPHP内で使われる何らかのデフォルト文字コードを指定するものではないので注意。
例えば、default_mimetype = 'text/html'で「default_charset = 'utf-8'」と設定した場合、

header('Content-Type: text/html; charset:utf-8');

というコードが出力される。
したがって、PHPでメールやXMLなど、Web以外のものを生成する際は、これらのコードは余計なものとなってしまうためdefault_charsetは設定すべきではない。
多くの解説書や初心者本でこのパラメータを設定するように書かれているが、とくに必要がないなら設定すべきではない。

■mbstring.language
このパラメータは内部言語のことではない。
知っている人は少ないかもしれないが、languageパラメータは全く使われないパラメータだ。
これが利用される機会はただ一つ。
mb_send_mailを利用した時だけ
mb_send_mailは全く使わない関数なので、このパラメータは存在意義がない。

また、マルチバイトのメールを送るからといって、mb_send_mailを使っている人も多いかもしれない。
だが、このmb_send_mailは文字化けの元凶だ。
mb_send_mailは何の文字コードを何の文字コードに変換するかを指定することが出来ない。
なので、何の文字コードで入力を受け付けて、ブラックボックスを通った後に何の文字コードで出力されるか全くわからないのである。

理由はmb_send_mailで利用される文字コードは、languageパラメータに依存しているからだ。
languageにJapaneseと指定したところで、ISO-2202-JPで送るのか、UTF-8で送るのか、またはSJISで送るのか全く不明だ。
それにマルチパートメールの場合は、文字コードが一律でないことがある。
例えばDoCoMoのデコメール。
テキスト部分はJISだがHTML部分はSJISだ。
DoCoMOはSJIS Loveなためこのような仕様になっているが、迷惑この上ない。
そんなことをせずに、送信するメールをあらかじめ変換しておきmailに通す方が制御がわかりやすい。
mailも使い勝手が悪い関数なので、PEAR::MailでSMTP送信するのが一番良い方法だろう。


■mbstring.internal_encoding
紛らわしいが、このパラメータは内部エンコードのことではない。
PHPには内部エンコードという概念は存在しない。
ではmbstring.internal_encodingとは何なのか。
これは、「mbstring関数のデフォルトエンコード」なだけである。
mb_convert_kanaなどのパラメータで、変換元文字コードの指定がなかった時にだけ利用されるものだ。
これが必須なのはmb_decode_mimeheaderぐらいだ。
( ・_・;) エ゛ッ!?
驚くのも無理はない。
大抵のPHP本にはPHPの内部エンコードと説明しているし、インストール直後に必ず設定するように書かれている。
だが、実際はほとんど使われていないパラメータなのだ。
例えばPHPのソースコードをEUC-JPで書いたからといって、mbstring.internal_encodingがEUC-JPである必要は全くない。

SJISで利用した場合、5C問題(「ソ」「表」などを記述するとパーサエラーが出る)が発生するわけだが、
internal_encodingをSJISにしても問題は解決しない。
これを解決するには--enable-zend-multibyteをつけてコンパイルし直し、php.iniの設定で、
mbstring.script_encoding = Shift_JIS
とする必要がある(もちろんSJISは利用しないのが一番いいのだが)。
しかし、変換元が固定になるというのは重要なことなので、これはソースコードと揃えておくのがBetter。
マルチバイト関数を使う時は変換元エンコードを必ず指定する癖を付けておくのが重要なのである。


■mbstring.detect_order
これは必ず指定する。detect_orderとは「文字コードの自動検出の優先順位」のこと。
何も指定しなければ「auto」というパラメータになるのだが、このautoはかなりくせ者だ。
何も指定していない場合や、autoを指定すると「ASCII,JIS,UTF-8,EUC-JP,SJIS」の用に展開される。
が、マルチバイトを計る上でASCIIが一番先頭である時点ですでに欠陥である。
detect_orderは二次的に利用される機会が多いため、必ず指定する必要がある。
Webで出力する文字コードを先頭にしてJISやASCIIは最後の方にするのが良い。

これはプログラム上でも構わない。
私はプログラム上で指定している。
可能な限りphp.iniの設定に依存しないためだ。


■mbstring.http_outputは利用しない
http_outputについてはふたつ勘違いされやすいポイントがある。
ひとつは「指定すると自動で変換されて出力される様になる」という勘違い。

Σ( ̄ロ ̄; エッ!?チガウノ?

http_outputは指定するだけでは何も動作しない。これは、
mb_output_handlerが実行された時の出力エンコードに過ぎない。

ob_start("mb_output_handler")

と指定されて初めて使われるのだ。

もう一つは「すべての出力に適用される」という勘違い。

( ・_・;) エッ!?チガウノ?

ob_startを実行しても、すべての出力に適用されるわけではない。
http_outputの発動条件は「出力がtext/htmlである」必要がある。
なのでapplication/xmlとかをヘッダーで投げていると動かないのだ。
ラベル:PHP 文字コード
posted by ベルクカッツェ at 17:26| Comment(2) | 文字コード | このブログの読者になる | 更新情報をチェックする
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。