「phpでcsvを読み込んで項目名をキーにした連想配列をつくる[メモ]」
https://qiita.com/Terasan_Koshigaya/items/00ce0b114e527a572865
で紹介されている、csvToArray.php を使っていた。
// csvの1列目をキーにした連想配列を返す(引数:csvファイルのパス)
function csvToArray($csvPath){
$csvArray = array();
$firstFlg = true;
$keys = array();
$count = 0;
$file = fopen($csvPath, 'r');
while ($line = fgetcsv($file)) {
if($firstFlg){
for($i = 0; $i < count($line); $i++){
array_push($keys,$line[$i]);
}
$firstFlg = false;
}else{
for($i = 0; $i < count($line); $i++){
$csvArray[$count][$keys[$i]] = $line[$i];
}
$count++;
}
}
fclose($file);
return $csvArray;
}
これが、LibreOffice で出力したものは問題なかったけれども、
Excel で出力したCSVをどうもうまく読んでくれない。
以下の test1.csv (問題ない) と test2.csv ( キー名 DATE のデータが空になる ) の違いは無さそうなのだが・・・・
$ cat test1.csv
DATE,ID,NAME
2021/7/9,123,JOHN
$ cat test2.csv
DATE,ID,NAME
2021/7/9,123,JOHN
中身は同じのようなのにファイルサイズが異なっている
$ ls -alh test?.csv
-rw-r--r-- 1 www-data www-data 33 8月 31 12:00 test1.csv
-rw-r--r-- 1 www-data www-data 36 8月 31 11:59 test2.csv
改行コード CR/LF の問題かな? と思ったが、ダンプしてみると違っていた。
$ od -ax test1.csv
0000000 D A T E , I D , N A M E cr nl 2 0
4144 4554 492c 2c44 414e 454d 0a0d 3032
0000020 2 1 / 7 / 9 , 1 2 3 , J O H N cr
3132 372f 392f 312c 3332 4a2c 484f 0d4e
0000040 nl
000a
0000041
$ od -ax test2.csv
0000000 o ; ? D A T E , I D , N A M E cr
bbef 44bf 5441 2c45 4449 4e2c 4d41 0d45
0000020 nl 2 0 2 1 / 7 / 9 , 1 2 3 , J O
320a 3230 2f31 2f37 2c39 3231 2c33 4f4a
0000040 H N cr nl
4e48 0a0d
0000044
改行コードではなく、ファイル頭に efbbbf がついています。UTF-8 の BOM ですね。
このシステムは、CSVファイルをユーザーでアップロードして処理するものです。
だったのですが、 function csvToArray($csvPath) を呼び出す前に以下のように下処理をしました。
変更前:
if (is_uploaded_file($tempfile)) {
if ( move_uploaded_file($tempfile , $filename )) {
echo $filename . "をアップロードしました。";
変更後:
if (is_uploaded_file($tempfile)) {
if ( move_uploaded_file($tempfile , $filename."_BOM" )) {
exec ( "nkf -w ".$filename."_BOM > ".$filename );
echo $filename . "をアップロードしました。";
nkf コマンドを呼び出して、-w オプションで BOM ヘッダを消去。
これでちゃんと動くようになりました。