How to return a CSV file in Laravel

Updated: January 16, 2024 By: Guest Contributor Post a comment

Introduction

When it comes to generating downloadable content, CSV files are one of the most common formats developers come across. In Laravel, creating and downloading such files can be accomplished effortlessly. This tutorial will guide you through the process of creating and serving CSV files in a Laravel application using various techniques and packages.

Prerequisites

  • Basic knowledge of PHP and Laravel
  • A working Laravel application setup
  • Composer installed locally

Returning a Basic CSV File

Let’s start with the most basic implementation of returning a CSV file in Laravel using native PHP functions:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\StreamedResponse;

class ExportController extends Controller
{
    public function downloadCSV()
    {
        $callback = function() {
            $handle = fopen('php://output', 'w');
            fputcsv($handle, ['Header1', 'Header2', 'Header3']);
            fputcsv($handle, ['Data1', 'Data2', 'Data3']);
            fclose($handle);
        };

        return new StreamedResponse($callback, 200, [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="export.csv"',
        ]);
    }
}

In the above code, a simple CSV file is created on the fly and sent to the browser as a download. The php://output is used to write the output directly as a streamed response.

Using Laravel’s Response Helpers

Laravel offers a more fluent interface for sending different types of responses, including CSV files. Let’s use the response helper to clean up our CSV output:

public function downloadCSV()
{
    $filename = "export.csv";
    $headers = [
        'Content-type' => 'text/csv',
        'Content-Disposition' => "attachment; filename=$filename",
        'Pragma' => 'no-cache',
        'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
        'Expires' => '0'
    ];

    $columns = ['Header1', 'Header2', 'Header3'];

    $callback = function() use ($columns) {
        $file = fopen('php://output', 'w');
        fputcsv($file, $columns);

        // Sample data
        foreach(range(1, 10) as $index) {
            fputcsv($file, ["Row $index Col 1", "Row $index Col 2", "Row $index Col 3"]);
        }
        fclose($file);
    };

    return response()->stream($callback, 200, $headers);
}

The code shows creating a CSV file with an array of headers and a loop to generate sample data. A cleaner approach to sending the CSV as a stream is demonstrated with the response helper.

Using A Predefined Array

Often, you need to export an existing array to CSV. Here’s how that can be achieved:

public function exportPredefinedArray()
{
    $list = [
        ['Header1', 'Header2', 'Header3'],
        ['Data1', 'Data2', 'Data3'],
        // Other data rows...
    ];

    $headers = [
        'Content-Type' => 'text/csv',
        'Content-Disposition' => 'attachment; filename="export.csv"',
    ];

    $callback = function() use ($list) {
        $file = fopen('php://output', 'w');
        foreach ($list as $row) {
            fputcsv($file, $row);
        }
        fclose($file);
    };

    return response()->stream($callback, 200, $headers);
}

This time, the data to be exported to CSV comes from a predefined array. We iterate over this array and output each row as a CSV line.

Generating CSV From Database

To export data from a database, you can fetch your models and loop through the results. For example, let’s export users:

use App\Models\User;

//...

public function exportUsers()
{
    $headers = [
        'Content-Type' => 'text/csv',
        'Content-Disposition' => 'attachment; filename="users.csv"',
    ];

    $callback = function() {
        $users = User::all();
        $csv = fopen('php://output', 'w');

        fputcsv($csv, ['ID', 'Name', 'Email']);

        foreach ($users as $user) {
            fputcsv($csv, [$user->id, $user->name, $user->email]);
        }

        fclose($csv);
    };

    return response()->stream($callback, 200, $headers);
}

This code retrieves all users from the User model and writes each user as a row in the CSV file.

Using Third-Party Libraries

While native solutions work great, third-party libraries can simplify the process. The laravel-excel package by Maatwebsite is a popular choice. First, install it:

composer require maatwebsite/excel

Then, use it to create an export class:

php artisan make:export UsersExport --model=User

Define the export format:

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use App\Models\User;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}

And finally, use it within a controller:

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;

//...

public function exportExcel()
{
    return Excel::download(new UsersExport, 'users.xlsx');
}

This code snippet does not return a CSV format but an XLSX file, which is beneficial when working with Excel.

Advanced Usage – Customizing Exports

With laravel-excel, you can also customize the exported data:

public function map($user): array
{
    return [
        $user->id,
        $user->name,
        $user->email,
        $user->created_at->format('Y-m-d'),
    ];
}

public function headings(): array
{
    return [
        'ID',
        'Name',
        'Email',
        'Registered At',
    ];
}

The map method allows you to modify how each user is represented in the export, and the headings method customizes the headers.

Conclusion

In this tutorial, you’ve learned several ways to generate and return CSV files in Laravel. Whether you choose simple streaming techniques or powerful external packages, Laravel makes the process straightforward and efficient.