Phpspreadsheet: Created spreadsheets are corrupted

Created on 7 Sep 2017  路  31Comments  路  Source: PHPOffice/PhpSpreadsheet

This is:

  • [X] a bug report
  • [ ] a feature request
  • [ ] not a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)

What is the expected behavior?

Serves blank spreadsheet to the browser

What is the current behavior?

Serves a corrupted excel file. Excel error message:

We found a problem with some content in test.xlsx. Do you want us to try and recover as much as we can? If you trust the source of this workbook, click Yes.

After Repair I get the following message:

Excel completed file level validation and repair. Some parts of this workbook may have been repaired or discarded.

What are the steps to reproduce?

Run the code below

<?php

require __DIR__ . '/vendor/autoload.php';

// add code that show the issue here...
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();

// Redirect output to a client鈥檚 web browser (Xlsx)
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="test.xlsx"');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');

// If you're serving to IE over SSL, then the following may be needed
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header('Pragma: public'); // HTTP/1.0

$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');

Which versions of PhpSpreadsheet and PHP are affected?

PHP: v7.0.22
Excel: 2016
OS: Windows 10, 64bit
Webserver: Apache httpd-2.4.27-win64-VC14 (via Laragon v3.1.4)

Notes

The same behaviour exists if I load a blank excel file via load()

Most helpful comment

to anyone that having the problem, my team experience this problem, and it was caused by php output before the save(), sometimes it's part of the php framework you're using, and you don't notice in your code for generating the xls.

calling ob_end_clean(); just before the $writer->save() might fixed the corrupted file.
ob_end_clean();
$writer->save('php://output');

All 31 comments

Cannot reproduce. The following code will produce a valid empty file:

$spreadsheet = new Spreadsheet();
$writer = new Xlsx($spreadsheet);
$filename = '/tmp/test.xlsx';
$writer->save($filename);

Most likely you have PHP warnings mixed in your output. Open the xlsx file with a text editor and look for "PHP", "warning", "error" and so on...

@alex6169, probably it's the same issue of #226; try to set a different locale before saving:

setlocale(LC_ALL, 'en_US');

For me the problem was that the framework I am using (and also most frameworks do the same) is adding some additional headers or something.

So the fix was just to terminate the script with die(); or exit(); IF you're outputting the generated file to the browser for download.

If you're just saving the file to the filesystem and that's it, there is no need to terminate the script.

Had the same problem using Laravel, returned $writer
return $writer->save('php://output');

What about when saving it to the filesystem and then download it? I'm getting same error but it only happens on Excel 2016, even if it is an empty spreadsheet. I have opened output file with a text editor and I do not see any PHP warning or error.
This is my current code.

GenerateReport.php

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

[...] // Report generation

// New Spreadsheet 
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->fromArray(
            $datasource,
            NULL,
            'B2'
 );
// New Writer 
$writer = new Xlsx($spreadsheet);

setlocale(LC_ALL, 'en_US');
$writer->save($file);

return $file; // returns file name

DownloadReport.php

$name = basename($file);

header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false);
header('Content-Transfer-Encoding: binary');
header('Content-Disposition: inline; filename="'.$name.'";');
header('Content-Type:  application/octet-stream');
header('Content-Length: ' . filesize($file));

//  Buffering file
$chunkSize = 8 *(1024 * 1024);
$handle = fopen($file, 'rb');
while (!feof($handle))
{
     $buffer = fread($handle, $chunkSize);
     echo $buffer;
     ob_flush();
     flush();
}
fclose($handle);
exit;

Seems I'm facing the same problem right now, someone did find a solution?

Same problem. Any ideas?

to anyone that having the problem, my team experience this problem, and it was caused by php output before the save(), sometimes it's part of the php framework you're using, and you don't notice in your code for generating the xls.

calling ob_end_clean(); just before the $writer->save() might fixed the corrupted file.
ob_end_clean();
$writer->save('php://output');

Thank you kifni41, it was exaclty that !

For Laravel, call exit() right after $writer->save('php://output'); Apparently Laravel outputs other things that cause the corruption:

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

Had the same problem using Laravel, returned $writer
return $writer->save('php://output');

add die() or exit() and php output will work.

to anyone that having the problem, my team experience this problem, and it was caused by php output before the save(), sometimes it's part of the php framework you're using, and you don't notice in your code for generating the xls.

calling ob_end_clean(); just before the $writer->save() might fixed the corrupted file.
ob_end_clean();
$writer->save('php://output');

It's save my day! Thank you!

i guess there are 2 ways of fixing this.
1 - call ob_end_clean() before saving to output
2 - add die() or exit() after saving to output

both ways solved my issue.

Saving to a file is not possible on GAE (Google App Engine), so $writer->save('php://output'); is the only solution.

$writer->save('php://output');  
exit();

works fine.

Had the same problem using Laravel, returned $writer
return $writer->save('php://output');

add die() or exit() and php output will work.

die() or exit interrupts the request lifecycle in Laravel. You better return a StreamedResponse like this:

return response()->stream(function() {
     $spreadsheet = new Spreadsheet();
     $spreadsheet->setActiveSheetIndex(0)->setCellValue('A1', 'Hello');
     $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
     $writer->save('php://output');
}, 200, $header);

Error when:

ob_end_clean() 
$writer->save('php://output');
#
Headers already sent in
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php
on line 415

415:
if (copy($pFilename, $originalFilename) === false) {

I fixed this issue by adding ob_end_clean() before save and exit; after save in IIS.

ob_end_clean();
$writer->save('php://output');
exit;

Thank @amiretemad
ob_end_clean(); have working well for me

Excelente, la funcion ob_end_clean (); antes de save() y ya queda gracias

to anyone that having the problem, my team experience this problem, and it was caused by php output before the save(), sometimes it's part of the php framework you're using, and you don't notice in your code for generating the xls.

calling ob_end_clean(); just before the $writer->save() might fixed the corrupted file.
ob_end_clean();
$writer->save('php://output');

kifni41
Thank You!

Hi,
I am still having the issue even after using the ob_end_clean(); and exit(); as below.
ob_end_clean();
$writer->save('php://output');
exit();

Can somebody help how to resolve the issue.

@pbabugn Are you using a framework? They can output something before PHPSpreadsheet.

Also check for stray spaces and characters in php files before the open

Good luck.

@phpfui
There is no stray spaces or characters before In my excel I am drawing the graphs , then only it is giving this error messages.

Any one please help here

Same issue. There are no content before saving. And corrupted xls as result. But xlsx Writer save uncorrupted file

same issue. the other solutions did not resolve but this worked: $writer->setOffice2003Compatibility(true);

Unfortunately this solution ( $writer->setOffice2003Compatibility(true);) also not working for me.

Hello! Tried all possible ways, nothing worked. Rolled back to version 1.9.0 and the problem disappeared ... Perhaps you can use a more recent version, but you need to check

Hey Peeps, for anyone who experiences a corrupt file (generating xlsx files) when attempting to 'open with' we found that by changing the header content-type from:

header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="some-file.xlsx"');
header('Cache-Control: max-age=0');
$writer->save('php://output'); // download file

to:

header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="some-file.xlsx"');
header('Cache-Control: max-age=0');
$writer->save('php://output'); // download file

worked like a charm - hope this helps =)

this one worked for me.
ob_end_clean();
$writer->save('php://output');
exit();

@alex6169, probably it's the same issue of #226; try to set a different locale before saving:

setlocale(LC_ALL, 'en_US');

where should I add this? before $writer->save(php://output) ?

to anyone that having the problem, my team experience this problem, and it was caused by php output before the save(), sometimes it's part of the php framework you're using, and you don't notice in your code for generating the xls.

calling ob_end_clean(); just before the $writer->save() might fixed the corrupted file.
ob_end_clean();
$writer->save('php://output');

You are safe my day. Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jcroucher picture jcroucher  路  4Comments

PowerKiKi picture PowerKiKi  路  5Comments

Typel picture Typel  路  5Comments

isopen picture isopen  路  3Comments

PowerKiKi picture PowerKiKi  路  5Comments