This is driving me crazy. I'm using a PHP function to download an Excel file. This works fine in my local environment and testing server, but on the production server, instead of downloading the spreadsheet, it prints a lot of garbled text to the browser window. It looks like the "PK" code for a zip file. The result is inconsistent. I reduce the number of columns and it works. Then I added one more column and it breaks. Then the next day it works. Then I add another column and it breaks. The same function works in other areas of the app, it's just when I try to export this one file.
This is a Symfony 4.4 app running on PHP 8.1. All environments should be identical.
$filePath = $path . $fileName;
$response = new Response();
$response->headers->set('Content-Type', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
$response->headers->set('Content-Disposition', "attachment;filename={$fileName}");
$response->headers->set('Cache-Control', "no-cache");
$response->headers->set('Expires', "0");
$response->headers->set('Content-Transfer-Encoding', "binary");
$response->headers->set('Content-Length', filesize($filePath));
$request = Request::createFromGlobals();
$response->prepare($request);
$response->setContent(readfile($filePath));
$response->sendContent();
unlink($filePath);
return $response;
CodePudding user response:
Right off the bat, readfile()
does not return the contents of the file, but rather outputs it directly so:
$response->setContent(readfile($filePath));
is definitely wrong.
Instead use file_get_contents
:
$response->setContent(file_get_contents($filePath));
I would refactor the code to read the file contents and set the Content-Length
according to how many bytes $fileContents
is:
$fileContents = file_get_contents($filePath);
$response->headers->set('Content-Length', strlen($fileContents));
$request = Request::createFromGlobals();
$response->prepare($request);
$response->setContent($fileContents);
(strlen() always returns the number of bytes in a string, not characters).
CodePudding user response:
I got it. Instead of trying to set all those headers manually I just used the ResponseHeaderBag. Works now.
return $this->file("export/".$fileName, $fileName, ResponseHeaderBag::DISPOSITION_INLINE);