PHPでCSVを読み込んだら配列に異常が出ていた件
PHPでCSVを読み込んだら配列に異常が出ていた件
この問題知りませんでした。既知の問題なのだそうです。
発生した異常
楽天市場の商品分析をCSVで落とし、PHPで読込み配列化、欲しい情報をDBに格納すると言う使い方をしたのですが、レコードをよく見ると意味不明なものが...。
6列目の値には出品URLが格納されているはずなのに【 0 】というレコードが存在する
楽天市場からDLされたデータの文字コードは Shift_jis サーバー側は UTF-8 なのでこの文字コードの問題だろうと思い、行ごとに読込んでいるパートでエンコードを変更、再度実行してみます。
...結果が変わらない。
まずい、これはハマるルートかも...。
まずは何が起こっているのか確認
可能性としてはこの3つしか考えられない
- 商品名等にカンマが入っていてCSVの読込場所がずれてしまった
- 使えない文字がある
- エンコードの変換が上手くいっていない
まずはエンコード変換結果の確認。
意味不明な文字は入っていないのでエンコードは成功しているようです。
カンマも入っていない。
となると使えない文字??
使用していた文字を切断してテストしてみた所、次の現象を確認しました。
文字列の最後に【能】の文字が入っていると次のカラムの値が 0 になる
fgetcsvでのCSV読込では『5C問題』が発生する
丁度【可能】って書いてあるところがダメだったんですよね。■5C問題とは
「ソ」「表」「十」「予」などSJISの文字の2バイト目が「5C」になる文字が、fgetcsvなどの処理機に与えられたとき、それが文字の一部としてでなく、ASCIIのバックスラッシュ(5C)と判断してしまい、エスケープ文字として解釈される問題を言う。
なるほど「能」もここに入るのね。
他にもこんな文字が5C問題を引き起こすようです。
— ソ Ы 噂 浬 欺 圭 構 蚕 十 申 曾 箪 貼 能 表 暴 予 禄 兔 喀 媾 彌 拿 杤 歃 濬 畚 秉 綵 臀 藹 觸 軆 鐔 饅 鷭
安全に処理する方法
次の段取りで操作を行うと解消されます。
- file_get_contentsでSJISで書かれたCSVファイルを読み込む
- 読込んだファイルをUTF-8にエンコードする
- エンコードしたファイルを file_put_contents で上書き保存する
- 上書きしたものを fgetcsv で読込み展開する
めんどくさいですがしょうがないですね。
実際に書いたコード
#function内
$filePath = "hoge/hoga/item_list_20200801_day_fuga.csv";
# file -i ファイル名のコマンドで文字コードを調べる
$command = "file -i " . $filePath ;
$output = [];
$status = "";
exec($command, $output, $status);
#エンコードを抜き取る
preg_match("/charset=(.*)/", $output[0], $charset);
#utf-8出ない場合処理実行
if (!in_array("utf-8", $charset)) {
#文字コードの変更※読込む前に変換しておく
$sjis = file_get_contents(filePath);
$utf8 = mb_convert_encoding($sjis, 'UTF-8', 'Shift_jis');
file_put_contents($data[0], $utf8);
}
$row = 0;
// ファイル存在チェック
if (($handle = fopen(filePath , "r")) !== FALSE) {
// 1行ずつ読込
$value = [];
while (($value = fgetcsv($handle))) {
//レコード開始まで無視
if(($row >=6)&&(!empty($value[0]))){
//商品URLをdumpする
var_dump(strval($value[5]));
}
$row++;
}
fclose($handle);
}
まとめ
自分なりに「結構かけるようになってきたな」などと思っていた矢先にコレです。
まだまだ足りない知識は多いなぁとシミジミ感じました。


