コードロード

エラー討伐

【PHP】CSV出力したいのにheader()関数が効かない

環境

やりたかったこと

PHPCSVを出力する機能を作っていて、レスポンスヘッダーを下記のように設定したかった。

Content-Disposition: attachment; filename=ファイル名.csv
Content-Type: text/csv

課題

下記のメソッドを使ってレスポンスしたのに、 header() で設定したはずのが反映されていない。

使用した関数

<?php
  /**
   * CSVダウンロード
   *
   * @param string $file_name
   * @param array $header
   * @param array $csv_list
   * @return void
   */
  public static function csvDownload($file_name, $header, $csv_list) {

    // 出力バッファをopen
    $stream = fopen('php://output', 'w');

    // 文字化け対策
    mb_convert_variables('SJIS-win', 'UTF-8', $header);

    // 列名を記入
    fputcsv($stream, $header);

    // 2行目以降を1行ずつストリームへ記入
    foreach ($csv_list as $line) {
        mb_convert_variables('SJIS-win', 'UTF-8', $line);
        fputcsv($stream, $line);
    }

    fclose($stream);

    // ファイルダウンロードさせるためにヘッダーを調整
    header("Content-Type: text/csv");
    header("Content-Disposition: attachment; filename=$file_name");
    readfile($file_name);
    exit;
  }

Postmanで確認したレスポンスヘッダ

解決策

先程のメソッドで、 header() 関数を使う順番を最初に持ってきた

<?php
/**
   * CSVダウンロード
   *
   * @param string $file_name
   * @param array $header
   * @param array $csv_list
   * @return void
   */
  public static function csvDownload($file_name, $header, $csv_list) {

    // ファイルダウンロードさせるためにヘッダーを調整
    header("Content-Type: text/csv");
    header("Content-Disposition: attachment; filename=$file_name");

    // 出力バッファをopen
    $stream = fopen('php://output', 'w');

    // 文字化け対策
    mb_convert_variables('SJIS-win', 'UTF-8', $header);

    // 列名を記入
    fputcsv($stream, $header);

    // 2行目以降を1行ずつストリームへ記入
    foreach ($csv_list as $line) {
        mb_convert_variables('SJIS-win', 'UTF-8', $line);
        fputcsv($stream, $line);
    }

    fclose($stream);

    readfile($file_name);
    exit;;
  }

すると、想定通りにレスポンスヘッダに反映されていた。

公式にも記載の通り、メソッド内でも先に書くようにということか?

覚えておいて頂きたいのは、header()  関数は、 通常の HTML タグまたは PHP からの出力にかかわらず、すべての実際の 出力の前にコールする必要があることです。 https://www.php.net/manual/ja/function.header