CSVファイルを呼び出す前に文字コードを確認するようにする。

みなさんこんにちは

私の担当したプロジェクトで必要な情報をエクセルからCSVファイルに変換してそれをphpで読み取って保存する。
という手順がありました。
処理自体は簡単なものでSplFileObject()を使ってやればforeachで一行ずつ読み取るだけです。
しかし、一点読み取る前に問題がありました。文字コードです。

エクセルからCSVファイルを保存するとShift-JIS

調べてみるとどうやら最新のエクセルでは問題なくutf-8で保存ができるようですが、私の使用しているMicrosoft Excel 2010では難しいようです。
そのため一度CSVファイルを保存してからエディタなどで開いてutf-8に保存し直しています。
しかし人間なので何回もやっているとその工程を忘れてしまう事があります。
すると・・・・ターミナルが最悪停止します。
サーバーは生きてるとはいえ、ターミナルを立ち上げなおしたりするのも面倒なので、事前に文字コードをチェックするようにしました。

実装

    <?php

    // ファイル名は指定できるようにしておく
    $fileName = empty($argv[1]) ? "testText.csv" : $argv[1];

    // file -i ファイル名のコマンドで文字コードを調べる
    $command = "file -i " . $fileName;
    $output = [];
    $status = "";
    exec($command, $output, $status);

    /*
     * 以下のフォーマットの結果から正規表現で文字コードを抜き取る
     * ファイル名: MIMEタイプ; charset=文字コード
     */
    preg_match("/charset=(.*)/", $output[0], $charset);

    // utf-8以外なら警告して終了
    if (!in_array("utf-8", $charset)) {
        echo "読み取るCSVファイルはutf-8にしてください。" . PHP_EOL;
        echo "今の文字コード" . $charset[1];
        return;
    }

    // それ以降は実際にファイルを読み込むだけ
    $lines = new SplFileObject($fileName);
    $lines->setFlags(SplFileObject::READ_CSV);

    // ここではわかりやすく一行ずつ表示しているだけです。
    foreach ($lines as $line) {
        foreach ($line as $val) {
            echo $val;
        }
        echo PHP_EOL;
    }

fileコマンド

いきなりPHPではない話になりますが、Linuxサーバーにコマンドを投げてファイルを調べます。
file -i ファイル名で調べられるので試してみてください。
これをPHP側から実行して返り値から文字コードを確認します。

exec()

exec($command, $output, $return_val)を実行すると$outputに配列で結果が、$return_valにはコマンドを実行結果のステータスコードが入ってます。
ステータスコードを調べれば失敗した時にはそこでreturnするようにもできそうですね。

preg_match()

preg_match("/charset=(.*)/", $output[0], $charset)でcharset=に続く文字コードを抜き出します。

まとめ

ファイルを読み込む前という事で、PHP側から直接サーバーのファイルにアクセスしてみました。
実行するPHPファイルとCSVファイルが同階層という体で書いてしまいましたが、別階層の場合もそんなに難しくないと思います。

今後はその場で文字コード変換したりできれば普段の作業が楽になりそうですね。
もしコマンドを実行する以外にいい方法があれば是非教えてください。

Source: SEO