Wie sieht das Zip-Archiv aus und was können wir dagegen tun?

Guten Tag, lieber Habr!

Während des letzten halben Jahres hat mich der krumme Weg meiner Haustierprojekte in eine solche Wildnis geführt, aus der es immer noch unmöglich zu kommen scheint. Und alles begann harmlos - eine Seite mit Bildern, aber ein Gefühl von Perfektionismus, das Streben nach einem Werbegeschenk sowie einige Merkmale meiner Denkweise machten diesen, wie ursprünglich geplant, kleinen Spaziergang zu einer wirklich langen Reise. Nun, okay, wie ein ziemlich burryer Revolutionär sagte: „Lerne, lerne und lerne noch einmal“, aber ich muss dieser Ermahnung wohl oder übel folgen.

Oh, etwas, das uns vom Hauptthema abgelenkt hat. Ich werde Sie nicht mehr mit langen Reden langweilen, aber ich werde zur Sache kommen.

Erstellen Sie ein Zip-Archiv


Im Prinzip werde ich die Spezifikation hier nicht umschreiben. Im Großen und Ganzen macht es auch keinen Sinn, die Struktur zu beschreiben, da dies alles vor mir getan wurde .

Für diejenigen, die zu faul sind, um den Links zu folgen, werde ich kurz skizzieren, dass jedes Zip-Archiv Folgendes enthalten sollte:

  • Dateieintrag:
    • Lokaler Dateikopf
    • Nützliche Daten
    • Datendeskriptor (optional, wird verwendet, wenn wir die Dateigröße und den Hash erst kennen, wenn wir ihn bis zum Ende gelesen haben)
  • Datei-Header des zentralen Verzeichnisses (für jede Datei. Es ist wie ein Inhaltsverzeichnis eines Buches, in dem jeder Abschnitt und jede Seite angegeben ist, auf der es sich befindet.)
  • Ende des zentralen Verzeichnisses

Wenn wir das wissen, können wir versuchen, ein einfaches Archiv zu schreiben, das nur zwei Dateien enthält:

<?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; 

Versuchen Sie, diesen primitiven Code auszuführen, und die Ausgabe gibt Ihnen eine Lorem.zip-Datei, die 1.txt und 2.txt enthält.

Und warum?


Natürlich wird jede adäquate Person sagen, dass das Schreiben von Archivierern in PHP ein vergebliches Unterfangen ist, zumal es für ein Format wie zip eine Reihe von vorgefertigten Implementierungen für jeden Geschmack und jede Farbe gibt. Und im gleichen PHP gibt es fertige Bibliotheken. Ich werde es auch sagen :)

Aber warum ist dieser ganze Artikel dann, warum habe ich Zeit damit verbracht, ihn zu schreiben, und Sie haben ihn gelesen?
Und dann, dass nicht alles so einfach ist und wir wissen, wie Zip funktioniert, eröffnet uns einige zusätzliche Möglichkeiten.

Erstens hoffe ich, zumindest ein wenig, aber es wird denen helfen, die die Struktur von zip verstehen wollen.
Und zweitens haben wir durch die Erstellung des Archivs mit unseren eigenen Händen die Kontrolle und vor allem den Zugriff auf die internen Daten.

Wir können den lokalen Dateikopf und den Dateikopf des zentralen Verzeichnisses vorberechnen und dann bei Bedarf ein Zip-Archiv mit allen Inhalten und der Reihenfolge der Dateien erstellen, indem wir diese Daten einfach ersetzen. Und kein Overhead außer I / O.

Oder wir können das Archiv aufzeichnen, es beispielsweise in die Cloud hochladen, die das fragmentierte Herunterladen unterstützt, und, wenn wir die Offsets für jede der Dateien kennen, eine der Archivdateien abrufen, als ob sie überhaupt nicht im Archiv wären, und nur eine hinzufügen Titel der Anfrage. Und dann kann all dies vertreten werden und ...

Okay, lass uns nicht weiterkommen. Wenn Sie an diesem Thema interessiert sind, werde ich in den folgenden Artikeln versuchen, diese Möglichkeiten zu berücksichtigen und zu zeigen, wie Sie sie nutzen können.


'diskNumber' => 0, // Normalerweise bin ich überall auf 0 gestoßen, und insbesondere habe ich beschlossen, mich nicht damit zu beschäftigen
Wie berez vorgeschlagen hat, die Volume- Nummer im Multi-Volume-Archiv.

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


All Articles