LoginSignup
33
39

More than 3 years have passed since last update.

PHPで配列をCSV出力する

Last updated at Posted at 2020-10-25

きっかけ

業務でDBのデータをcsv出力したいという要件から実装
これからも必要になってくると思ったのでまとめました。

今回の内容

csvとして出力したデータをボタンを押すとダウンロードする

こんな感じ
csv-test.gif

phpでcsv出力する際、fputcsv関数SplFileObjectクラスを使用する方法があるみたいですが、今回はfputcsv関数を用いました。
この関数やクラスを使わなくても実現は可能

csvとは?

「CSV」とは "Comma Separated Value" の略で、データをカンマ(" , ")区切った値の事です。アプリケーション間でデータをやり取りする際に使われます。CSV形式で保存されたファイルを「CSVファイル」と呼びます。

Excelとの違いはExcelは文字に色とか罫線とかデータに装飾可能ですが、csvはただテキストで構成されているデータみたいです。
余分な情報がないのでアプリケーション間でテキストデータのやり取りが可能になります。

いざ実装

  • 出力したいデータ
$user = array(
    array(
        'id' => 1,
        'name' => 'Aさん',
        'email' => 'aaa@a.com',
        'password' => 'aaaaa'
    ),
    array(
        'id' => 2,
        'name' => 'Bさん',
        'email' => 'bbb@b.com',
        'password' => 'bbbbb'
    ),
    array(
        'id' => 3,
        'name' => 'Cさん',
        'email' => 'ccc@c.com',
        'password' => 'ccccc'
    ),
);

※こういうデータをDBから取ってきて配列に入れる。


  • ダウンロードボタン表示
<h1>Hello World!<h1>
<a href="./csv.php">
    <button>csvダウンロード</button>
</a>

スクリーンショット 2020-10-25 11.31.17.png


  • csv出力andダウンロード処理

$user =[配列]

function putCsv($data) {

    try {

        //CSV形式で情報をファイルに出力のための準備
        $csvFileName = '/tmp/' . time() . rand() . '.csv';
        $fileName = time() . rand() . '.csv';
        $res = fopen($csvFileName, 'w');
        if ($res === FALSE) {
            throw new Exception('ファイルの書き込みに失敗しました。');
        }

        // 項目名先に出力
        $header = ["id", "name", "email", "password"];
        fputcsv($res, $header);

        // ループしながら出力
        foreach($data as $dataInfo) {
            // 文字コード変換。エクセルで開けるようにする
            mb_convert_variables('SJIS', 'UTF-8', $dataInfo);

            // ファイルに書き出しをする
            fputcsv($res, $dataInfo);
        }

        // ファイルを閉じる
        fclose($res);

        // ダウンロード開始

        // ファイルタイプ(csv)
        header('Content-Type: application/octet-stream');

        // ファイル名
        header('Content-Disposition: attachment; filename=' . $fileName); 
        // ファイルのサイズ ダウンロードの進捗状況が表示
        header('Content-Length: ' . filesize($csvFileName)); 
        header('Content-Transfer-Encoding: binary');
        // ファイルを出力する
        readfile($csvFileName);

    } catch(Exception $e) {

        // 例外処理をここに書きます
        echo $e->getMessage();

    }
}

putCsv($user);

※追記(@rana_kualu さんのコメントを受けて)

上記の方法では出力するために作った$csvFileNameファイルが/tmp/に残ったままになっています。

  • ファイルを出力した後にunlinkでファイルを削除する。
  • tmpfileで自動的に一時ファイルを削除する。
  • fopenfilenamephp://outputを指定して一時ファイルを作らずcsv出力する。

一時ファイル


■fopen関数で出力するファイルを指定して開く
第2引数にwを指定して書き込みモードにする。

■fputcsv関数で上記で開いたファイルにcsvを出力していく
foreachで回す前にヘッダーとなる部分を出力する。
その後にforeachで配列を回して出力する。

■ダウンロードのためにHTTPヘッダーを設定する
Content-Type以下でphpの出力形式を指定する。
今回はcsvファイルとして出力する指定をしているので、ブラウザで閲覧できるページとしては出力されない。

出力結果

スクリーンショット 2020-10-25 11.41.24.png
mb_convert_variables('SJIS', 'UTF-8', $dataInfo);で文字コードを変換しているので日本語部分の「さん」がちゃんと表示されている。
これがないとExcelで開いたときに文字化けしてしまう。

以上です

33
39
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
39