Подтвердить что ты не робот

PHPExcel_Writer_Exception с сообщением "Не удалось закрыть zip файл php://output".

Я использую PHPExcel для экспорта некоторых данных пользователю в файл excel. Я хотел бы, чтобы script отправил файл excel пользователю сразу после его создания. Вот мой тестовый код:

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();
}

На моем локальном сервере (Windows 7 x64, Php 5.3.8, Apache 2.2.21) я получаю действительный файл xlsx. Ошибок нет. Но на реальном сервере (Linux 2.6.32-5-amd64, PHP 5.3.3-7+squeeze13, Apache 2.2.16) есть проблема. script позволяет браузеру загружать файл "export.xlsx" с таким контентом:

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 не работает в безопасном режиме. Опция "open_basedir" пуста (она прокомментирована).

Я нашел такой код в файлах PHPExcel:

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

Таким образом, причина проблемы заключается в том, что $objZip->close() === false где $objZip является экземпляром класса ZipArchive.

В чем причина проблемы и как ее решить? Спасибо.

4b9b3361

Ответ 1

Самая распространенная причина этой ошибки при сохранении в php://output - это ограничение open_basedir, которое не содержит допустимую папку временной системы (например, /tmp), или разрешения для системной папки temp... suhosin также может повлиять на это, даже если очевидные разрешения отображаются правильно.

Возможный рабочий стол - это записать файл в файловую систему в каталоге, который, как вы знаете, имеет полные права на запись, а затем использовать readfile() для потоковой передачи этого файла на php://перед удалением файла

Ответ 2

Спасибо Марку Бейкеру. Его ответ решил проблему. Я написал простой вспомогательный метод, используя его подход.

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

И я только что заменил $objWriter->save('php://output') на SaveViaTempFile($objWriter)

Ответ 3

Привет, я пробовал следующее: на сервере linux Centos 7.0 не указывается маршрут каталога tmp, input:

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

и работайте!

Ответ 4

Для некоторых людей, у которых может быть такое же сообщение ERROR: это может быть просто потому, что имя файла, которое вы пытаетесь сохранить, на самом деле уже открыто в вашем Excel.. Был ли мой случай

Ответ 5

Отличный друг Работай со мной в php 7.1.2 и работай в PhpSpreadsheet, исправь тот же файл.

PhpSpreadsheet/Writer/Excel2007.php

решение в де функции сохранить в Excel2007.php

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

Заменить вторую строку на это:

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

Благодарю.

Ответ 6

У меня была такая же ошибка, когда я пытаюсь запустить мой php файл, просто измените следующую строку:

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

для этого:

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

добавьте путь dir, и он сработает!!!.

Ответ 7

И мой ответ: В имени файла были такие символы, как ":", ",", "" ' Пришлось заменить их на разные. Все работало

Ответ 8

В моем случае я изменяю права доступа к целевой папке на rwxrwxrwx (0777) и теперь работает!

Ответ 9

Эта ошибка также возникает при попытке сохранить файл в несуществующую папку. Убедитесь, что весь путь существует.

Ответ 10

Это вызвано разрешением dir. Попробуйте войти в последнюю папку, затем chmod -R 777 [folder_name]. Он должен работать :)

Ответ 11

В формате Excel2007 работает следующее. Его нужно будет адаптировать для разных форматов.


Открыть этот файл:

\Classes\PHPExcel\Writer\Excel2007.php

Посмотрите на строку 196 для:

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

Замените вторую строку следующим образом:

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

Затем вы можете использовать функцию export, как описано в руководстве разработчика.

Ответ 12

set chmod 777 -R public/results