template

Index :: PHP/MySQL :: Module :: ZIP/GZIP-Komprimierung (cZip.php)

Dieses Modul kapselt die Komprimierung von Verzeichnissen und Dateien.

Auf dem Server muss die ZLib-Bibliothek installiert sein, weil die Funktion gzcompress() verwendet wird.


Interface

Methoden
Add_Dir() Verzeichnis erzeugen.
Parameter:
  • $name (String) Verzeichnisname, z.B. 'css/' oder 'public/Docs/'.
Add_File() Datei aufnehmen.
Parameter:
  • $data (String) Inhalt, alphanumerisch oder binär.
  • $name (String) Dateiname, z.B. 'readme.txt' oder 'public/Docs/manual.txt'.
    Bei Pfadangabe muss das entsprechende Verzeichnis bereits mittels Add_Dir() angelegt worden sein.
File() Liefert die komprimierte Archivdatei.

Verwendung

Im Beispiel wird eine ZIP-Datei namens MeinArchiv.zip erzeugt, die Ordner, Unterordner und Textdateien enthält.
Die in die Archivstruktur eingesetzen Objekte sind jeweils blau gekennzeichnet:
<?php
require('cZip.php'); // Modul einbinden

$zip=new cZip; // Objekt erzeugen

// Textdatei readme.txt schreiben
$zip->Add_File('Inhalt der Datei readme','readme.txt');

$zip->Add_Dir('Basedir/'); // Ordner Basedir anlegen
// Textdatei basetext.txt schreiben
$zip->Add_File('Inhalt der Datei basetext','Basedir/basetext.txt');

$zip->Add_Dir('Basedir/Subdir/'); // Ordner Basedir/Subdir anlegen
// Textdatei subtext.txt schreiben
$zip->Add_File('Inhalt der Datei subtext','Basedir/Subdir/subtext.txt');

$fhout=fopen('MeinArchiv.zip','w'); // Archivdatei anlegen
fputs($fhout,$zip->File());         // ZIP-Daten schreiben
fclose($fhout);                     // Archivdatei schliessen
?>
Meist wird die Komprimierung beim Download (siehe: Downloadstream erzeugen) von Exportdaten eingesetzt. Hierzu würde man dann die Liste bzw. Tabelle (evtl. im CSV-Format) in einer Stringvariablen wie $data zusammenstellen, mit $zip->Add_File($data,'Exportliste.txt') ins Archiv aufnehmen und schließlich $zip->File() zum Client streamen.

Modul-Quellcode :: Mit Kommentaren

<?php // ZIP Dateiformat: http://www.pkware.com/appnote.txt
class cZip {
  var $datasec=array(); // Array zur Speicherung der komprimierten Daten
  var $ctrl_dir=array(); // Zentrales Verzeichnis
  var $eof_ctrl_dir="\x50\x4b\x05\x06\x00\x00\x00\x00"; // Ende des zentralen Verzeichnisses
  var $old_offset=0;
  function Add_Dir($name) {
  // Verzeichnis anlegen - BEVOR irgendwelche Dateien mit Pfaden angegeben werden!
  // $name: Name des Verzeichnisses, z.B. 'abc/'
  // (dann sind bei add_file() auch Dateien mit Pfaden moeglich, z.B. 'abc/file.txt')
    $name=str_replace("\\","/",$name);  
    $fr="\x50\x4b\x03\x04";
    $fr.="\x0a\x00"; // Version, wird zur Extraktion benoetigt
    $fr.="\x00\x00"; // Flag: gen purpose bit
    $fr.="\x00\x00"; // Kompressionsmethode
    $fr.="\x00\x00\x00\x00"; // Datum/Zeit der letzte Aenderung
    $fr.=pack('V',0); // crc32
    $fr.=pack('V',0); // Dateigroesse: komprimiert
    $fr.=pack('V',0); // Dateigroesse: unkomprimiert
    $fr.=pack('v',strlen($name)); // Laenge des Pfadnamens
    $fr.=pack('v',0); // Laenge: Extrafeld
    $fr.=$name;
    // Ende des 'local file header' Segments
    // Kein 'file data' Segment fuer den Pfad
    // 'data descriptor' Segment (optional, aber noetig, falls Archiv nicht als Datei geliefert wird)
    $fr.=pack('V',$crc); // crc32
    $fr.=pack('V',$c_len); // Dateigroesse: komprimiert
    $fr.=pack('V',$unc_len); // Dateigroesse: unkomprimiert
    // Eintrag ins Array
    $this->datasec[]=$fr;
    $new_offset=strlen(implode('',$this->datasec));
    // 'ext. file attributes' entspricht MS-DOS directory attr byte 
    // (Details unter http://support.microsoft.com/support/kb/articles/Q125/0/19.asp)
    // dem zentralen Verzeichnis hinzufuegen
    $cdrec="\x50\x4b\x01\x02";
    $cdrec.="\x00\x00"; // Version, made by
    $cdrec.="\x0a\x00"; // Version, wird zur Extraktion benoetigt
    $cdrec.="\x00\x00"; // Flag: gen purpose bit
    $cdrec.="\x00\x00"; // Kompressionsmethode
    $cdrec.="\x00\x00\x00\x00"; // Datum/Zeit der letzte Aenderung
    $cdrec.=pack('V',0); // crc32
    $cdrec.=pack('V',0); // Dateigroesse: komprimiert
    $cdrec.=pack('V',0); // Dateigroesse: unkomprimiert
    $cdrec.=pack('v',strlen($name)); // Laenge des Dateinamens
    $cdrec.=pack('v',0); // Laenge: Extrafeld
    $cdrec.=pack('v',0); // Laenge: Dateikommentar
    $cdrec.=pack('v',0); // Start Disk Nummer
    $cdrec.=pack('v',0); // Interne Dateiattribute
    $cdrec.=pack('V',16); // Externe Dateiattribute - 'directory' Bit gesetzt
    $cdrec.=pack('V',$this->old_offset); // Relativer Offset des lokalen Headers
    $this->old_offset=$new_offset;
    $cdrec.=$name;
    // Optionales Extrafeld fuer Dateikommentar
    // Eintrag ins zentrale Verzeichnis
    $this->ctrl_dir[]=$cdrec;  
  }
  function Add_File($data,$name) {
  // Fuegt dem Archiv eine Datei hinzu
  // $data: Inhalt der Datei
  // $name: Name der Datei im Archiv. Evtl. mit Pfad
    $name=str_replace("\\","/",$name);  
    $fr="\x50\x4b\x03\x04";
    $fr.="\x14\x00"; // Version, wird zur Extraktion benoetigt
    $fr.="\x00\x00"; // Flag: gen purpose bit
    $fr.="\x08\x00"; // Kompressionsmethode
    $fr.="\x00\x00\x00\x00"; // Datum/Zeit der letzte Aenderung
    $unc_len=strlen($data);
    $crc=crc32($data);
    $zdata=gzcompress($data); // ZLib-Funktion nutzen
    $zdata=substr(substr($zdata,0,strlen($zdata)-4),2); // crc Bugfix
    $c_len=strlen($zdata);
    $fr.=pack('V',$crc); // crc32
    $fr.=pack('V',$c_len); // Dateigroesse: komprimiert
    $fr.=pack('V',$unc_len); // Dateigroesse: unkomprimiert
    $fr.=pack('v',strlen($name)); // Laenge des Dateinamens
    $fr.=pack('v',0); // Laenge: Extrafeld
    $fr.=$name;  
    // Ende des 'local file header' Segments
    // 'file data' Segment
    $fr.=$zdata;  
    // 'data descriptor' Segment (optional, aber noetig, falls Archiv nicht als Datei geliefert wird)
    $fr.=pack('V',$crc); // crc32
    $fr.=pack('V',$c_len); // Dateigroesse: komprimiert
    $fr.=pack('V',$unc_len); // Dateigroesse: unkomprimiert
    // Eintrag ins Array
    $this->datasec[]=$fr;
    $new_offset=strlen(implode('',$this->datasec));
    // dem zentralen Verzeichnis hinzufuegen
    $cdrec="\x50\x4b\x01\x02";
    $cdrec.="\x00\x00"; // Version, made by
    $cdrec.="\x14\x00"; // Version, wird zur Extraktion benoetigt
    $cdrec.="\x00\x00"; // Flag: gen purpose bit
    $cdrec.="\x08\x00"; // Kompressionsmethode
    $cdrec.="\x00\x00\x00\x00"; // Datum/Zeit der letzte Aenderung
    $cdrec.=pack('V',$crc); // crc32
    $cdrec.=pack('V',$c_len); // Dateigroesse: komprimiert
    $cdrec.=pack('V',$unc_len); // Dateigroesse: unkomprimiert
    $cdrec.=pack('v',strlen($name)); // Laenge des Dateinamens
    $cdrec.=pack('v',0); // Laenge: Extrafeld
    $cdrec.=pack('v',0); // Laenge: Dateikommentar
    $cdrec.=pack('v',0); // Start Disk Nummer
    $cdrec.=pack('v',0); // Interne Dateiattribute
    $cdrec.=pack('V',32); // Externe Dateiattribute - 'archive' Bit gesetzt
    $cdrec.=pack('V',$this->old_offset); // Relativer Offset des lokalen Headers
    $this->old_offset=$new_offset;
    $cdrec.=$name;  
    // Optionales Extrafeld fuer Dateikommentar
    // Eintrag ins zentrale Verzeichnis
    $this->ctrl_dir[]=$cdrec;  
  }
  function File() {
    // Liefert die komprimierte Archivdatei
    $data=implode('',$this->datasec);
    $ctrldir=implode('',$this->ctrl_dir);
    return $data.$ctrldir.$this->eof_ctrl_dir.
      pack('v',sizeof($this->ctrl_dir)). // Anzahl Eintraege 'on this disk'
      pack('v',sizeof($this->ctrl_dir)). // Gesamtanzahl Eintraege
      pack('V',strlen($ctrldir)).        // Groesse des zentralen Verzeichnisses
      pack('V',strlen($data)).           // Offset bis Start des zentralen Verzeichnisses
      "\x00\x00";                        // Laenge: ZipFile Kommentar
  }
} ?>

Modul-Quellcode :: Kompakt (ohne Kommentare)

<?php
class cZip { var $datasec=array(); var $ctrl_dir=array();
  var $eof_ctrl_dir="\x50\x4b\x05\x06\x00\x00\x00\x00"; var $old_offset=0;
  function Add_Dir($name) { $name=str_replace("\\","/",$name);  
    $fr="\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
    $fr.=pack('V',0).pack('V',0).pack('V',0).pack('v',strlen($name)).pack('v',0);
    $fr.=$name.pack('V',$crc).pack('V',$c_len).pack('V',$unc_len);
    $this->datasec[]=$fr; $new_offset=strlen(implode('',$this->datasec));
    $cdrec="\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00";
    $cdrec.=pack('V',0).pack('V',0).pack('V',0).pack('v',strlen($name)).pack('v',0);
    $cdrec.=pack('v',0).pack('v',0).pack('v',0).pack('V',16).pack('V',$this->old_offset);
    $this->old_offset=$new_offset; $cdrec.=$name; $this->ctrl_dir[]=$cdrec; }
  function Add_File($data,$name) { $name=str_replace("\\","/",$name);  
    $fr="\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00"; $unc_len=strlen($data);
    $crc=crc32($data); $zdata=gzcompress($data); $zdata=substr(substr($zdata,0,strlen($zdata)-4),2);
    $c_len=strlen($zdata);
    $fr.=pack('V',$crc).pack('V',$c_len).pack('V',$unc_len).pack('v',strlen($name)).pack('v',0);
    $fr.=$name.$zdata.pack('V',$crc).pack('V',$c_len).pack('V',$unc_len); $this->datasec[]=$fr;
    $new_offset=strlen(implode('',$this->datasec));
    $cdrec="\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00";
    $cdrec.=pack('V',$crc).pack('V',$c_len).pack('V',$unc_len).pack('v',strlen($name)).pack('v',0);
    $cdrec.=pack('v',0).pack('v',0).pack('v',0).pack('V',32).pack('V',$this->old_offset);
    $this->old_offset=$new_offset; $cdrec.=$name; $this->ctrl_dir[]=$cdrec; }
  function File() { $data=implode('',$this->datasec); $ctrldir=implode('',$this->ctrl_dir);
    return $data.$ctrldir.$this->eof_ctrl_dir.pack('v',sizeof($this->ctrl_dir)).
      pack('v',sizeof($this->ctrl_dir)).pack('V',strlen($ctrldir)).pack('V',strlen($data))."\x00\x00"; }
} ?>

Index :: PHP/MySQL


template