26 votes

PHP ZipArchive corrompu sous Windows

J'utilise la classe ZipArchive de PHP pour créer un fichier zip contenant des photos et l'envoyer au navigateur pour téléchargement. Voici mon code :

/**
 * Grabs the order, packages the files, and serves them up for download.
 *
 * @param string $intEntryID 
 * @return void
 * @author Jesse Bunch
 */
public static function download_order_by_entry_id($intUniqueID) {

    $objCustomer = PhotoCustomer::get_customer_by_unique_id($intUniqueID);

    if ($objCustomer):

        if (!class_exists('ZipArchive')):
            trigger_error('ZipArchive Class does not exist', E_USER_ERROR);
        endif;

        $objZip = new ZipArchive();
        $strZipFilename = sprintf('%s/application/tmp/%s-%s.zip', $_SERVER['DOCUMENT_ROOT'], $objCustomer->getEntryID(), time());

        if ($objZip->open($strZipFilename, ZIPARCHIVE::CREATE) !== TRUE):

            trigger_error('Unable to create zip archive', E_USER_ERROR);

        endif;          

        foreach($objCustomer->arrPhotosRequested as $objPhoto):

            $filename = PhotoCart::replace_ee_file_dir_in_string($objPhoto->strHighRes);
            $objZip->addFile($filename,sprintf('/press_photos/%s-%s', $objPhoto->getEntryID(), basename($filename)));

        endforeach;

        $objZip->close();

        header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($strZipFilename)).' GMT',  TRUE, 200);
        header('Cache-Control: no-cache', TRUE);
        header('Pragma: Public', TRUE);
        header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT', TRUE);
        header('Content-Length: '.filesize($strZipFilename), TRUE);
        header('Content-disposition: attachment; filename=press_photos.zip', TRUE);

        header('Content-Type: application/octet-stream', TRUE);

        ob_start();
        readfile($strZipFilename);
        ob_end_flush();
        exit;

    else:

        trigger_error('Invalid Customer', E_USER_ERROR);

    endif;

}

Ce code fonctionne très bien avec tous les navigateurs sauf IE. Dans IE, le fichier se télécharge correctement, mais l'archive zip est vide. Lorsque j'essaie d'extraire les fichiers, Windows me dit que l'archive zip est corrompue. Quelqu'un a-t-il déjà rencontré ce problème ?

Modifier Mise à jour : Après une suggestion de @profitphp, j'ai changé mes en-têtes en ceci :

header("Cache-Control: public");
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
//header("Content-Description: File Transfer");
//header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"pressphotos.zip\"");
//header("Content-Transfer-Encoding: binary");
header("Content-length: " . filesize($strZipFilename));

Voici également une capture d'écran de l'erreur dans Windows après ouverture avec Firefox :

alt text

Cette erreur se produit à la fois dans IE et Firefox sous Windows. Elle fonctionne bien sur Mac. De plus, sous Windows, la taille des fichiers semble correcte :

alt text

Edit #2 Ce problème est résolu. Voir ma réponse ci-dessous.

31voto

CWSpear Points 1825

J'ai eu ce même problème, et ma solution était similaire à la bonne réponse de ce fil de discussion. Lorsque vous placez un fichier dans l'archive, vous ne pouvez pas avoir de fichiers absolus (fichiers commençant par un slash), sinon il ne s'ouvrira pas dans Windows pour une raison quelconque.

Il a donc réussi à le faire fonctionner non pas parce qu'il (Jesse Bunch, la réponse choisie au moment de la rédaction de cet article) a supprimé le dossier contenant le fichier, mais parce qu'il a supprimé la barre oblique de départ.

J'ai résolu le problème en changeant

$zip->addFile($file, $file); // $file is something like /path/to/file.png

à

// we make file relative by removing beginning slash so it will open in Windows
$zip->addFile($file, ltrim($file, '/'));

et ensuite il a pu s'ouvrir dans Windows !

C'est probablement la même raison pour laquelle pclzip (réponse de Plahcinski) fonctionne. Je parie qu'il supprime automatiquement la barre oblique du début.

Je n'aurais pas compris ça sans une commentaire particulier sur le site de PHP ZipArchive::addFile page de documentation.

14voto

Plahcinski Points 159

J'ai récemment eu un problème similaire à celui que vous avez décrit. J'ai trouvé ZipArchive instable, au mieux.

J'ai résolu mes problèmes avec cette simple bibliothèque

http://www.phpconcept.net/pclzip

include_once('libs/pclzip.lib.php');

...

function zip($source, $destination){
$zipfile = new PclZip($destination);
$v_list = $zipfile->create($source, '', $source); }

$source = dossier que je veux compresser $destination = emplacement du fichier zip

J'ai passé 2 jours à chercher ZipArchive et j'ai ensuite résolu tous les problèmes avec PCLZip en 5 minutes.

J'espère que cela vous aidera, ainsi que tous ceux qui rencontrent ce problème (car il s'agit du premier résultat de Google sur ce sujet).

14voto

Luca Camillo Points 622

Toutes ces suggestions peuvent vous aider, mais dans mon cas, j'ai besoin d'écrire un ob_clean() ; avant le premier header('') ; parce que certains fichiers que j'ai inclus avant d'imprimer certains caractères qui ont cassé le fichier zip sur Windows.

$zip=new ZipArchive();
$zip->open($filename, ZIPARCHIVE::CREATE);
$zip->addFile($file_to_attach,$real_file_name_to_attach);
$zip->close();

ob_clean();
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Content-Type: application/x-download');
header('Content-Disposition: attachment; filename="file.zip"');
readfile($filename);
exit;

6voto

Jesse Bunch Points 4251

Ok, après beaucoup d'efforts, j'ai trouvé le problème. Le problème vient de la ligne de code suivante :

$objZip->addFile($filename,sprintf('/press_photos/%s-%s', $objPhoto->getEntryID(), basename($filename)));

Pour une raison quelconque, le /press_photos/ de ce chemin pour le nom de fichier local (interne) à l'intérieur de l'archive zip faisait croire à Windows que le fichier zip était corrompu. Après avoir modifié la ligne pour qu'elle ressemble à ce qui est indiqué ci-dessous, Windows a ouvert les fichiers zip correctement. Ouf.

$objZip->addFile($filename,sprintf('%s-%s', $objPhoto->getEntryID(), basename($filename)));

5voto

David Spector Points 51

L'utilisation de caractères spéciaux, tels que l'underscore, pose des problèmes car ZipArchive requiert des noms d'entrée encodés en IBM850. Voir les commentaires dans le manuel PHP en ligne : http://www.php.net/manual/en/function.ziparchive-addfile.php#95725 .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X