web-dev-qa-db-fra.com

PHPExcel_Writer_Exception avec le message "Impossible de fermer le fichier Zip php: // output."

J'utilise PHPExcel pour exporter des données vers un utilisateur dans un fichier Excel. J'aimerais que le script envoie le fichier Excel à l'utilisateur immédiatement après sa création. Voici mon code de test:

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

Sur mon serveur local (Windows 7 x64, Php 5.3.8, Apache 2.2.21), je reçois un fichier xlsx valide. Il n'y a pas d'erreur. Mais il y a un problème sur le serveur live (Linux 2.6.32-5-AMD64, PHP 5.3.3-7+squeeze13, Apache 2.2.16). Le script permet au navigateur de télécharger le fichier "export.xlsx" avec ce contenu:

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 ne fonctionne pas en mode sans échec. L'option "open_basedir" est vide (elle est commentée).

J'ai trouvé ce code dans les fichiers PHPExcel:

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

La raison du problème est donc que $objZip->close() === false$objZip est une instance de la classe ZipArchive.

Quelle est la raison du problème et comment puis-je le résoudre? Je vous remercie.

26
Pavel L

La cause la plus fréquente de cette erreur lors de l’enregistrement dans php: // output est une restriction open_basedir qui n’inclut pas un dossier temporaire du système valide (par exemple, /tmp), ni les autorisations pour le dossier temporaire du système ... suhosin peut également affecter cela. même lorsque les autorisations évidentes semblent être définies correctement.

Une solution de contournement possible consiste à écrire le fichier sur le système de fichiers dans un répertoire dans lequel vous savez que vous disposez de tous les privilèges, puis utilisez readfile () pour diffuser ce fichier en php: // en sortie avant de supprimer le fichier.

38
Mark Baker

Merci à Mark Baker. Sa réponse a résolu le problème. J'ai écrit une méthode d'assistance simple en utilisant son approche.

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

Et je viens de remplacer $objWriter->save('php://output') par SaveViaTempFile($objWriter)

23
Pavel L

Bonjour, j'ai essayé ce qui suit: Sur un serveur linux Centos 7.0 ne spécifie pas la route du répertoire tmp, entrée:

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

et le travail !!

Excelent Friend Travaillez pour moi dans php 7.1.2 et dans PhpSpreadsheet, corrigez le même fichier.

PhpSpreadsheet/Writer/Excel2007.php

la solution est en fonction enregistrer dans Excel2007.php

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

Remplacez la deuxième ligne par ceci:

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

merci.

2
blackslifer888

J'ai eu la même erreur quand j'essaye de lancer mon fichier php, changez juste la ligne suivante

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

pour ça:

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

ajoutez le chemin dir et cela a fonctionné !!!.

1
Giovanny Canasto

Pour certaines personnes qui peuvent avoir le même message d'erreur: c'est peut-être tout simplement parce que le nom du fichier que vous essayez de sauvegarder est en fait déjà ouvert dans votre Excel ...

1
Custam

Dans mon cas, je modifie les autorisations du dossier cible sur rwxrwxrwx (0777) et fonctionne maintenant!

0

Et ma réponse est la suivante:

0
Velaro