Laravel 5.2 stream download - php

I'm getting a bit muddled with a CSV download. I'm very happy to save it to a file and supply a link to the user, but this seems like the wrong way to go judging from things like these.
Going from this answer Use Laravel to Download table as CSV I think I've found that the stream() method no longer exists.
public function download()
{
$headers = [
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0'
, 'Content-type' => 'text/csv'
, 'Content-Disposition' => 'attachment; filename=galleries.csv'
, 'Expires' => '0'
, 'Pragma' => 'public'
];
$list = $this->users->getAllUsers()->toArray();
# add headers for each column in the CSV download
array_unshift($list, array_keys($list[0]));
$callback = function() use ($list)
{
$FH = fopen('php://output', 'w');
foreach ($list as $row) {
fputcsv($FH, $row);
}
fclose($FH);
};
// return Response::stream($callback, 200, $headers); // Old version
return response()->download($callback, 'Users-' . date('d-m-Y'), $headers);
}
I've tried to use the Laravel 5.2 response() function, however I'm just getting a bit lost as to what I'm responding with – download() seems the logical option, but that gives me the following error:
Object of class Closure could not be converted to string
Which makes sense. What is the right way of going about this? Or should I save the file and then just use the filepath as the first argument of my download() function – something that seems to be bad practise?

It was simple enough and worked great once I replaced the class & static call Response:: With the helper function, response()->:
return response()->stream($callback, 200, $headers);
I believe this uses the StreamedResponse class.

Related

Laravel 8 download PDF with Livewire

On my page I am making an invoice that is fully compatible with Livewire. I use this package: https://github.com/LaravelDaily/laravel-invoices to generate my invoice and everything works fine. But their is one problem I ran into. I can't download my PDF with Livewire.
Here is a basic example to generate a PDF and download it:
public function invoice()
{
$customer = new Buyer([
'name' => 'John Doe',
'custom_fields' => [
'email' => 'test#example.com',
],
]);
$item = (new InvoiceItem())->title('Service 1')->pricePerUnit(2);
$invoice = Invoice::make()
->buyer($customer)
->discountByPercent(10)
->taxRate(15)
->shipping(1.99)
->addItem($item);
return $invoice->download();
}
Whenever I click on a button
<a role="button" class="pdf-download cursor-pointer" wire:click="invoice">download</a>
Nothing happens. So the problem is that Livewire doesn't support this download method. And this download method looks like this:
public function download()
{
$this->render();
return new Response($this->output, Response::HTTP_OK, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="' . $this->filename . '"',
'Content-Length' => strlen($this->output),
]);
}
$this->render(); Renders a template in a specific folder
Is their a work around for this? Where I can download my pdf with a template or maybe a different strategy. I allready tried one thing. I stored the invoice into a session, like so:
Session::put('invoice', $invoice);
Session::save();
And in a different controller I have.
if ($invoice = Session::get('invoice')) {
$invoice->download();
}
But that gives me this error:
serialization of 'closure' is not allowed
And I tried some stuff I found here: https://github.com/livewire/livewire/issues/483
But nothing works. Can someone give me a direction on where to look or how to fix this? Thanks!
return response()->streamDownload(function () use($invoice) {
echo $invoice->stream();
}, 'invoice.pdf');
Seems to do the trick.

Laravel: Generating and downloading a CSV file using StreamedResponse produces ERR_INVALID_RESPONSE

I have a controller method like so:
use Symfony\Component\HttpFoundation\StreamedResponse;
public function downloadTransactions($type)
{
$this->authorize('download', Invoice::class);
$filename = 'invoices-' . strtolower($type) . '.csv';
$response = new StreamedResponse(function() {
Invoice::generateTransactionsCsv($type);
}, 200, [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
]);
return $response;
}
and then in my Invoice model I am populating the file:
public static function generateTransactionsCsv($type = null)
{
// Open output stream
$handle = fopen('php://output', 'w');
// Add CSV headers
fputcsv($handle, [
'ID',
'REF',
'DESCRIPTION',
'DATE',
'AMOUNT',
]);
// Close the output stream
fclose($handle);
}
but I get an ERR_INVALID_RESPONSE in Chrome, although I would assume the browser doesn't matter. I've checked similar questions which suggest installing the zip extension but I already have it installed. Using PHP 7.1 locally. Also tried looking at the logs but there doesn't seem to be anything there (using Valet locally).
If I move the logic from the model to the controller then it works fine but my example above is simplified to just the header row of the csv, in reality, there's a bit more to it so I'd like to keep the logic in the model if possible.
I've also tried opening and closing the file handle in the controller and passing it the model but that didn't work either.
Looks like it was because the $type variable wasn't being passed correctly:
$response = new StreamedResponse(function() use ($type) {
....
}
Was able to figure it out thanks to Safari, it downloaded a csv with the Laravel error trace in it which was weird, I didn't think it would be any different from Chrome.

Laravel 5.4 Response File -> Error in File

I am working with Laravel 5.4 and save some JPEG-Files to Storage with
`Storage::disk('local')->put('upload/pictures/full-size/'.$filename ,$picture);`
And now i try to get this pictures again which i tryed like
...
Routes:
Route::get('pictures/full/{filename}', ['as' => 'picture_full', 'uses' => 'ImageController#getFull']);
...
Image Controller:
public function getFull(Image $image)
{
$path = storage_path('app/'.Config::get('pictures.icon_size').$image->filename);
$handler = new \Symfony\Component\HttpFoundation\File\File($path);
$header_content_type = $handler->getMimeType();
$header_content_length = $handler->getSize();
$headers = array(
'Content-Type' => $header_content_type,
'Content-Length' => $header_content_length
);
return response()->file($path, $headers);
}
So now my Problem is, that the file can't be shown.
The Browser says the File contains an Error.
Tryed a lot, but just don't see what I am making wrong.
Anyone has an idea?

error while trying to serve a Dingo-protected download from Laravel 4

I am using Laravel 4 & dingo 0.8.3 trying to serve a dynamically created export file as a download in response to a protected route and am getting an error from inside dingo
I know that L4 is out of date, but this project was started over a year ago and is < 2 months away from delivery
Is there any workaround that I can use to get this done?
The file contains dynamically created json
(in routes.php)
Route::group([ 'protected' => true ], function(){
Route::resource('bundle', 'Bundle');
Route::get('bundle/download/{id}', 'Bundle#download');
(in Bundle.php)
$contents = $this->createBookletExport($id);
$nameForFile = $contents->exportName .'.intbnd';
$pathToFile = "/tmp/".$nameForFile;
File::put( $pathToFile, json_encode($contents) );
return Response::download($pathToFile,$nameForFile);
(in laravel.log)
[2016-02-21 13:57:24] local.ERROR: exception 'Symfony\Component\Debug\Exception\FatalErrorException' with message 'Call to undefined method Symfony\Component\HttpFoundation\BinaryFileResponse::getFormatter()' in [...]/vendor/dingo/api/src/Routing/Router.php:220
(from dingo/composer.json)
"require-dev": {
"tymon/jwt-auth": "0.4.*",
},
"extra": {
"branch-alias": {
"dev-master": "0.8-dev"
}
}
I have fixed this -- the answer was NOT to use the Response::download but to use Response::make and add some headers (I had tried headers with Response::download to no avail)
So this:
$contents = $this->createBookletExport($id);
$nameForFile = $contents->exportName .'.intbnd';
$pathToFile = "/tmp/".$nameForFile;
File::put( $pathToFile, json_encode($contents) );
return Response::download($pathToFile,$nameForFile);
Became this:
$contents = $this->createBookletExport($id);
$nameForFile = $contents->exportName .'.intbnd';
$headers = array('Content-Type' => 'application/octet-stream', 'Content-Disposition' => 'attachment; filename='.$nameForFile);
return Response::make(json_encode($contents),200,$headers);
and Dingo! Bob's yer Uncle !!
:)

cakephp file download link

I've encountered a problem I'm trying to solve for more than two days now: I've built a Website using cakephp and everything is working just fine but I got stuck when I tried to implement download links to files stored under APP_DIR/someFolder/someFile.zip.
How do I set download links to files inside someFolder? I often stumbled over "Media Views" I tried implementing them but so far I've been unsuccessful.
Besides is there no easier way to make files downloadable?
Media Views is deprecated since version 2.3. You should use Sending files instead.
Check out this minimal example in your controller:
public function download($id) {
$path = $this->YourModel->aMagicFunctionThatReturnsThePathToYourFile($id);
$this->response->file($path, array(
'download' => true,
'name' => 'the name of the file as it should appear on the client\'s computer',
));
return $this->response;
}
The first parameter of $this->response->file is relative to your APP directory. So calling $this->response->file('someFolder' . DS . 'someFile.zip') will download the file APP/someFolder/someFile.zip.
“Sending files” requires at least CakePHP version 2.0. Please also consider taking a look at the Cookbook link above.
If you are running an older version of CakePHP you should use Media Views as you already mentioned in your question. Use this code and refer to Media Views (Cookbook).
Here's the same method for older versions:
public function download($id) {
$this->viewClass = 'Media';
$path = $this->YourModel->aMagicFunctionThatReturnsThePathToYourFile($id);
// in this example $path should hold the filename but a trailing slash
$params = array(
'id' => 'someFile.zip',
'name' => 'the name of the file as it should appear on the client\'s computer',
'download' => true,
'extension' => 'zip',
'path' => $path
);
$this->set($params);
}
Right way to generate download link in CakePHP 3
Place this function in AppController or Write a component and then call from other controllers.
Make sure to change the content-type as per the download file
public function downloadResponse() {
return $this->response
->withHeader('Content-Type', 'application/pdf')
->withHeader('Content-Disposition', 'attachment;')
->withHeader('Cache-Control', 'max-age=0')
->withHeader('Cache-Control', 'max-age=1')
->withHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT')
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' PDT')
->withHeader('Cache-Control', 'cache, must-revalidate')
->withHeader('Pragma', 'public')
->withFile($filePath, ['download' => true]);
}

Categories