Pavel L
Pavel L

Reputation: 931

PHPExcel_Writer_Exception with message "Could not close zip file php://output."

I'm using PHPExcel to export some data to user in an excel file. I would like the script to send the excel file to the user immediately after it's creation. Here is my test code:

try{

  /* Some test data */
  $data = array(
    array(1, 10   , 2             ,),
    array(3, 'qqq', 'some string' ,),
  );

  $objPHPExcel = new PHPExcel();
  $objPHPExcel->setActiveSheetIndex(0);

  /* Fill the excel sheet with the data */
  $rowI = 0;
  foreach($data as $row){
    $colI = 0;
    foreach($row as $v){
      $colChar = PHPExcel_Cell::stringFromColumnIndex($colI++);
      $cellId = $colChar.($rowI+1);
      $objPHPExcel->getActiveSheet()->SetCellValue($cellId, $v);
    }
    $rowI++;
  }

  header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  header('Content-Disposition: attachment;filename="export.xlsx"');
  header('Cache-Control: max-age=0');

  $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
  $objWriter->save('php://output');

}catch(Exception $e){
  echo $e->__toString();
}

On my local server (Windows 7 x64, Php 5.3.8, Apache 2.2.21) I get a valid xlsx file. There are no errors. But there is problem on the live server (Linux 2.6.32-5-amd64, PHP 5.3.3-7+squeeze13, Apache 2.2.16). The script lets the browser to download the "export.xlsx" file with such content:

exception 'PHPExcel_Writer_Exception' with message 'Could not close zip file php://output.' in /var/www/someuser/data/www/somedomain.com/libs/PHPExcel/Writer/Excel2007.php:348
Stack trace:
#0 /var/www/someuser/data/www/somedomain.com/classes/Report/Leads/Export.php(339): PHPExcel_Writer_Excel2007->save('php://output')
#1 /var/www/someuser/data/www/somedomain.com/application/pages/account/controllers/TestController.php(13): Report_Leads_Export->Test()
#2 /var/www/someuser/data/www/somedomain.com/libs/Zend/Controller/Action.php(516): Account_TestController->indexAction()
#3 /var/www/someuser/data/www/somedomain.com/libs/Zend/Controller/Dispatcher/Standard.php(295): Zend_Controller_Action->dispatch('indexAction')
#4 /var/www/someuser/data/www/somedomain.com/libs/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#5 /var/www/someuser/data/www/somedomain.com/index.php(511): Zend_Controller_Front->dispatch()
#6 {main}

PHP is NOT running in Safe Mode. The "open_basedir" option is empty (it's commented out).

I have found such code in the PHPExcel files:

if ($objZip->close() === false) {
    throw new PHPExcel_Writer_Exception("Could not close zip file $pFilename.");
}

So the reason of the problem is that $objZip->close() === false where $objZip is an instance of ZipArchive class.

What is the reason of the problem and how can I solve it? Thank you.

Upvotes: 29

Views: 82028

Answers (15)

Luca Pisoni
Luca Pisoni

Reputation: 465

I know, it's so stupid, but i forget "/" in the filename.

Upvotes: 0

FiddlingAway
FiddlingAway

Reputation: 2259

It can also be caused by ownership issues of the directory where your PHPExcel (or its replacement - PhpSpreadsheet) is located.

Example for what can cause this to happen1 - you upload a zip archive containing the PHPExcel / PhpSpreadsheet library, via FTP/SFTP to your website / webapp. Then, you use unzip phpexcelarchive.zip -d ./example.com via the terminal to extract the archive with your files.

Depending on how you were logged in to the console / terminal (root, or some other kind of user with different privileges, belonging to a specific group, etc) when decompressing / unzipping the archive, that particular user will be set as the owner of the files and directories created by unzipping the archive.

This could cause problems later on, as it might limit what you can do with PHPExcel / PhpSpreadsheet - the titular error being one thing that could happen.

The solution would be to unzip the archive programmatically (with a PHP script, and the use of echo exec('unzip phpexcelarchive.zip -d ./example.com')), or via your control panel's (cPanel, Plesk, something else), and its built-in extractor within the File Manager.

This will make your Apache (or the equivalent) user the owner of the unpacked directories and files.


1 You should really have a good reason for installing / setting up PHPExcel / PhpSpreadsheet like this. The preferable way of installing it is via composer.

Upvotes: 0

Mick
Mick

Reputation: 1

In my case I just tried to save file to folder, that wasn't exist. Created folder and problem was solved.

Upvotes: 0

Jax Liu
Jax Liu

Reputation: 11

It's caused by dir permission. Try to enter the final folder, then chmod -R 777 [folder_name]. It should work :)

Upvotes: -2

Joey Quint
Joey Quint

Reputation: 47

This error happens also when trying to save a file into a folder that doesn't exist. Make sure the whole path exists.

Upvotes: 0

In my case, I modify the permissions of the target folder to rwxrwxrwx (0777) and now works!

Upvotes: -1

blackslifer888
blackslifer888

Reputation: 21

Excelent Friend Work for me in php 7.1.2 and work in PhpSpreadsheet, fix the same file.

PhpSpreadsheet/Writer/Excel2007.php

the solution is in de function save in Excel2007.php

if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') {
    $pFilename = @tempnam(PHPExcel_Shared_File::sys_get_temp_dir(), 'phpxltmp');

Replace the second line with this:

$pFilename = dirname(__FILE__).'/'. rand(0, getrandmax()) . rand(0, getrandmax()) . ".phpxltmp";

thanks.

Upvotes: 2

Vasyl Bolshakov
Vasyl Bolshakov

Reputation: 1

set chmod 777 -R public/results

Upvotes: -3

Custam
Custam

Reputation: 75

For some people who may have this same ERROR message : it may very simply be because the filename you're trying to save to is actually already open in your Excel.. Was my case

Upvotes: 2

Zipfel
Zipfel

Reputation: 1

The following works for the Excel2007 format. It would need to be adapted for different formats.


Open this file:

\Classes\PHPExcel\Writer\Excel2007.php

Look near Line 196 for:

if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') {
    $pFilename = @tempnam(PHPExcel_Shared_File::sys_get_temp_dir(), 'phpxltmp');

Replace the second line with this:

    $pFilename = dirname(\__FILE__).'/'. rand(0, getrandmax()) . rand(0, getrandmax()) . ".phpxltmp";

Then you can use the export-function as described in the developer guide.

Upvotes: -1

Pavel L
Pavel L

Reputation: 931

Thanks to Mark Baker. His answer has solved the problem. I have written a simple helper method using his approach.

static function SaveViaTempFile($objWriter){
    $filePath = sys_get_temp_dir() . "/" . rand(0, getrandmax()) . rand(0, getrandmax()) . ".tmp";
    $objWriter->save($filePath);
    readfile($filePath);
    unlink($filePath);
}

And I have just replaced $objWriter->save('php://output') with SaveViaTempFile($objWriter)

Upvotes: 28

Velaro
Velaro

Reputation: 501

And my answer is: Filename had symbols such as ":", ",", '"' Had to replace them to different ones. All worked

Upvotes: 0

Giovanny Canasto
Giovanny Canasto

Reputation: 101

I´ve had the same error when I try run my php file, just change the in next line:

$objWriter->save("/dir1"."/".$file.".xlsx");

for this:

$objWriter->save(dirname(__FILE__)."/dir1"."/".$file.".xlsx");

add the the dir path and it worked!!!.

Upvotes: 1

Hi i tried the following: in a server linux Centos 7.0 do not specified the route of directory tmp, input:

function SaveViaTempFile($objWriter){
    $filePath = '' . rand(0, getrandmax()) . rand(0, getrandmax()) . ".tmp";
    $objWriter->save($filePath);
    readfile($filePath);
    unlink($filePath);
    exit;
}

and work !!

Upvotes: 6

Mark Baker
Mark Baker

Reputation: 212512

The most common cause of this error when saving to php://output is an open_basedir restriction that doesn't include a valid system's temp folder (e.g. /tmp), or permissions for the system's temp folder... suhosin can also affect this, even when the obvious permissions appear to be set correctly.

A possible workround is to write the file to the filesystem in a directory that you know you do have full privileges to write, and then use readfile() to stream that file to php://output before deleting the file

Upvotes: 44

Related Questions