さまよえるプログラマ(当社比)のtetsuです。
個人的にPHP4系のサーバに関わることが多いのですが、PHP5のサーバでCSVファイルの取り込み処理を行う機会があった為、いつも通りコーディングしていたら予期せぬ事態に遭遇しました。
その時のことを、備忘録として残しておきます。
利用した関数
CSVファイル取り込み処理としてよく使われる関数がこれ
fgetcsv()
関数自体はPHP4とPHP5、どちらでも使えます。
記述の仕方も大きく変わるものではないので、普通にコーディングを行ってました。
コーディングは難なく進みCSVファイルは「Shift-JIS」のエンコードタイプでシステムは「UTF-8」。この違いもエンコードの変更処理を加えて終わりと、いざ実行。。。
ざっくりな処理の流れ
- 1.CSVファイルをfopenする
- 2.whileでfgetcsvをする
- 3.UTF-8へ文字コードを独自の再起関数で変換する
ということでCSVデータの取り込みも問題なくできた。と、思っていた矢先に
取り込みしたデータ内に「?」が出てくる!特にローマ数字。
なぜ!?
CSVファイルに何か問題が?
CSVファイルのフォーマットは一般的に「,」区切りの「”」で括る。今回のデータを確認してもフォーマット通り。ロケール設定(ja_JP)もしてる。
特殊記号を回避するために「sjis-win」も指定している。このままだとローマ数字などの変換マップを作る事に、と思い調査。。。
PHP5での「fgetcsv()」関数のバグ!?
調査をしていくと、やはりPHP5で若干の仕様変更が引き起こされているようで。PHP4の時は問題なかった全角文字と特殊記号に対応してないという事が判明。
完全な解明となるとソースコードレベルで見ることになり、ここでは説明しきれないので、回避策は次の通り。
setlocale(LC_ALL, 'ja_JP');<br />
mb_detect_order("SJIS-win");<br />
$list=array();<br />
//PHP5用回避$fileData=file_get_contents($file['tmp_name']);$fileBuf = mb_convert_encoding($fileData, "utf-8", "sjis-win");$tmp = tmpfile();fwrite($tmp, $fileBuf);rewind($tmp);while(($array = fgetcsv($tmp, 2500, ',')) !== false) { $list[] = $array;}
参考にさせて頂いたサイトはこちら
回避策でコーディングをやり直して実行すると問題無く処理されました。
危うく変換マップなるものを作って膨大な時間を費やすところでした。
こういった解決方法があることをプログラマとして覚えておかないといけませんね。
しかし、fgetcsv関数のPHP5における仕様変更は盲点でした。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。