PHPでCSVを読み込んだら配列に異常が出ていた件
- 2020.09.10
- php備忘録
- 5C問題, CSV取り込み, fgetcsv, file_get_contents, file_put_contents, mb_convert_encoding, MySQL, PHP, エラー改善, エンコード変更, スクリプト備忘録, 文字化け, 自作システム
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 で読込み展開する
めんどくさいですがしょうがないですね。
実際に書いたコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#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); } |
まとめ
自分なりに「結構かけるようになってきたな」などと思っていた矢先にコレです。
まだまだ足りない知識は多いなぁとシミジミ感じました。
-
前の記事
VBSでの引数の渡し方と参照方法 2020.09.10
-
次の記事
ECの集客施策の効果測定と季節ワード等の『見える化』が必要だと思う 2020.09.15
コメントを残す