matsudada技術ブログ

日々の雑念と備忘録

PHP7.2:Excelで編集できるCSVを作る

PHP7.2:Excelで編集できるCSVを作る

Excel 2016以降はUTF-8で扱えるようですので、2013以前の場合のお話です。

このやり方でダウンロードしたCSVファイルをExcelで編集してそのままアップロードできます。
ただ、Excelによる値の変換(ex.全角数字のみの項目は半角数字に変換される、数字の頭に有る0が消える)は起きるので注意してください。

環境

現象

CSVファイルをExcelで開くときに、文字コードSJIS以外の場合はBOMをつけないとSJISで読み込もうとして文字化けしてしまう。

また、開いたCSVファイルを保存したときにExcelが自動変換してしまう。

Excelで開いたとき、保存したときの動作は下表の通り。

区切り文字 文字コード BOM Excelで開いたときの動作 Excelで保存したときの動作
カンマ UTF-8 無し 項目がセルごとに別れる。文字化け カンマ区切り・SJISで保存
カンマ UTF-8 有り 項目がセルごとに別れる。文字化けしない タブ区切り・SJISで保存
カンマ UTF-16 LE 有り セルごとに別れない。文字化けしない 1行が1項目扱い・UTF-16 LEで保存
タブ UTF-8 無し セルごとに別れない。文字化け 1行が1項目扱い・SJISで保存
タブ UTF-8 有り セルごとに別れない。文字化けしない 1行が1項目扱い・SJISで保存
タブ UTF-16 LE 有り 項目がセルごとに別れる。文字化けしない タブ区切り・UTF-16 LEで保存

対応

対応策としては2通り。今回は下のパターンで対応します。

  • カンマ区切りのSJISで出力する
  • タブ区切りのUTF-16 LEで出力する

参考リンクを参考にstream_filterでUTF-16 LEに変換し、タブ区切りで出力する。

// ストリームを開く
$fp = fopen('php://output','w');

// 文字コードを変換するフィルター
stream_filter_prepend($fp, "convert.iconv.utf-8/utf-16le//TRANSLIT");

// BOMをつける
fwrite($fp, "\xEF\xBB\xBF"); //UTF-8

// CSVのヘッダ行出力
$csvHeader = ["1列目", "2列目", "3列目"];
fputcsv($fp, $csvHeader, "\t");

// レコード出力
foreach ($rows as $row) {
    fputcsv($fp, $row, "\t");
}

// ストリームを閉じる
fclose($fp);

参考

[PHP] MacExcelと互換性のあるCSVファイルを出来るだけ効率よく作成する
https://qiita.com/mpyw/items/2795bef3ed561f4cf4e9

PHPのストリームフィルタでCSV読み込み
https://qiita.com/rana_kualu/items/dc99be34b9e2f721b70f

感想

お願いですからUTF-8で処理できるようにしといてください。

というか2016以降を使えという話かもしれないが。

一点分からないのが、なぜ付与するBOMが「\xFF\xFE」(UTF-16 LE)でなく「\xEF\xBB\xBF」(UTF-8)なのか。

BOMもstream_filterで変換されるのだろうか?

もう少し調べる必要がある。