robdesilets's avatar

File Download

Hi,

I am using Laravel 8.

I wanted to run some ideas by some fellow developers to make sure I am understanding the way the file download works in Laravel.

I am using Amazon S3 as my back end storage system and it's all connected and working fine in my system.

I am providing a button so my customers can download files (invoices, videos, etc).

Option 1: Download via Streams

When I use the stock "download" it looks like (based on the source) that it's using streams as discussed here:

https://laravel.com/docs/8.x/filesystem#downloading-files

I understand this such that when I initiate a download it will connect to Amazon s3 and then read the file in real-time and pass "through" my web server for the entire download. As the bits are read from amazon (private bucket authenticated via the Laravel/s3 connector) they are sent back to the user.

Is that correct? Or does it somehow download the file first to a temp file on my web server and then send that back?

I would think with a lot of downloads going concurrently this approach would take a lot of resources from my web server.

Option 2: Temp URL

The other option is to create a Temp URL from Amazon and essentially hand off the download to Amazon as discussed here:

https://sutherlandboswell.com/force-file-download-from-aws-s3-in-laravel/

This would, I would think, just take my web server resources as it's setting up the temp URL and handing it off.

Any replies or insight would be greatly appreciated.

Thanks!

-Rob

0 likes
2 replies
laracoft's avatar
  1. If you use Storage::download(), it would be saving to your server and only after, your code has to perform the pass through download with readfile(), i.e. the entire file is not read into your memory, instead, bit by bit for a low resource approach to sending big files.

  2. To do pass through download from S3, you will have to call the temporaryUrl() and do a readfile() on the temporary URL.

  3. https://laravel.com/docs/8.x/filesystem#file-urls The temporary URLs can be made to expire in X minutes, this should be sufficient if you are not overly concerned about link sharing, i.e. the download is not a paid product etc

  4. #1 is pointless, furthermore if it is a big file, you can imagine nothing will happen at the downloader's side until the file has been transferred to your server.

  5. #2 gives you the best security/control such as single download only etc especially if it is a paid product, it will take up some resources, but that's the price required. I think there are easier ways to protect a paid product such as requiring another small download to "activate" this download.

  6. #3 is redirecting the downloader to the S3's temporary URL, which will expire in X minutes. It will not tax your server. Since it expires, leechers cannot abuse the temporary link by posting it all over the internet.

  7. I would say go for #3.

1 like
robdesilets's avatar
robdesilets
OP
Best Answer
Level 5

Thanks for the reply. In #3 you suggest, this is how I implemented it and it seems to work great (for amazon s3).




public function download($path, $filename)
    {

// $path = "some/path/to/file";
// $filename = "foo.mp4"; // the filename that will be downloaded on the customers computer

return redirect(Storage::cloud()->temporaryUrl(
                $path,
                now()->addHour(),
                ['ResponseContentDisposition' => 'attachment; filename ="' . $filename . '"']
            ));
}
1 like

Please or to participate in this conversation.