16

I'm trying to get my Laravel app to download an excel file with phpSpreadSheet a continuation of PhpExcel. But so far I'm not having any luck with it. I first tried to make an Axios call through an onClick but that didn't work since JS is not allowed to save things. After that I tried to attach the button to a Laravel action this just opened an empty page.

I don't know if anyone here will be able to help me but I will remain hopeful

Ferdi van der Woerd
  • 366
  • 1
  • 4
  • 22
  • What do you mean by **JS is not allowed to save things**? – Asur Aug 17 '17 at 15:04
  • I looked online and somewhere I saw that JS couldn't save things on your computer because of security resasons – Ferdi van der Woerd Aug 17 '17 at 15:09
  • You are looking at it wrong, using axios you need to **trigger** the download, not perform the save – Asur Aug 17 '17 at 15:13
  • But that doesn't appear to be possible with this package. I have to use an Axios call to build up the file and then use a save function in the php to save it but but it should prompt me or at least save it locally but so far I have had no success getting either. – Ferdi van der Woerd Aug 17 '17 at 15:21

1 Answers1

33

First you need to set an endpoint in your routes to call it using ajax (axios in your case):

Route::get('spreadsheet/download',[
   'as' => 'spreadsheet.download', 
   'uses' => 'SpreadsheetController@download'
]);

In your controller:

public function download ()
{
    $fileContents = Storage::disk('local')->get($pathToTheFile);
    $response = Response::make($fileContents, 200);
    $response->header('Content-Type', Storage::disk('local')->mimeType($pathToTheFile));
    return $response;
}

In case you don't have the file you can save it to php://output:

public function download ()
{
    $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, "Xlsx");
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment; filename="file.xlsx"');
    $writer->save("php://output");
}

Now you just need to call the endpoint /spreadsheet/download to start the download, but a normal <a href="/spreadsheet/download">Download</a> would work.

Hope this helps you.

Asur
  • 3,727
  • 1
  • 26
  • 34
  • But this is just to download a local file if I'm reading it right. But I need to build the file first. and then save it like this: $writer->save('Product-Report.xlsx'); – Ferdi van der Woerd Aug 17 '17 at 15:36
  • If the file doesn't already exist you just need to provide a resource directly to the response method, instead of creating it from the saved file. – Asur Aug 17 '17 at 15:40
  • So that would look something like this? public function download () { if (! empty($pathToTheFile)) { $fileContents = Storage::disk('local')->get($pathToTheFile); $response = Response::make($fileContents, 200); $response->header('Content-Type', Storage::disk('local')- >mimeType($path)); return $response; } else { $fileContents = $writer->save('Product-Report.xlsx'); $response = Response::make($fileContents, 200); $response->header('Content-Type', Storage::disk('local')- >mimeType($path)); return $response; } } – Ferdi van der Woerd Aug 17 '17 at 15:43
  • @FerdivanderWoerd That example would be used if you already have the file saved on your server. – Asur Aug 17 '17 at 15:49
  • $fileContents = $writer->save('Product-Report.xlsx'); Would this then make it so that it downloads the file I just build? – Ferdi van der Woerd Aug 17 '17 at 21:01
  • @FerdivanderWoerd No, I've updated the answer in case you don't have the file saved – Asur Aug 17 '17 at 22:43
  • 1
    I tried your second answer and it appears to do something at least. It gives a response to the axios call but it's just a bunch of random characters: PKñQK'¦P[Content_Types].xmlÍWÝNÂ0½÷)ÞVh\^*úuýƶ¶iËßÛûm $~7kõüì´9iãuUFKp¾0:a"î²tjT¡g {{êXäÔJFCÂ6àÙxt1|ÛXðµOX½çܧ9TÒÇÆÆ/qøêfÜÊt.gÀ{Ýn§FСj6¾ ¾+DS鳬P¯K ¶O#¶ÀZ;aÒÚ²He@ã|©Õ/Õɲ"eÒE¸¡¹¬YøAA6%ø¥¼u ÏBUÆ[Ò½ò2¹(Cô¸FömæJÞ.ÌͶM¡ýã'ø+ÜJ-¡¯3?wìõW²Ðmà©3Ös:ÙÔÉ)PàBñ½ì­Ú©qp¼ø~Ôè?*îÒn¢ñ¼Äcÿâ?ÒG+">®ø¸!â£OÄÇ-">îø]*F¨4ª R©J§ *¥*¨´ª R«J¯ – Ferdi van der Woerd Aug 18 '17 at 08:18
  • @FerdivanderWoerd Don't use axios, try just typing the url on your browser – Asur Aug 18 '17 at 08:19
  • Thanks for all your help. Do you know more about PhpSpreadSheet? In case I run into any more problems. – Ferdi van der Woerd Aug 18 '17 at 09:00
  • @FerdivanderWoerd I actually didn't know the package before you asked about it – Asur Aug 18 '17 at 09:03
  • Okay, because whenever I download my file, that I filled with data I get the same random characters I got as the response before that. But if you don't know I might ask another question. – Ferdi van der Woerd Aug 18 '17 at 09:19
  • @FerdivanderWoerd But the random characters are inside the file? It might be a headers issue, I don't know what exact file format you want. You should change the content type header to fit your needs. – Asur Aug 18 '17 at 09:22
  • 1
    @FerdivanderWoerd the error is on this line header('Content-Disposition: attachment; filename="file.xls"'); add an "x" to end of file.xls to make it header('Content-Disposition: attachment; filename="file.xlsx"') – jdwee Feb 13 '18 at 21:42
  • @Asur This answer helped me to download Excel file, I just changed header lines to: `header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="file.xlsx"');` and it works great! – NekoLopez Jun 13 '18 at 14:56
  • @NekoLopez Yes it looks like `xls` is a legacy extension, I will update my answer thank you very much! – Asur Jun 13 '18 at 15:10