Sling Academy
Home/PHP/How to return stream response in Laravel (for large files)

How to return stream response in Laravel (for large files)

Last updated: January 16, 2024

Introduction

Handling large files effectively is crucial to providing a good user experience and maintaining server performance. In Laravel, one of the best ways to handle the download of large files is by streaming responses rather than directly returning file contents. This helps to reduce memory usage drastically. In this tutorial, we’ll explore how to stream large files to the user, ensuring your Laravel application remains performant and scalable.

Prerequisites

Before we dive into streaming responses, here’s what you need to get started:

  • A running Laravel installation (version 5.5 or higher recommended)
  • Basic knowledge of Laravel’s request/response structure
  • Familiarity with PHP’s file handling functions

Basic Streaming Response

To return a stream response in Laravel, you’ll use the response()->stream() method. Here’s a simple example of a controller method that streams a large text file to the browser:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Storage;

class FileDownloadController extends Controller
{
    public function streamLargeFile()
    {
        $filePath = storage_path('app/largefile.txt');

        return response()->stream(
            function() use ($filePath) {
                $stream = fopen($filePath, 'r');
                fpassthru($stream);
                fclose($stream);
            },
            200,
            [
                'Content-Type' => 'text/plain',
                'Content-Disposition' => 'attachment; filename="largefile.txt"'
            ]
        );
    }
}

The above code defines a controller method that opens a read stream to a file, writes its content to the output buffer, and then sends the file to the client’s browser as a downloadable attachment.

Custom Headers and Streamed Downloads

At times, you may want to have more control over the HTTP headers in your stream response. Here’s how you can implement streaming with custom headers:

<?php

// ... (previous code)

public function customStreamHeaders()
{
    // ...

    return response()->stream(
        // Streaming logic remains the same
        // ...
        function () {
            // Your streaming logic here
        },
        200,
        [
            'Content-Type' => $customMimeType,
            'Cache-Control' => 'no-cache, must-revalidate', // Custom cache control
            'Content-Disposition' => 'inline; filename="' . $customFileName . '"',
        ]
    );
}

This example introduces custom HTTP headers, including specifying the MIME type and setting cache control to prevent caching of the response.

Note: Be sure to validate and sanitize custom data used for header values to avoid security issues such as header injection attacks.

Chunked Reading for Extremely Large Files

For extremely large files, reading a file in chunks can prevent PHP memory buffer overflow. To achieve this, you would use a loop coupled with a read buffer:

<?php

// ... (previous code)

public function chunkedFileStream()
{
    // ...

    return response()->stream(
        function() use ($filePath) {
            $stream = fopen($filePath, 'r');
            while (!feof($stream)) {
                echo fread($stream, 1024 * 1024); // Reading in chunks of 1MB
                flush();
                ob_flush();
            }
            fclose($stream);
        },
        200,
        [
            'Content-Type' => 'text/plain' // Custom headers can be added here
        ]
    );
}

This code reads the file in 1MB chunks until the end of the file is reached, sending each chunk immediately to the user, which is more efficient for very large files.

Using Laravel’s Filesystem for Streaming

Laravel’s filesystem provides a fluent, abstracted way to work with local and remote storage options. Here is how you can use Laravel’s Filesystem to stream a response:

<?php

// ... (previous code)

use Illuminate\Support\Facades\Storage;

public function streamWithFilesystem()
{
    // ...

    $path = 'path/to/your/largefile.ext';
    $filesystem = Storage::disk('local');

    if (!$filesystem->exists($path)) {
        abort(404);
    }

    $stream = $filesystem->readStream($path);

    return response()->stream(
        function() use ($stream) {
            fpassthru($stream);
        },
        200,
        [
            'Content-Type' => $filesystem->mimeType($path),
            'Content-Disposition' => 'attachment; filename="' . basename($path) . '"'
        ]
    );
}

In this example, we use Laravel’s Storage facade to access the file system and return a stream. This approach allows for abstraction and supports local as well as cloud storages like Amazon S3, making it a versatile and scalable solution for Laravel applications.

Conclusion

Streaming large files in Laravel can greatly reduce memory usage and help maintain server performance. The approaches we’ve covered range from basic streaming with built-in PHP functions to leveraging Laravel’s powerful filesystem abstraction layer. By understanding and utilizing these techniques, you can handle large file downloads gracefully in your Laravel applications.

Next Article: File Response in Laravel: An Example-Driven Guide

Previous Article: How to create an RSS feed in Laravel

Series: Laravel & Eloquent Tutorials

PHP

You May Also Like

  • Pandas DataFrame.value_counts() method: Explained with examples
  • Constructor Property Promotion in PHP: Tutorial & Examples
  • Understanding mixed types in PHP (5 examples)
  • Union Types in PHP: A practical guide (5 examples)
  • PHP: How to implement type checking in a function (PHP 8+)
  • Symfony + Doctrine: Implementing cursor-based pagination
  • Laravel + Eloquent: How to Group Data by Multiple Columns
  • PHP: How to convert CSV data to HTML tables
  • Using ‘never’ return type in PHP (PHP 8.1+)
  • Nullable (Optional) Types in PHP: A practical guide (5 examples)
  • Explore Attributes (Annotations) in Modern PHP (5 examples)
  • An introduction to WeakMap in PHP (6 examples)
  • Type Declarations for Class Properties in PHP (5 examples)
  • Static Return Type in PHP: Explained with examples
  • PHP: Using DocBlock comments to annotate variables
  • PHP: How to ping a server/website and get the response time
  • PHP: 3 Ways to Get City/Country from IP Address
  • PHP: How to find the mode(s) of an array (4 examples)
  • PHP: Calculate standard deviation & variance of an array