出力時の文字エンコーディング変換、妥当性確認について
大垣さんが以下のページで PHP について言及しておられますので、気になったことを書いておきたいと思います。
私は、現在、PHP で構築したサイト運用はしていませんので、出力時に文字エンコーディングを変換、妥当性確認する方法がどの程度有効で、どのような問題があるのかは十分把握していません。ある程度実施方法については書いておきますので、参考にされる方は、実用可能かどうかを十分検証してください。
出力時に文字エンコーディングを変換する方法
PHPで、似た様な動作にしたい場合(ブラウザ以外からの入力も怪しいなど)出力時に強制的に文字エンコーディング変換してしまえば良いです。例えば、
mbstring.internal_encoding = utf-8
mbstring.http_output = utf-8と出力文字エンコーディングを指定すると不正な文字列はサニタイズされます。
http://blog.ohgaki.net/rails-ruby-1-9
これだけでは設定が不足しています。これだでは出力時に文字エンコーディングは変換されません。PHP マニュアルの以下に記述されている通り、出力時に文字エンコーディング変換をしたい場合は、以下の2つの設定が必要です。output_buffering は有効になっています(4096 などになっています)が、output_handler は設定する必要があります。
例2 php.ini の設定例
;; 全ての PHP ページで出力の文字エンコーディング変換を有効にする
;; 出力バッファリングを有効にする
output_buffering = On;; mb_output_handler による出力変換を有効にする
http://php.net/mbstring.http
output_handler = mb_output_handler
mb_output_handler() では、Content-Type によって変換するかどうかを判定しています。全ての PHP スクリプトで文字エンコーディングの変換が行われるわけではありません。このため、以下の記述は誤りです。
ただし、http_outputをpass以外に設定すると副作用が発生するので注意が必要です。例えば、画像ファイルをUTF-8エンコーディングに変換すると確実に壊れます。
http://blog.ohgaki.net/rails-ruby-1-9
mb_output_handler() による、文字エンコーディング変換は、以下のようになっています。
出力時に文字エンコーディングを妥当性確認する方法
おそらく、元の記事だけでは、どうすれば良いのか分からないように思いますので、少し書いておきます。PHP スクリプト内で出力バッファリングを適用する場合は、以下のように、ob_start() を使用した後に出力します。
<?php ob_start( 'mb_output_handler' ); // HTML の出力処理
mb_output_handler() は、mbstring が出力用に提供している関数で、mbstring.internal_encoding に設定した文字エンコーディングから mbstring.http_output に設定した文字エンコーディングに変換します。PHP が用意している出力用関数は、他にも ob_iconv_handler() や ob_gzhandler() などがあります。
ob_start() の引数は、コールバック関数で、この関数は PHP スクリプト内で定義することもできます。定義する関数には、第1引数に出力する値がそのまま渡ってきます。この関数内で、何か処理を行い、出力する文字列を返します。何も返さなかった場合、何も出力しないことになります。この関数内では、echo, print_r(), var_dump() などによる出力はできません。
今回の大垣さんの例では、以下のように、出力全体に対して mb_check_encoding() を適用し、不正な文字列が一文字でもあればエラー処理をする関数になっています。
<?php function check_encoding_handler( $output ) { if ( ! mb_check_encoding( $output ) ) { // trigger_error('Invalid char encoding detected', E_USER_ERROR); return get_error_page(); // エラーページの HTML など } return $output; } ob_start( 'check_encoding_handler' ); // HTML の出力処理
注意点としては、ob_start() は複数回呼び出すことが可能です。このため、複数使用する場合、処理内容によっては、順番に注意してください。ob_start() は、入れ子構造で適用されますので、後で実行した方が先に適用されます。例えば、ob_gzhandler() を使用している場合は以下のようにします。
<?php ob_start( 'ob_gzhandler' ); ob_start( 'check_encoding_handler' ); // 先に check_encoding_handler が適用されます。
この順番を反対にした場合、check_encoding_handler() では ob_gzhandler() で圧縮後のバイト列に適用することになります。このため、想定した結果にはなりません。
<?php ob_start( 'check_encoding_handler' ); ob_start( 'ob_gzhandler' ); // 先に ob_gzhandler が適用されます。
現在の出力ハンドラ情報は、ob_list_handlers() や、ob_get_status() で取得できます。
詳しくは、PHP マニュアルの以下のページを参照してください