Reputation: 931
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
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
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
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
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
Reputation: 298
In my case, I modify the permissions of the target folder to rwxrwxrwx (0777) and now works!
Upvotes: -1
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
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
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
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
Reputation: 501
And my answer is: Filename had symbols such as ":", ",", '"' Had to replace them to different ones. All worked
Upvotes: 0
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
Reputation: 69
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
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