123456789,0,234567890,ABCDE
345678901,1,456789012,BCDEF
上記のようなCSVファイルを読み込んで、数字はint型に変換し、配列に詰めて、さらにごにょごにょするというのをやってました。
しかし、下記のように、1行目の先頭が0になってしまうという問題とご対面。
その時の備忘録です。
array(4) {
[0]=>
int(0)
[1]=>
int(0)
[2]=>
int(234567890)
[3]=>
string(5) "ABCDE"
}
array(4) {
[0]=>
int(345678901)
[1]=>
int(1)
[2]=>
int(456789012)
[3]=>
string(5) "BCDEF"
}
疑惑① fgetcsv
Google先生で調べていくと、fgetcsvで苦しんだ先人の記事がたくさん出てきました。
やれsetlocaleだの、やれ文字コード変換だの、試してみたものの、結果は変わらず。
こりゃfgetcsvそのものを諦めるかと、SplFileObjectを使って書き直してみました。
ところが、結果は変わりません。
そこで、CSVファイルを読み込み、配列に詰めた段階でvar_dumpしてみました。
※詰め方が違うのは見逃してください。
array(2) {
[0]=>
array(4) {
[0]=>
string(12) "123456789"
[1]=>
string(1) "0"
[2]=>
string(9) "234567890"
[3]=>
string(5) "ABCDE"
}
[1]=>
array(4) {
[0]=>
string(9) "345678901"
[1]=>
string(1) "1"
[2]=>
string(9) "456789012"
[3]=>
string(5) "BCDEF"
}
}
…12?9じゃなくて?
疑惑② CSVファイル
どうやら先頭に意識していない3バイトが含まれているようです。
「php csv 先頭」でググって答えにたどり着きました。BOMです。
UTF-8とは:BOM付きとBOMなし(UTF-8N)の違い――Unicode関連の文字エンコード
先頭に数バイトつくって厄介すぎませんかね。
ダウンロードしてきたCSVファイルを流用して編集したのですが、確かに秀丸で開いてみたらBOMにチェックが入ってました。
というわけで、このBOM対策を行います。
※【参考】[解決済] ExcelでUTF-8のCSVを吐いたらwith BOMだったせいでPHPでの取込に不具合が出た件
BOM対策① CSVファイルをBOMなしに変更
エディタなどでCSVファイルをBOMなしに変更してしまいます。いちばん簡単です。
BOM対策② BOMを置換
そうはいってもBOMがあろうがなかろうが対応したいよね…という場合はこちら。
$count = 0;
$handle = fopen($file_dir.'sample.csv', 'r');
while (($data = fgetcsv($handle)) !== FALSE) {
if ($count === 0) {
$data[0] = preg_replace('/^\xEF\xBB\xBF/', '', data[0]);
}
$row[] = $data;
$count++;
}
※この記事は、アウトプットネタ棚卸し Advent Calendar 2018 22日目の記事も兼ねています。