10
votes

Fichiers zip créés de manière dynamique par zipstream dans PHP ne s'ouvrira pas dans OSX

J'ai un site PHP avec de nombreux fichiers multimédia et les utilisateurs doivent pouvoir télécharger plusieurs fichiers à la fois en tant que .zip. J'essaie d'utiliser Zipstream pour servir les fermetures à glissières à la volée avec la compression "Store" Donc, je n'ai pas vraiment à créer un zip sur le serveur, car certains des fichiers sont énormes et il est interdive lent de les compresser tous.

Cela fonctionne bien et les fichiers résultants peuvent être ouverts par chaque programme ZIP que j'ai essayé sans erreur, à l'exception du programme de décompression par défaut d'OS X, Utilitaire d'archive. Vous double-cliquez sur le fichier .zip et l'utilitaire d'archive décide qu'il ne regarde pas un zip réel et compresse plutôt dans un fichier .cgz.

Utiliser Unzip ou Ditto dans le terminal OS X ou StuffIt Expander décompressez le fichier sans problème, mais j'ai besoin du programme par défaut (utilitaire d'archive) pour travailler pour le bien de nos utilisateurs.

Quel genre de choses (drapeaux, etc.) dans des fichiers zip non acceptables peut déclencher l'utilitaire d'archive en pensant qu'un fichier n'est pas un zip valide?

J'ai lu Ceci Question , qui semble décrire un problème similaire, mais je n'ai aucune des bits bitfields à usage général, il n'est donc pas le troisième problème et je suis sûr que je suis valable CRC-32, car quand je n'ai pas 'T, Winrar jette un ajustement.

Je suis heureux de poster du code ou un lien vers un fichier zip "mauvais" si cela vous aiderait, mais je suis presque tout simplement à l'aide de zipstream, de le forcer à "grand mode de fichiers" et à l'aide de "Store" comme Méthode de compression.

Edit - J'ai également essayé l'algorithme de compression "dégonfler" et obtenez les mêmes résultats pour que je ne pense pas que ce soit le "magasin". Il convient également d'être souligné que je tire les fichiers une fois à partir d'un serveur de stockage et que je leur envoie lorsqu'ils arrivent donc une solution qui nécessite que tous les fichiers soient téléchargés avant d'envoyer quelque chose ne sera pas viable (extrême Exemple est 5 Go + de fichiers de 20 Mo. L'utilisateur ne peut pas attendre que tous les 5 Go se transfèrent sur Zipper Server avant que leur téléchargement ne commence ou qu'il pense qu'il est cassé)

Voici un dossier de 140 octets, "Store" compressé, test Zip de test qui présente ce comportement: http: // teknocowboys .com / test.zip


0 commentaires

7 Réponses :


1
votes

aucune idée. Si la classe de zipstring externe ne fonctionne pas, essayez une autre option. Le php zipararchive extension ne vous aidera pas, car il ne supporte pas le streaming, mais Seulement jamais écrit aux fichiers.

Mais vous pouvez essayer l'utilitaire d'information standard-zip. Il peut être invoqué à partir de PHP comme ceci: xxx

qui conduirait directement à un fichier zip non compressé renvoyer directement au client.

si cela ne 't aide, puis la refonte à glissière MacOS n'aime probablement pas les trucs non compressés. Supprimer le drapeau -0 alors.


4 commentaires

Le PassThru est une bonne idée si rien d'autre ne fonctionne. Merci! L'avantage d'utiliser la bibliothèque est que les fichiers sont réellement hébergés sur un serveur séparé et je les retire temporairement avant la "zippation". Utilisation "Zip" nécessite que tous les fichiers soient tirés avant d'envoyer des données, donnant à l'utilisateur une longue ", ce site Web est-il cassé?" Attendez que tout ce qui se passe visiblement, tout en créant le zip moi-même me permet de passer des fichiers à mesure qu'ils entrent, donnant l'apparition de progrès constants.


Ah ok. C'est une difficulté significative alors. Cela nécessiterait une solution de contournement trop élaborée (NFS, SSHFS ou DAVFS) pour rendre ce travail avec l'utilitaire ZIP. Peut-être devriez-vous essayer d'activer la compression de cette classe Zipstream, au moins pour les tests. Peut-être que cela change suffisamment le format ZIP pour faire comprendre OSX.


J'ai effectivement essayé avec l'algorithme "dégonfler" et j'ai les mêmes résultats. (J'aurais probablement dû mentionner que dans la question initiale. Désolé. Je vais le mettre à jour) Je pense que c'est un problème dans les en-têtes zip mais je suppose que je ne sais pas vraiment. Peut-être que je peux créer le même fichier avec "zip" et zipstream et faire un diff binaire pour voir ce que zip fait différemment


Peut-être que vous pourriez poster un zip de test ici (juste une seule lecture non compressée.test), avec un vidage binaire / base64. Peut-être que quelqu'un est enclin à le piquer avec un hexédiciteur.



10
votes

Le problème était dans la "version nécessaire pour extraire" le champ, que j'ai trouvé en effectuant un fichier hexagonal sur un fichier créé par Zipstream vs un fichier créé par Info-Zip et en passant par les différences, essayant de les résoudre. < / p>

Zipstream par défaut le définit à 0x0603. Info-Zip le définit à 0x000a. Les fichiers zip avec la valeur précédente ne semblent pas ouverts dans l'utilitaire d'archive. Peut-être que cela ne prend pas en charge les fonctionnalités de cette version?

forcer la "version nécessaire pour extraire" sur 0x000A a rendu les fichiers générés ouverts également dans les archives utilitaires tels qu'ils font partout ailleurs.

Edit: Une autre cause de ce numéro est si le fichier ZIP a été téléchargé à l'aide de Safari (version de l'agent d'utilisateur> = 537) et que vous avez signalé la taille du fichier lorsque vous avez envoyé votre en-tête de longueur de contenu.

La solution que nous utilisons est de détecter Safari> = 537 côté serveur et si c'est ce que vous utilisez, nous déterminons la différence entre la taille de la longueur du contenu et la taille réelle (comment cela dépend de votre application spécifique) et après avoir appelé $ zipstream-> Terminer (), nous écho chr (0) pour atteindre la bonne longueur. Le fichier résultant est techniquement mal formé et tout commentaire que vous placez dans le zip ne sera pas affiché, mais tous les programmes Zip seront en mesure de l'ouvrir et d'extraire les fichiers.

Ie nécessite le même piratage si vous faites fausse chose à votre contenu, mais au lieu de télécharger un fichier qui ne fonctionne pas, il ne finira pas de télécharger et de lancer un "Téléchargement interrompu".


6 commentaires

Voir aussi cette question similaire: Stackoverflow.com/Questtions/1679986/...


économiseur de vie. J'avais exactement le même problème (utilisait même Zipstream).


Bonjour Zorrodelaarena, je suis très heureux en voyant votre question dans le débordement de la pile. Fondamentalement, j'essaie d'utiliser la bibliothèque de Zipstream pour télécharger et télécharger dynamiquement les grands fichiers d'Amazon S3. Mais pas de succès jusqu'à présent, si cela ne vous dérange pas, pouvez-vous partager votre bloc de code pour ma référence pour gérer ce scénario.


Vraiment lutter pour utiliser la bibliothèque Zipstream avec des fichiers stockés sur S3, je pense que vous utilisez déjà cette bibliothèque pour gérer les fichiers de différents serveurs. Je sens que votre bloc de code m'aidera à gérer ma situation, alors pouvez-vous m'aider. Merci, siva ...


J'ai trouvé 2 correspondances pour 'Version nécessaire pour extraire' dans le fichier zipstream.php, alors lequel vous avez modifié et quelle est la nouvelle valeur que vous définissez pour ce champ?


Avez-vous essayé cela plus récemment? J'ai une application de symfony 2.8 avec zipstream à l'aide de la méthode AddFileTostream, j'ai défini la "version nécessaire pour extraire" sur 0x000A et elle échoue lorsque vous essayez de décompresser avec l'utilitaire d'archive sur OSX El Capitan. Erreur est: Impossible d'agrandir "Test.zip" dans "Téléchargements". (Erreur 2 - Aucun fichier ou répertoire de ce type.)



1
votes

L'outil d'infozip Commandline que j'utilise, à la fois sur Windows et Linux, utilise la version 20 pour la "version" nécessaire pour extraire ". Cela est également nécessaire sur PHP, car la compression par défaut est l'algorithme de déflèvement. Ainsi, la "version nécessaire pour extraire" le champ devrait vraiment être 0x0014. Si vous modifiez le code "(6 << 8) +3" dans la classe Zipstream référencée à Just "20", vous devez obtenir un fichier zip valide à travers les plates-formes.

L'auteur vous dit essentiellement que le fichier ZIP a été créé dans OS / 2 à l'aide du système de fichiers HPFS et la version zip requise par and Infozip 1.0. Pas de nombreuses implémentations savent quoi faire à ce sujet.)


0 commentaires

5
votes

Utilisez ob_clean (); strong> et affleurant (); strong>

Exemple: P>

    $file =  __UPLOAD_PATH . $projectname . '/' . $fileName;

    $zipname = "watherver.zip"
    $zip = new ZipArchive(); 
    $zip_full_path_name = __UPLOAD_PATH . $projectname . '/' . $zipname;
    $zip->open($zip_full_path_name, ZIPARCHIVE::CREATE);
    $zip->addFile($file); // Adding one file for testing
    $zip->close();

    if(file_exists($zip_full_path_name)){
        header('Content-type: application/zip');
        header('Content-Disposition: attachment; filename="'.$zipname.'"');
        ob_clean();
        flush();
        readfile($zip_full_path_name);
        unlink($zip_full_path_name);
    }


0 commentaires

2
votes

J'ai eu ce problème exacte mais avec une cause différente.

Dans mon cas, le PHP généré par ZIP ouvre de la ligne de commande, mais pas via le Finder à OSX. P>

J'avais fait l'erreur d'autoriser un contenu HTML dans le tampon de sortie avant de créer le fichier ZIP et de l'envoyer à la suite de la réponse. P>

<some html></....>
<?php

// Output a zip file...


0 commentaires

1
votes

Pour ceux qui utilisent Zipstream dans Symfony, voici votre solution: https://stackoverflow.com/a/44706446/136151

use Symfony\Component\HttpFoundation\StreamedResponse;
use Aws\S3\S3Client;    
use ZipStream;

//...

/**
 * @Route("/zipstream", name="zipstream")
 */
public function zipStreamAction()
{
    //test file on s3
    $s3keys = array(
      "ziptestfolder/file1.txt"
    );

    $s3Client = $this->get('app.amazon.s3'); //s3client service
    $s3Client->registerStreamWrapper(); //required

    $response = new StreamedResponse(function() use($s3keys, $s3Client) 
    {

        // Define suitable options for ZipStream Archive.
        $opt = array(
                'comment' => 'test zip file.',
                'content_type' => 'application/octet-stream'
              );
        //initialise zipstream with output zip filename and options.
        $zip = new ZipStream\ZipStream('test.zip', $opt);

        //loop keys useful for multiple files
        foreach ($s3keys as $key) {
            // Get the file name in S3 key so we can save it to the zip 
            //file using the same name.
            $fileName = basename($key);

            //concatenate s3path.
            $bucket = 'bucketname';
            $s3path = "s3://" . $bucket . "/" . $key;        

            //addFileFromStream
            if ($streamRead = fopen($s3path, 'r')) {
              $zip->addFileFromStream($fileName, $streamRead);        
            } else {
              die('Could not open stream for reading');
            }
        }

        $zip->finish();

    });

    return $response;
}


0 commentaires

0
votes

C'est une vieille question mais je laisse ce qu'il a fonctionné pour moi juste au cas où cela aide quelqu'un d'autre. Lors du réglage des options, vous devez définir zéro en-tête sur true et activer le zip 64 à FALSE (cela limitera l'archive aux archives à 4 Go):

$options->setZeroHeader(true);
$opt->setEnableZip64(false)


0 commentaires