Stream Files From S3

When using S3 as our external storage, sometimes we have to let users download files from S3. If file is too large, it may not fit in the memory. The solution is to stream file into user’s browser straight from S3. Let’s take a look how to do it with Laravel’s Filesystem.

$path = 'path/to/my/report.csv'
$adapter = Storage::getAdapter();
$client = $adapter->getClient();
$client->registerStreamWrapper();

$object = $client->headObject([
    'Bucket' => $adapter->getBucket(),
    'Key' => $path,
]);

$fileName = basename($path);

$headers = [
    'Last-Modified' => $object['LastModified'],
    'Accept-Ranges' => $object['AcceptRanges'],
    'Content-Length' => $object['ContentLength'],
    'Content-type'        => 'text/csv',
    'Content-Disposition' => 'attachment; filename='. $fileName,
];


return response()->stream(function () use ($adapter, $export) {
    if ($stream = fopen("s3://{$adapter->getBucket()}/". $path, 'r')) {
        while (!feof($stream)) {
            echo fread($stream, 1024);
        }
        fclose($stream);
    }    
}, 200, $headers);

There are 2 main things to pay attention to: 1) we need to register s3 stream wrapper ($client->registerStreamWrapper()) 2) we need to set Content-Disposition header to allow user’s browser to force a download.

The streaming is easy enough to do if you are using plain PHP. Please take a look at the Resources Used links to get an idea how to do that.

Resources Used

https://aws.amazon.com/blogs/developer/amazon-s3-php-stream-wrapper/

https://gist.github.com/fideloper/6ada632650d8677ba23963ab4eae6b48