【Laravel】容量の大きいデータをcsvでダウンロードする方法

 暖かくなってきたと思ったら、また寒波と雨が降ってる東京、テンション下がるよね。。てことで、こんにちわ、Hashiです。今回は、Laravelで大量のデータをcsvとしてダウンロードするやり方を備忘録も兼ねて紹介したいと思います。大体、システム開発をする際はcsv等のダウンロード機能は求められることが多いですよね。

 なお、Laravelとはなんぞやという方は下の記事を参照してください!

環境

 今回の環境は下記の通りとなります。

今回の環境

  • Laravel 5.5
  • MySQL 5.6.37

大容量データをcsvでダウンロードする

 さて、早速、具体的にコードを書いていきますが、今回は下記の用法で実装してみたいと思います。

  • Symfonyの「StreamedResponse」クラスを使用する
  • fputcsvを使用する
  • php://outputストリームを使用する
  • chunkでデータを分割して取得する

 それぞれの用途理由は下記の通りです。

Symfonyの「StreamedResponse」クラスを使用する

 SymfonyのStreamedResponseクラスは、第一引数に文字列ではなくコールバック関数として出力内容を記述することができるのが特徴です。さらに第3引数にレスポンスヘッダの設定もできるので、CSV等のデータダウンロードの際にはとても便利です。

fputcsvを使用する

 fputcsvは、csv形式にフォーマットしてくれるPHPお決まりの関数ですね。

php://outputストリームを使用する

 fputcsvを使用する場合は、fopenまたはfsockopen関数によって正常にオープンされたファイルを指している必要があるとphpの公式サイトでは説明されていますが、今回はいちいちファイルに書きださなくても出力ストリームとして「php://output」を使用して、ファイルに書き出すことなくダウンロードしたいと思います。

chunkでデータを分割して取得する

 今回は、大容量のデータを扱うことを前提としていますので、chunkを使用してデータを分割取得する必要があります。これによってメモリーリークを防ぐことができます。

 ということで、実際にサンプルコードを書いていきたいと思います。なお、ここでは下記のような状態を想定します。

  • usersテーブルに大量のデータがある
  • usersテーブルには、idとnameフィールドが存在する
  • usersテーブルからid昇順で全件取得する
  • usersテーブルはUserモデルと紐づいている
  • chunkで1,000件ずつ分割して取得する

 まずは、StreamedResponseクラスを使用するので、ライブラリをimportします。

use Symfony\Component\HttpFoundation\StreamedResponse;

 次に、実際のダウンロード部分のソースになります。

public function downloadCSV()
{
      return  new StreamedResponse(
          function () {
              $stream = fopen('php://output', 'w');
              User::orderBy('id','asc')->chunk(1000, function ($users) use ($stream) {
                  foreach ($users as $user) {
                      fputcsv($stream, [$user->id, $user->name]);
                  }
                    
              });
              fclose($stream);
          },
          200,
          [
              'Content-Type' => 'text/csv',
              'Content-Disposition' => 'attachment; filename="users.csv"',
          ]
      );
}

 StreamedResponseの第一引数部分が実際にデータベースからデータを1,000件出力して、fputcsv関数でcsvにフォーマットしている箇所になります。そして、第3引数においてレスポンスヘッダを指定しています。

 これで大容量のデータでもメモリリークを起こさずにcsvのダウンロードをすることができます。

 以上、今回はここまで!Takaでした。また!

この記事のまとめ

  • Laravelで容量の大きいデータをcsvでダウンロードする方法

お仕事のご相談・ご依頼
お気軽にお問い合わせください!

お仕事の依頼はこちら

著者プロフィール

Taka

東京、奄美大島を拠点にサーフィンとスノーボードが好きなフリーランスのWebクリエイターです。普段はプログラム書いたりデザインしたり映像作ったりしています。いろいろな人の話しを聞くのが好きなので、このブログを通して多くの人と繋がりが出来たら嬉しいです。noteとInstagramもやっているのでフォローしてくれたらありがたいです!

人気記事

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です