-1

I've got a simple code as the following (docs) :

// Set the headers to a downloadble content
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); 
header('Content-Disposition: attachment;filename="nomfichier.xlsx"'); 

// Initialize spreadsheet
$objPHPExcel = new PhpOffice\PhpSpreadsheet\Spreadsheet();
$objPHPExcel->setActiveSheetIndex(0);

// Get the sheet and set the value of the first cell
$objPHPExcel->getActiveSheet()->setCellValue('A1', 'ID');

// Create the .xlsx file and download it
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($objPHPExcel, 'Xlsx');
$writer->save('/tmp/temp.csv');

Knowing that this code is in the middle of my PHP page, the downloaded content is the whole text of the HTML page trying to fit into my excel file in the first column and not the simple result I'm looking for : Value named ID in the first cell and first column.

What did I miss? Does this code needs to be contained in it's own file?

Alexandre Elshobokshy
  • 10,720
  • 6
  • 27
  • 57
  • Can you clarify your question? – Justinas Mar 08 '19 at 14:18
  • @Justinas define `clarify`? What is it you don't understand? :-) – Alexandre Elshobokshy Mar 08 '19 at 14:18
  • It doesn't need to be contained in it's own file. You can move it to the top of the file if you want. (don't forget to have an `exit;` after this code then). The reason for it is that the web server (and client) don't know what your intended response should be so it can't "remove" the already outputted HTML for you. Also, any `header()`-call _must_ be before _any_ output at all. Headers are always sent before any content, so if you output any content, you can't set additional headers for that response. – M. Eriksson Mar 08 '19 at 14:24
  • @MagnusEriksson putting the code at the top of the file and exiting right after the save does download an empty excel file - but not with the cell value I specified. Any idea why? – Alexandre Elshobokshy Mar 08 '19 at 14:28
  • That's because you're not sending the file to the client. You're just saving it on your server as `temp.csv` in the `tmp`-folder. If you want to output it instead, use `$writer->save('php://output');` – M. Eriksson Mar 08 '19 at 14:36
  • @MagnusEriksson so it's not necessary to save the file in a tmp folder in order to download a working version of it? Feel free to post your comment as an answer with a bit more explaining and I'll gladly mark it as answer/upvote it. – Alexandre Elshobokshy Mar 08 '19 at 14:43
  • No, it's not necessary. If you use `php://output`, the contents will be sent directly to the client. – M. Eriksson Mar 08 '19 at 14:48
  • @MagnusEriksson and if I want to save it first and then download a working version of it (not the empty excel I get), how to do so? I just noticed that I *need* to save it first. – Alexandre Elshobokshy Mar 08 '19 at 14:52

1 Answers1

2

There are a couple of issues with your code.

Location of the code

Since a file download simply is the server sending a bunch of data to the client, together with some headers that tells the browser how to act on the content, you can't output anything other than the file contents. Doing so will add that to the file content as well (and your downloaded file will most likely be corrupt).

Also, any header()-call in needs to be before any output at all. Headers are sent first, then the content. So if you've already outputted content, you can't send additional headers.

Solutions:
Move your code to it's own file or move it to the top of the current file (before any other output like HTML etc). If it's in the top, don't forget to add an exit; after your code to stop it from parsing and sending the HTML as well.

Outputting the Excel document

Your current code doesn't actually output the document at any point. All it does is saving it on the server, in the /tmp/-folder.

Solutions:
To output the document instead of saving it, change:

$writer->save('/tmp/temp.csv');

to

$writer->save('php://output'); // Send it to the output buffer instead

If you want to save it and send it to the client, you could try (I'm not sure if this works, but it should), then just keep both:

$writer->save('/tmp/temp.csv');
$writer->save('php://output');

If that, for some reason, wouldn't work, you can save it first and then read it back to the client with readfile(). Something like this:

$writer->save('/tmp/temp.csv');
readfile('/tml/temp.csv');
M. Eriksson
  • 13,450
  • 4
  • 29
  • 40