In diesem Artikel beschreibe ich wie man auch ohne PHP Erweiterungen ZIP-Archive unter Unix auf dem Server in Echtzeit erstellen kann.
Anatomie eines Archivs
Ein ZIP-Archiv besteht aus zwei großen Teilen: Die gepackten Dateien als Datenstrom und eine Dateitabelle mit Typinformationen.
Im Datenstrom findet man folgende Informationen über die Datei:
- CRC32 der Originaldatei,
- Länge des komprimierten Dateiinhaltes,
- Länge der Originaldatei,
- Länge von Dateipfad und –name,
- (binäres Trennzeichen),
- Dateipfad und –name,
- komprimierter Dateiinhalt,
- Danach erneut CRC32 der Originaldatei, Länge des komprimierten Dateiinhaltes, Länge der Originaldatei
In der Allokationstabelle findet man folgende Informationen über die Datei:
- CRC32 der Originaldatei,
- Länge des komprimierten Dateiinhaltes,
- Länge der Originaldatei,
- Länge von Dateipfad und –name,
- (mysteriöse binäre Trennzeichen),
- Position des zugehörigen Datenstroms innerhalb des Archivs,
- Dateipfad und –name.
Am Ende des Archivs werden noch statische Daten geschrieben: Anzahl der Dateien im Archiv, Länge von Datenblock und Allokationstabelle.
Die binären Trennzeichen im Datenblock und in der Allokationstabelle werden in der Regel durch 16 Bit Null-Blöcke dargestellt (also in hex so: 0×0000).
Komprimierungsverfahren
Einen komplexen Komprimierungsalgorithmus müssen Sie nicht neu implementieren dafür stellt PHP seit Version 4 die Funktion GzCompress() zur Verfügung.
Wie sieht das in PHP aus?
Um das Format darzustellen habe ich hier schon mal eine Klasse für PHP5 vorbereitet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | Class ziparchive { var $arrStream = Array(); var $fat = Null; var $data = Null; function addFile($filename, &$stream){ $this->arrStream[] = Array ( $filename, &$stream ); } Function Pack(){ ForEach ($this->arrStream AS $index => &$file){ $filename = &$file[0]; $stream = &$file[1]; $compressedData = SubStr (GZCompress(&$stream, 9), 2, -4); $NUL = Pack("v", 0 ); // File allocation table: $this->fat .= "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00". Pack("V", CRC32(&$stream)). Pack("V", StrLen (&$compressedData)). Pack("V", StrLen(&$stream)). Pack("v", StrLen(&$filename)). $NUL. $NUL. $NUL. $NUL. Pack("V", 32 ). Pack("V", StrLen(&$this->data)). $filename; // Compressed Data: $this->data .= "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00". Pack("V", CRC32(&$stream)). Pack("V", StrLen (&$compressedData)). Pack("V", StrLen(&$stream)). Pack("v", StrLen(&$filename)). $NUL. $filename. $compressedData. Pack("V", CRC32(&$stream)). Pack("V", StrLen (&$compressedData)). Pack("V", StrLen(&$stream)); // Free The Memory!!! $this->arrStream[$index] = Null; #Echo "Need memory: ".(memory_get_usage(TRUE) / 1024 / 1024)." M\r\n"; } // Free The Memory!!! Unset ($compressedData); // Build the binary file: return $this->data. $this->fat. "\x50\x4b\x05\x06\x00\x00\x00\x00". Pack("v", Count(&$this->arrStream)). Pack("v", Count(&$this->arrStream)). Pack("V", StrLen(&$this->fat)). Pack("V", StrLen(&$this->data)). "\x00\x00"; } } |
Dokumentation
Die Klasse ist voll funktionsfähig und kann z.B. so benutzt werden:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Zip Klasse inkludieren Include "class_zip.php"; // Neues zip-Archiv erstellen $zip = New ziparchive; // Dateien hinzufügen $zip->addFile ( 'class_zip.php', File_Get_Contents ('files/quellcode.php') ); $zip->addFile ( 'sounds/klang.mp3', File_Get_Contents ('files/klang.mp3') ); $zip->addFile ( 'pictures/bild.bmp', File_Get_Contents ('files/bild.bmp') ); // Neues zip-Archiv in Datei schreiben File_Put_Contents ( "test.zip", $zip->Pack() ); |

