fgetcsv と ロケール

お勉強してて、軽くハマったのでメモ

fgetcsv ってなんぞ

参照:PHP: fgetcsv - Manual

要約すると

csv形式のファイルをfgets()みたいに取得するよ!

じゃあ fgets() でいいんじゃね?

fgets() に動作は似ていますが、 fgetcsv() は行を CSV フォーマットのフィールドとして読込み処理を行い、 読み込んだフィールドを含む配列を返すという違いがあります

配列で返してくれるところがミソと。

ハマり箇所

fgetcsv() でファイルを読み込んで、読み込んだ配列を foreach() で回して表示させると日本語が表示されない。
ソースはこんな感じ

csvファイル読み込み
public function getMessageData() {
   $dataFilePath = "./hogehoge.dat";

   // ファイルよりCSVデータ取得
   $fp = fopen($dataFilePath, 'r');
   $data = array();
   while ($row = fgetcsv($fp)) {
       $data[] = $row;
   }
   fclose($fp);
 
   return $data;
}
呼び出し
// メッセージデータ取得、表示
$data = getMessageData();

// メッセージデータをもとに表のHTML生成
foreach ($data as $row) {
    echo '<tr>';
    echo sprintf('<td>%s<td>', $row[0]);
    echo sprintf('<td>%s<td>', $row[1]);
    echo sprintf('<td>%s<td>', $row[2]);
    echo '</tr>';
csvファイル

1,てすと名前,テストめっせじ

実行した結果

1 空白 空白

と、テスト名前とテストめっせじが表示されない。

原因

注意:

この関数はロケール設定を考慮します。
もし LANG が例えば en_US.UTF-8 の場合、 ファイル中の 1 バイトエンコーディングは間違って読み込まれます。

文字コード。おまえか。

参照:PHP: setlocale - Manual

ちなみに

LANGの文字コードはこんな感じ

[riceplanting@localhost MessageBoard]$ echo $LANG
ja_JP.UTF-8
対策
// メッセージデータ取得
public function getMessageData() {
    setlocale(LC_ALL, 'ja_JP.UTF-8');
    // ファイルよりCSVデータ取得
    $fp = fopen($this->dataFilePath, 'r');
    $data = array();
    while ($row = fgetcsv($fp)) {
        $data[] = $row;
    }
    fclose($fp);
    
    return $data;
}

こいつを追加したら、無事日本語も表示されました。

setlocale(LC_ALL, 'ja_JP.UTF-8');


地味に、ファイルの文字コードを調べるのがわからない。
nfkコマンドとかでいいのかなーっと。