PHPでCSVを読み込んだら配列に異常が出ていた件

PHPでCSVを読み込んだら配列に異常が出ていた件

PHPでCSVを読み込んだら配列に異常が出ていた件

この問題知りませんでした。既知の問題なのだそうです。

SJISのCSVをfgetcsvで直接読み取るのは「5C問題」のため危険である。

発生した異常

楽天市場の商品分析をCSVで落とし、PHPで読込み配列化、欲しい情報をDBに格納すると言う使い方をしたのですが、レコードをよく見ると意味不明なものが…。

6列目の値には出品URLが格納されているはずなのに【 0 】というレコードが存在する

楽天市場からDLされたデータの文字コードは Shift_jis サーバー側は UTF-8 なのでこの文字コードの問題だろうと思い、行ごとに読込んでいるパートでエンコードを変更、再度実行してみます。

…結果が変わらない。
まずい、これはハマるルートかも…。

まずは何が起こっているのか確認

可能性としてはこの3つしか考えられない

  1. 商品名等にカンマが入っていてCSVの読込場所がずれてしまった
  2. 使えない文字がある
  3. エンコードの変換が上手くいっていない

まずはエンコード変換結果の確認。
意味不明な文字は入っていないのでエンコードは成功しているようです。
カンマも入っていない。
となると使えない文字??

使用していた文字を切断してテストしてみた所、次の現象を確認しました。

文字列の最後に【能】の文字が入っていると次のカラムの値が 0 になる

fgetcsvでのCSV読込では『5C問題』が発生する

丁度【可能】って書いてあるところがダメだったんですよね。■5C問題とは

「ソ」「表」「十」「予」などSJISの文字の2バイト目が「5C」になる文字が、fgetcsvなどの処理機に与えられたとき、それが文字の一部としてでなく、ASCIIのバックスラッシュ(5C)と判断してしまい、エスケープ文字として解釈される問題を言う。

なるほど「能」もここに入るのね。
他にもこんな文字が5C問題を引き起こすようです。

— ソ Ы 噂 浬 欺 圭 構 蚕 十 申 曾 箪 貼 能 表 暴 予 禄 兔 喀 媾 彌 拿 杤 歃 濬 畚 秉 綵 臀 藹 觸 軆 鐔 饅 鷭

安全に処理する方法

次の段取りで操作を行うと解消されます。

  1. file_get_contentsでSJISで書かれたCSVファイルを読み込む
  2. 読込んだファイルをUTF-8にエンコードする
  3. エンコードしたファイルを file_put_contents で上書き保存する
  4. 上書きしたものを fgetcsv で読込み展開する

めんどくさいですがしょうがないですね。

実際に書いたコード

まとめ

自分なりに「結構かけるようになってきたな」などと思っていた矢先にコレです。

まだまだ足りない知識は多いなぁとシミジミ感じました。