schedule2019-12-11

【PHP】CSV出力で値をダブルクォーテーションで囲う

CSV出力する際に、値をダブルクォーテーションで囲うに必要があった。

PHP標準のfputcsvではバグがありました。 $enclosureに設定しても間に空白がある文字列しかダブルクォーテーションで囲んでくれない。 fputcsvを使う前に"を付けると"""と出力してしまう。 これはエスケープ"`しても起きる。

結局自作した。

動作確認環境

  • PHP 7.3

値をダブルクォーテーションで囲ってCSV形式にする

下の関数で2次元配列のデータをCSV形式にして出力できる。

/**
    * CSV形式に変換
    * @param array $data 2次元配列
    * @return string $csv
    */
function tocsv($data, $toEncoding='sjis-win', $srcEncoding='UTF-8') {
    $csv = '';
    foreach ($data as $row) {
        // ダブルクォーテーションで囲う
        $row = array_map(function($value){return "\"{$value}\"";}, $row);
        // カンマ区切り
        $row = implode(',', $row);
        $csv .= $row . "\r\n";
    }
    $csv = mb_convert_encoding($csv, $toEncoding, $srcEncoding);
    return $csv;
}

処理が簡潔になるよう行を一括して整形している。

  • array_mapで配列の値をダブルクォーテーションで囲う
  • implodeで1行をカンマ区切の文字列に結合する
  • Windowsに対応した改行文字を末尾に付けて、$csv`に追加

また、Excelで開いたときに文字化けしないようにsjis-winにエンコーディングしている。

この後、ファイルに保存するなり、ダウンロードのさせるなりしても値をダブルクォーテーションで囲ったCSVができる。

LaravelでCSVダウンロード

Laravelの\Illuminate\Http\Responseを使ってCSVダウンロードを実装した例。 これをControllerで返してあげる。

/**
     * CSVダウンロード
     * @param array $list
     * @param array $header
     * @param string $filename
     * @return \Illuminate\Http\Response
     */
    public function download($list, $header, $filename)
    {
        if (count($header) > 0) {
            array_unshift($list, $header);
        }
        $csv = $this->tocsv($list);
        $headers = array(
            'Content-Type' => 'text/csv',
            'Content-Disposition' => "attachment; filename=$filename",
        );
        return \Response::make($csv, 200, $headers);
    }

正直言うとExcelで見る際にダブルクォーテーションで囲う必要性は薄い。 ゼロ埋めした数値をそのまま表示したいときぐらい。

参考