page_adsence

2011年4月26日火曜日

機種依存文字の文字コード変換

今回やっている案件で、CSV内に記述されているマルチバイトの文字をaddslashesでエスケープしている処理があった。
しかし、文字コードがSJISだったために、5C問題に該当する部分のSQLは全て失敗していた。
なので、その改修を今回行うために調べた内容を残す。

まずaddslashesについて調べてみた。
addslashesはマルチバイトに対応してないのに、普通に使われていてビビった。
とはいえ、全くエスケープされないわけではないので、
深く調べずにやると今回のような現象が起こる。

で、mysql_real_escape_stringを使うのが普通なのだが、
この関数も結局マルチバイトに対応しているわけではないので、


CSVに記述されているSJISの機種依存文字をMysqlのDBに入れようとした際のログ。
要件としては、機種依存文字や5C文字を安全にエスケープする方法を探す。

機種依存文字は基本的にはSJISには存在してない。
なので
mb_convert_encoding($text, 'utf-8', 'sjis');
などをしようものなら、あっという間に?とかに文字化けてしまう。
なので、

$str = mb_convert_encoding(mb_convert_encoding($text, 'sjis-win', 'sjis'), 'UTF-8', 'sjis-win');

上記のように一度sjisからsjis-winにエンコードしてから、UTF-8にエンコードをする。
こうすることで機種依存文字を文字化けさせることなく、文字コードを変換できる。

で、UTF-8に変換することで、5C問題は解決されるので、ここでエスケープする。

$str = mysql_real_escape_string($str);

で、エスケープした文字列を再びsjisに戻す。

$str = mb_convert_encoding($str, 'sjis-win', 'UTF-8');

ここで注意しないといけないのは、元のsjisに戻してしまうと、機種依存文字が文字化けしてしまうこと。
sjisには機種依存文字が存在しないので、戻す時はsjis-winに戻さないと、正常に表示できない。

とりあえず今回調べた感じだとこんな感じ。
なんか最初っからsjis-winからutf-8で変換できんじゃねって思ってやってみたらいけたし!!
まぁ試した文字はあんまりいっぱい試してないので、もしかしたら駄目な場合もあるのかも。
でも理論的には問題無さそうな気がする。
というわけで、最終的にはこんな感じで。

$str = mb_convert_encoding($text, 'UTF-8', 'sjis-win');
$str = mysql_real_escape_string($str);
$str = mb_convert_encoding($str, 'sjis-win', 'UTF-8');