Seperti apa bentuk arsip zip dan apa yang bisa kita lakukan

Selamat siang, Habr!

Selama setengah tahun terakhir, jalan bengkok dari proyek hewan peliharaan saya telah membawa saya ke hutan seperti itu, dari tempat itu masih tidak mungkin untuk keluar. Dan itu semua dimulai tanpa membahayakan - sebuah situs dengan gambar, tetapi rasa perfeksionisme, pengejaran freebie, serta beberapa fitur dari pola pikir saya mengubah ini, seperti yang awalnya direncanakan, sedikit berjalan ke perjalanan yang sangat panjang. Baiklah, seperti yang biasa dikatakan oleh seorang revolusioner burry: โ€œBelajar, belajar dan belajar lagiโ€, tetapi saya, mau tak mau, harus mengikuti nasihat ini.

Oh, sesuatu yang mengalihkan perhatian kita dari topik utama. Saya tidak akan membuat Anda bosan dengan pidato yang panjang, tetapi saya akan membahas urusan.

Buat arsip zip


Pada prinsipnya, saya tidak akan menulis ulang spesifikasi di sini. Secara keseluruhan, tidak masuk akal untuk menggambarkan struktur juga, karena semua ini dilakukan sebelum saya .

Bagi mereka yang terlalu malas untuk mengikuti tautan, saya hanya akan menjelaskan secara singkat bahwa arsip zip mana pun harus berisi:

  • Entri file:
    • Header file lokal
    • Data yang berguna
    • Deskriptor data (opsional, digunakan ketika kita tidak tahu ukuran file dan hashnya sampai kita membacanya sampai akhir)
  • Header File Direktori Tengah (untuk setiap file. Ini seperti daftar isi buku, di mana setiap bagian dan halaman yang dapat ditemukan ditunjukkan)
  • Akhir dari direktori pusat

Mengetahui hal ini, kita dapat mencoba menulis arsip sederhana yang hanya akan berisi dua file:

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

Cobalah untuk menjalankan kode primitif ini dan hasilnya akan memberi Anda file Lorem.zip yang akan berisi 1.txt dan 2.txt.

Mengapa


Tentu saja, setiap orang yang memadai akan mengatakan bahwa menulis arsip di php adalah pekerjaan yang sia-sia, terutama karena untuk format seperti zip, ada banyak implementasi yang siap pakai untuk setiap selera dan warna. Dan di php yang sama ada perpustakaan yang sudah jadi. Saya akan mengatakannya juga :)

Tetapi mengapa, mengapa, seluruh artikel ini, mengapa saya menghabiskan waktu menulisnya, dan Anda membacanya?
Dan kemudian, bahwa semuanya tidak begitu sederhana dan mengetahui cara kerja zip, membuka beberapa kemungkinan tambahan bagi kita.

Pertama, saya harap, setidaknya sedikit, tetapi ini akan membantu mereka yang ingin memahami struktur zip.
Dan kedua, membuat arsip dengan tangan kita sendiri, kita memiliki kontrol, dan, yang paling penting, akses ke data internalnya.

Kami dapat melakukan pra-penghitungan Header File Lokal dan Header Direktori Direktori Utama, dan kemudian atas permintaan membuat arsip zip dengan cepat dengan konten dan urutan file apa pun, cukup mengganti data ini. Dan tidak ada overhead kecuali untuk I / O.

Atau, kita dapat merekam arsip, mengunggahnya, misalnya, ke cloud, yang mendukung pengunduhan terfragmentasi dan, mengetahui offset untuk setiap file, mendapatkan file arsip apa saja, seolah-olah itu tidak ada dalam arsip sama sekali, menambahkan hanya satu judul permintaan. Dan kemudian semua ini dapat diproksi dan ...

Oke, jangan maju dulu. Jika Anda tertarik dengan topik ini, maka dalam artikel berikut ini saya akan mencoba mempertimbangkan peluang ini dan menunjukkan cara menggunakannya.


'diskNumber' => 0, // Saya biasanya menemukan 0 di mana-mana, dan khususnya saya memutuskan untuk tidak menyelidiki
Seperti yang disarankan, jumlah volume dalam arsip multi-volume.

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


All Articles