PHP で CSVファイルといえば、fopen() で指定して fgetcsv() でデータを取得する方法がすぐに頭に浮かび、検索してもその方法が多くヒットされます。で、途中に改行が含まれる CSVファイルを取り扱う場合は・・・。お断りしたいくらいです。
そんな思いに反して「途中に改行が含まれる CSVファイル(Shift_JIS)をPHP(UTF-8)でデータベース(utf8)に保存」というステキなご要望があり、奮闘した記録をここに載せようかと。
SplFileObject
冒頭にも記載した通り、PHP で CSVファイルといえば、fgetcsv() ばかりなのですが、そんな中、見つけたのが「SplFileObject クラス」。そうです。オブジェクト指向です! 5.1 から! 知りませんでした。(^^;
早速、様々なサンプルを拝見し、次のように組んでみました。
$file = new SplFileObject( 'exp.csv' ); $file -> setFlags( SplFileObject::READ_CSV ); $file -> setCsvControl( ',', '"' ); foreach( $file as $key => $line ){ foreach( $line as $str ){ $records[$key][] = strlen( $str ) > 0 ? mb_convert_encoding( $str, 'UTF-8', 'Shift_JIS' ) : ''; } } var_dump( $records );
上のスクリプトで、ほとんどは意図した通りに動きました。「ほとんど」・・・です。
希に隣り合う項目が結合されることが見受けられます。
具体的には、「”試験”,”動作”,”042-812-7728″,”神奈川県”」が正しいところ「”試験”,”動作”,042-812-7728″”,”神奈川県”」となり「”動作”,042-812-7728″”」が1つのデータと認識されてしまうことがあります。
原因は、Shift_JIS
ローカルでCSVファイルを UTF-8 で保存し、上のスクリプトで mb_convert_encoding を外して動作チェックを行ったところ、全て意図した通りに動きましたので、原因は文字コードの変換部分。しかも、上記の現象ですから、疑うのは1~2行目の部分。PHP が UTF-8 で CSVファイルが Shift_JIS なのだから、無理があるのは当然かと。
$file = new SplFileObject( 'exp.csv' ); $file -> setFlags( SplFileObject::READ_CSV );
対応策
はじめに一時保存用のファイルを作成し、サーバーにアップ。適切なパーミッションに設定。
csvファイルを file_get_contents で読み込み、文字コードを変換。その後、一時保存用のファイルに保存。
一時保存用のファイルで上のスクリプトを実行させる。
一時保存用のファイルの中身を空にする。
Excel や Access からの CSVファイルは、UTF-8 にして欲しいと思うこの頃です。
[mokurenCB]