I have a Laravel 5.4 app where authenticated users need to be able to download private files from S3 storage. I've setup a route and controller to allow private file downloads.
The code looks like this:
Route:
Route::get('file/{filename}', 'FileController@download')->where(['filename' => '[A-Za-z0-9-._\/]+'])->name('file')->middleware('auth:employee');
Controller:
public function download($fileName)
{
if (!$fileName || !Storage::exists($fileName)) {
abort(404);
}
return response()->stream(function() use ($fileName) {
$stream = Storage::readStream($fileName);
fpassthru($stream);
if (is_resource($stream)) {
fclose($stream);
}
}, 200, [
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Content-Type' => Storage::mimeType($fileName),
'Content-Length' => Storage::size($fileName),
'Content-Disposition' => 'attachment; filename="' . basename($fileName) . '"',
'Pragma' => 'public',
]);
}
All working fine, but when I had a closer look to the Laravel docs, I found that they just talk about response()->download()
.
If I implement that kind of response, my code would look like this:
public function download($fileName)
{
if (!$fileName || !Storage::exists($fileName)) {
abort(404);
}
$file = Storage::get($fileName);
return response()->download($file, $fileName, [
'Content-Type' => Storage::mimeType($fileName),
]);
}
Both functions can be found in the API docs.
My question: what would be the preferred way to go and what are the advantages/disadvantages of each?
From what I've gathered so far:
Stream:
Download:
Downloading files in Laravel is even more simple than uploading. You can pass download() method with file path to download file. Same way, if you want to download file from the public folder, you can use download() method from Response class.
stream-laravel is a Laravel client for Stream. You can use this in any Laravel application, or in any application that uses Eloquent ORM ( illuminate/database ) as a standalone ORM. You can sign up for a Stream account at https://getstream.io/get_started.
One way to delete a file from the public directory in Laravel is to use the Storage facade. To delete a file, you will need to follow the following steps: Step 1: Check to ensure that the folder and file exist. Step 2: Delete the required file.
When you call the Laravel response()
helper, it returns an instance of the Illuminate\Routing\ResponseFactory
. The ResponseFactory
has these two methods: download
and stream
- the two methods in question. If you dig a little bit deeper, you'll see that download
returns an instance of \Symfony\Component\HttpFoundation\BinaryFileResponse
, while stream
returns a \Symfony\Component\HttpFoundation\StreamedResponse
- these are both Symfony components.
Digging through the code here isn't necessary, but it is nice to have an understanding of what's going on under the hood. Now that we know the underlying objects returned are from the Symfony HTTP Component, we can consult the Symfony docs and see what they recommend using. Typically, streams are used when the size of the file is unknown, such as when you are generating the file on the fly. In most other cases, the BinaryFileResponse
generated by the download
method will be sufficient for your needs.
You can take a look at a much more in-depth explanation of HTTP Streaming and its use cases here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With