À quoi ressemble l'archive zip et que pouvons-nous faire à ce sujet

Bonjour, cher Habr!

Au cours des six derniers mois, le chemin tortueux de mes projets d'animaux de compagnie m'a conduit dans une telle jungle, d'oĂč il n'est toujours pas possible de sortir. Et tout a commencĂ© sans danger - un site avec des images, mais un sentiment de perfectionnisme, la poursuite d'un cadeau, ainsi que certaines caractĂ©ristiques de mon Ă©tat d'esprit ont transformĂ© cela, comme prĂ©vu Ă  l'origine, en une petite promenade dans un vrai long voyage. Eh bien, d'accord, comme disait un rĂ©volutionnaire plutĂŽt enterrĂ©: «Apprenez, Ă©tudiez et Ă©tudiez Ă  nouveau», mais moi, bon grĂ© mal grĂ©, je dois suivre cet avertissement.

Oh, quelque chose que nous avons été distraits du sujet principal. Je ne vous ennuierai plus avec de longs discours, mais je passerai aux choses sérieuses.

Créer une archive zip


En principe, je ne réécrirai pas la spécification ici. Dans l'ensemble, cela n'a pas de sens non plus de décrire la structure, car tout cela a été fait avant moi .

Pour ceux qui sont trop paresseux pour suivre les liens, je soulignerai briĂšvement que toute archive zip doit contenir:

  • EntrĂ©e de fichier:
    • En-tĂȘte de fichier local
    • DonnĂ©es utiles
    • Descripteur de donnĂ©es (facultatif, utilisĂ© lorsque nous ne connaissons pas la taille du fichier et son hachage jusqu'Ă  ce que nous le lisions Ă  la fin)
  • En-tĂȘte de fichier du rĂ©pertoire central (pour chaque fichier. C'est comme une table des matiĂšres d'un livre, oĂč chaque section et page sur laquelle il peut ĂȘtre trouvĂ© sont indiquĂ©es)
  • Fin du rĂ©pertoire central

Sachant cela, nous pouvons essayer d'Ă©crire une archive simple qui ne contiendra que deux fichiers:

<?php //        (1.txt  2.txt)   : $entries = [ '1.txt' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc id ante ultrices, fermentum nibh eleifend, ullamcorper nunc. Sed dignissim ut odio et imperdiet. Nunc id felis et ligula viverra blandit a sit amet magna. Vestibulum facilisis venenatis enim sed bibendum. Duis maximus felis in suscipit bibendum. Mauris suscipit turpis eleifend nibh commodo imperdiet. Donec tincidunt porta interdum. Aenean interdum condimentum ligula, vitae ornare lorem auctor in. Suspendisse metus ipsum, porttitor et sapien id, fringilla aliquam nibh. Curabitur sem lacus, ultrices quis felis sed, blandit commodo metus. Duis tincidunt vel mauris at accumsan. Integer et ipsum fermentum leo viverra blandit.', '2.txt' => 'Mauris in purus sit amet ante tempor finibus nec sed justo. Integer ac nibh tempus, mollis sem vel, consequat diam. Pellentesque ut condimentum ex. Praesent finibus volutpat gravida. Vivamus eleifend neque sit amet diam scelerisque lacinia. Nunc imperdiet augue in suscipit lacinia. Curabitur orci diam, iaculis non ligula vitae, porta pellentesque est. Duis dolor erat, placerat a lacus eu, scelerisque egestas massa. Aliquam molestie pulvinar faucibus. Quisque consequat, dolor mattis lacinia pretium, eros eros tempor neque, volutpat consectetur elit elit non diam. In faucibus nulla justo, non dignissim erat maximus consectetur. Sed porttitor turpis nisl, elementum aliquam dui tincidunt nec. Nunc eu enim at nibh molestie porta ut ac erat. Sed tortor sem, mollis eget sodales vel, faucibus in dolor.', ]; //      Lorem.zip,      cwd (      ) $destination = 'Lorem.zip'; $handle = fopen($destination, 'w'); //      ,    ,     ,   "" Central Directory File Header $written = 0; $dictionary = []; foreach ($entries as $filename => $content) { //         Local File Header,     //        ,      . $fileInfo = [ //     'versionToExtract' => 10, //   0,        - 'generalPurposeBitFlag' => 0, //      ,    0 'compressionMethod' => 0, // -    mtime ,    ,      ? 'modificationTime' => 28021, //   , ? 'modificationDate' => 20072, //      .     ,       ,   ? 'crc32' => hexdec(hash('crc32b', $content)), //     .        . //       :) 'compressedSize' => $size = strlen($content), 'uncompressedSize' => $size, //    'filenameLength' => strlen($filename), //  .    ,   0. 'extraFieldLength' => 0, ]; //      . $LFH = pack('LSSSSSLLLSSa*', ...array_values([ 'signature' => 0x04034b50, //  Local File Header ] + $fileInfo + ['filename' => $filename])); //       ,       Central Directory File Header $dictionary[$filename] = [ 'signature' => 0x02014b50, //  Central Directory File Header 'versionMadeBy' => 798, //  .    ,  -  . ] + $fileInfo + [ 'fileCommentLength' => 0, //    . No comments 'diskNumber' => 0, //     0,        'internalFileAttributes' => 0, //    'externalFileAttributes' => 2176057344, //    'localFileHeaderOffset' => $written, //      Local File Header 'filename' => $filename, //  . ]; //      $written += fwrite($handle, $LFH); //    $written += fwrite($handle, $content); } // ,     ,    . //          End of central directory record (EOCD) $EOCD = [ //  EOCD 'signature' => 0x06054b50, //  .    ,   0 'diskNumber' => 0, //      -  0 'startDiskNumber' => 0, //       . 'numberCentralDirectoryRecord' => $records = count($dictionary), //    .    ,     'totalCentralDirectoryRecord' => $records, //   Central Directory Record. //      ,      'sizeOfCentralDirectory' => 0, // ,    Central Directory Records 'centralDirectoryOffset' => $written, //     'commentLength' => 0 ]; //     !   foreach ($dictionary as $entryInfo) { $CDFH = pack('LSSSSSSLLLSSSSSLLa*', ...array_values($entryInfo)); $written += fwrite($handle, $CDFH); } // ,   .  ,    $EOCD['sizeOfCentralDirectory'] = $written - $EOCD['centralDirectoryOffset']; //     End of central directory record $EOCD = pack('LSSSSLLS', ...array_values($EOCD)); $written += fwrite($handle, $EOCD); //  . fclose($handle); echo '  : ' . $written . ' ' . PHP_EOL; echo '     `unzip -tq ' . $destination . '`' . PHP_EOL; echo PHP_EOL; 

Essayez d'exécuter ce code primitif et la sortie vous donnera un fichier Lorem.zip qui contiendra 1.txt et 2.txt.

Pourquoi?


Bien sĂ»r, toute personne adĂ©quate dira qu'Ă©crire des archiveurs en php est une entreprise futile, d'autant plus que pour un format tel que zip, il existe un tas d'implĂ©mentations prĂȘtes Ă  l'emploi pour tous les goĂ»ts et toutes les couleurs. Et dans le mĂȘme php, il y a des bibliothĂšques prĂȘtes Ă  l'emploi. Je le dirai aussi :)

Mais pourquoi donc tout cet article, pourquoi ai-je passé du temps à l'écrire et vous à le lire?
Et puis, que tout n'est pas si simple et savoir comment fonctionne zip, nous ouvre des possibilités supplémentaires.

Tout d'abord, j'espĂšre, au moins un peu, mais cela aidera ceux qui veulent comprendre la structure du zip.
Et deuxiÚmement, en créant l'archive de nos propres mains, nous avons le contrÎle et, surtout, l'accÚs à ses données internes.

Nous pouvons prĂ©-calculer l'en-tĂȘte de fichier local et l'en-tĂȘte de fichier du rĂ©pertoire central, puis gĂ©nĂ©rer Ă  la demande une archive zip Ă  la volĂ©e avec n'importe quel contenu et ordre de fichiers, en remplaçant simplement ces donnĂ©es. Et pas de frais gĂ©nĂ©raux, sauf pour les E / S.

Ou, nous pouvons enregistrer l'archive, la tĂ©lĂ©charger, par exemple, dans le cloud, qui prend en charge le tĂ©lĂ©chargement fragmentĂ© et, connaissant les dĂ©calages pour chaque fichier, obtenir l'un des fichiers d'archive, comme s'il n'Ă©tait pas du tout dans l'archive, en ajoutant un seul titre de la demande. Et puis tout cela peut ĂȘtre mandatĂ© et ...

D'accord, ne prenons pas de l'avance sur nous-mĂȘmes. Si vous ĂȘtes intĂ©ressĂ© par ce sujet, alors dans les articles suivants, j'essaierai de considĂ©rer ces opportunitĂ©s et de montrer comment les utiliser.


'diskNumber' => 0, // J'ai généralement rencontré 0 partout, et en particulier j'ai décidé de ne pas me plonger dans
Comme l'a suggéré Berez , le numéro de volume dans l'archive multi-volumes.

Source: https://habr.com/ru/post/fr471066/


All Articles