Technik, Gothic und Anderes

Technik ist Spiel, Gothic ist ernst und Zeit hat man zuviel

  • Kategorien

  • Tags

  • Archiv

  • Links

    zu Bee5

    blog.oncode.info läuft bei Cyon und ich bin sehr glücklich damit.

Zipdateien on-the-fly erstellen mit PHP

Geschrieben von skaldrom am 17. October 2007

Das Problem

On-The-Fly An unserer Schule wird Moodle als LMS (Learning Management System) verwendet. Es eignet sich sehr gut um Unterrichtsunterlagen wie Skripts, Aufträge und Präsentationen zu publizieren und den Lernenden auf eine angenehme Art und Weise zur Verfügung zu stellen. In einigen Kursen gibt es sehr viele dieser Ressourcen (Dateien und Verzeichnisse) zum Download und alleine schon das Anklicken und Speichern nimmt einen grossen Teil des zur Verfügung stehenden Zeitbudgets ein.

Einzelne Ressourcen können von der Lehrperson unsichtbar gemacht werden und nicht alle Dateien eines Kurses stehen zum Download bereit. Die Ansicht ist also sehr individuell und kann sich schnell ändern. Die Dateien werden über eine Versionsverwaltung in das System eingespiesen und können sich so ausserhalb des Systems verändern. Leider verunmöglicht dies die offensichtliche Lösung, einfach ein statisches Zip-Archiv zum Download zur Verfügung zu stellen.

Screenshot Moodle

Die Lösung

Das Zip muss also dynamisch (im Speicher) generiert werden bei einem Aufruf. Fündig wurde ich bei der Klasse archive bei phpclasses.org. Neben Zip-Archiven kann sie auch tar’s, gzip’s und bzip2′s erzeugen. Ich habe einige, kleine Erweiterungen vorgenommen, die noch beschrieben werden.

Die Handhabung ist sehr einfach:

// Archivklasse einbinden:
require_once ('lib/archive.php');

// Objekt erzeugen. Das Argument bezeichnet den Dateinamen
$zipfile= new zip_file('Meine Zipdatei.zip');

// Die Optionen
$zipfile->set_options(array (
        'basedir' => "/home/me/toZip/", // Das Basisverzeichnis. Sonst wird der ganze Pfad von / an im Zip gespeichert.
        'followlinks' => 1, // Symlinks sollen berücksichtigt werden
        'inmemory' => 1, // Die Datei nur im Speicher erstellen
        'level' => 6, // Level 1 = schnell, Level 9 = gut
        'recurse' => 1, // In Unterverzeichnisse wechseln
        // Wenn zu grosse dateien verarbeitet werden, kannes zu einem php memory error kommen
        // Man sollte nicht über das halbe memory_limit (php.ini) hinausgehen
        'maxsize' => 12*1024*1024 // Nur Dateien die <= 12 MB gross sind zippen
));

// Alle Dateien im Verzeichnis /home/me/toZip/Stuff hinzufügen
// Alle ".doc" Dateien und alle Ordner im Verzeichnis /home/me/toZip/Letters hinzufügen
$zipfile->add_files(array("Stuff", "Letters/*.doc"));

// Alle ".tmp" dateien in Stuff ausschliessen
$zipfile->exclude_files("htdocs/*.tmp");

// Alle Dateien in ".svn" und "CVS" Verzeichnissen ausschliessen (Regular Expressions)
$zipfile->exclude_regexp_files('.*/CVS|.*/CVS/.*|.*/\.svn|.*/\.svn.*');

// Archiv erstellen
$zipfile->create_archive();

// Archiv zum Download anbieten
$zipfile->download_file();

// Oder speichern (vielen Dank an PHPler!!!)
$zipfile->save_file('myzip.zip', $path = '/tmp/');

Änderungen

Ich habe folgende Dinge gegenüber der original archive.php geändert:

  • Mittels exclude_regexp_files() können Dateien auf Grund von Regular Expressions ausgeschlossen werden.
  • Die maxsize Option erlaubt das Ausschliessen von Dateien die grösser sind als die angegebene Zahl in Byte.
  • Verzeichnisse unter Linux werden als Verzeichnisse behandelt (Bug?)
  • exclude_file() prüft, ob eine Datei ausgeschlossen würde

Dank PHPler lönnen nun auch mit der Methode save_file($filename, $path = '') inmemory zips als Dateien gespeichert werden.

Meine Version kann natürlich auch frei heruntergeladen werden.


22 Antworten zu “Zipdateien on-the-fly erstellen mit PHP”

Kommentare

  1. Marciel Schreibt:

    Hallo,

    habe das mal ausprobiert, bekomme aber kein Ergebnis. Wie genau muss ich das jetzt machen, wenn ich zum Beispiel den Ordner uploads/images komplett zippen will?

    Welche Dateien muss ich erstellen und mit welchen Scriptinhalt???

    Also ich habe bislang folgendes versucht:
    -Ordner lib erstellt und Datei archieves.php reingeladen
    -im basisverz. eine Datei zip.php mit dem obigen Script und meinen Einstellungen erstellt.

    Beim Aufruf ist wie gesasgt nichts passiert.

  2. admin Schreibt:

    Ich habe Dir gemailt und werde das Problem und die Lösung hier gerne posten…

  3. Marciel Schreibt:

    Vielen Dank für die schnelle Reaktion. Freu mich schon auf die Lösung.

  4. admin Schreibt:

    Oky, ich hoffe es hat funktioniert… Der Code in diesem Beitrag hatte Bugs (korrigiert) und es sollten keine nichtexistenten Verzeichnisse ausgeschlossen werden….

  5. Marciel Schreibt:

    Jetzt bleibt nur noch das Problem, dass der Microsoft IE es nicht schafft, den richtigen Dateinamen bzw. -pfad mitzubekommen und immer versucht die PHP-Datei herunterzuladen, anstatt der ZIP-Datei.

  6. hydrauligzap Schreibt:

    hallo,

    obwohl der artikel schon etwas älter ist hätte ich da noch ne frage.
    und zwar bringt er bei mir immer:
    Warning: Cannot modify header information – headers already sent by…
    an was könnte das denn liegen? an php 5? (ist mit zip-enabled compiliert.)
    ich hab auch keine ausgabe davor gemacht. nur comments im code, wie in deinem beispiel.
    hast du da ne idee?

  7. Marciel Schreibt:

    Kann man mit der Class auch ein ZIP-Archiv in ein Verzeichnis entpacken??
    Wie müsste der Code dafür aussehen??

    Mfg

  8. Carlos Schreibt:

    Hallo

    Ich habe die Klasse implementiert und es scheint soweit zu funktionieren. Das Problem ist nur, dass sich die Files im ZIP nicht öffnen lassen.

    Beim Öffnen des ZIP Files melden die ZIP Programme folgendes:
    WinRAR: “Unexpected end of archive”
    Microsoft ZIP: “Der ZIP-komprimierte Ordner ist ungültig oder beschädigt.

    Beim Versuch, ein jpg aus WinRar zu öffnen meldet dieser:
    Unexpected end of archive
    C:\TEMP\test\Meine Zipdatei.zip: Either multipart or corrupt ZIP archive

    An was könnte das liegen? Serverkonfiguration? Zur Info: Damit ich die Header Funktion innerhalb einer Klasse benutzen kann, habe ich in .htaccess php_flag output_buffering On.

    Für mögliche Hilfestellungen bin ich euch dankbar.

  9. skaldrom Schreibt:

    Was diese Klasse angeht habe ich noch einige Anfragen offen. Das Problem ist halt, ich komm so selten an Windows Compies :-(… Aber ich hab Dir gemailt…

  10. Marc Schreibt:

    Vielen Dank für dein Script,

    ich wollte noch gerne erfahren, ob es möglich ist,
    Dateien zu zippen – ohne die Ordnerstruktur einzubeziehen.

    z.B.
    $zipfile->add_files(array(“ordner/ordner/*.jpg”));

    und das zipfile soll jedoch nur die files beinhalte, nicht die ordner (-struktur).

    bitte hinterlass mir mal eine zeile,
    lg,
    marc

  11. skaldrom Schreibt:

    Das ist natürlich etwas tricky wegen doppelten Dateinamen. Laut http://www.phpclasses.org/browse/file/6584.html müsste das gehen, wenn Du bei den Optionen

    storepath

    auf

    0

    setzt. In unserem Beispiel also:

    $zipfile->set_options(array (
            'basedir' => "/home/me/toZip/", // Das Basisverzeichnis. Sonst wird der ganze Pfad von / an im Zip gespeichert.
            'followlinks' => 1, // Symlinks sollen berücksichtigt werden
            'inmemory' => 1, // Die Datei nur im Speicher erstellen
            'level' => 6, // Level 1 = schnell, Level 9 = gut
            'recurse' => 1, // In Unterverzeichnisse wechseln
            'storepath' => 0, // Unterverzeichnisse nicht speichern
            // Wenn zu grosse dateien verarbeitet werden, kannes zu einem php memory error kommen
            // Man sollte nicht über das halbe memory_limit (php.ini) hinausgehen
            'maxsize' => 12*1024*1024 // Nur Dateien die <= 12 MB gross sind zippen
    ));

    ich habs aber nicht getestet.

  12. Benni Schreibt:

    ich habe das script in meine homepage eingebaut und es funktioniert perfekt, mit nur ein paar kleinen änderungen lassen sich bestimmte dateien (werden aus einer mysql datenbank entnommen) zippen und downloaden.
    Es ist ein tollest script, danke.
    Soll ich auf der Homepage angeben das es von dir ist oder war es einfach nur so ein “spasprojekt”? :P

    danke

  13. skaldrom Schreibt:

    Vielen Dank für die Blumen! Es freut mich sehr wenn ich Rückmeldungen erhalte.
    Ebenfalls ist die Frage nach der Quellenanfrage sehr nett und wirklich höflich. Du musst meinen Namen nicht angeben und kannst es verwenden, wie Du möchtest.

  14. PHPler Schreibt:

    Hallo,
    eine coole Klasse hast du da Programmiert. Ich habe mal noch eine Kleinigkeit hinzugefügt:

        /**
         * this method saves the current archive-stream to the filesystem
         * @param string $filename
         * @param string $path
         * @return int success-/error-code
         */
        function save_file($filename, $path = '') {

            if ($this->options['inmemory'] == 0) {
                $this->error[]= "Can only use save_file() if archive is in memory.";
                return;
            }
           
            if($fhandle = @fopen($path . $filename, 'w')) {
                if(@fwrite($fhandle, $this->archive)) {
                    if(@fclose($fhandle))
                        return 1;
                    else
                        return 0;
                }else{
                    return -2;
                }
            }else{
                return -1;
            }
        }

    Gruß
    PHPler

  15. skaldrom Schreibt:

    Heyo, vielen Dank! Das ist eine geniale Erweiterung. Ich habe sie aufgenommen und Dich erwähnt und hoffe, das ist ok so für Dich….

  16. chris Schreibt:

    Hi,

    Tolles, einfaches script, leicht anpassbar und einsetzbar.

    Vielen Dank!

  17. skaldrom Schreibt:

    Vielen Dank für das Lob *blush*…

  18. misterunknown Schreibt:

    Sensationell.
    Nach schier endlosem Suchen endlich mal ein Skript, welches wirklich funktioniert. Du hast mir echt den Tag gerettet :)

    Es ist ein von wenig Erfolg gekröntes Unterfangen, ein ZIP-Skript zu finden, welches sowohl Linux-Verzeichnisse als solche interpretiert, als auch das Archiv als Datei zwischenspeichert (was bei größeren Datenmengen sehr wichtig ist).

    Ich arbeite gerade an einem One-Script-File-Manager und eine Funktion zum Download Verzeichnissen hat mir viele graue Haare beschert^^

    Mit dankendem Grinsen,
    misterunknown

  19. skaldrom Schreibt:

    Freut mich sehr, dass es Dir geholfen hat. Viel Erfolg mit Deinem Script..

  20. Max Schreibt:

    Wirklich tolles Skript. Nach längerem Anpassen klappt auch alles. Ich habe nur ein anderes Problem. Bei mir werden leider die deutschen Sonderzeichen nicht richtig angezeigt. Aus “ü” wird zum Beispiel “³” usw… Wo kann ich den in der Klasse die entsprechende Formatierung umstellen. Irgendeine Idee?

    Danke nochmals.

    LG.

    Max

  21. Andrej Schreibt:

    super script. Habe es etwas an meine Bedürfnisse angepasst und jetzt funktioniert alles einwandfrei bis auf dasgleiche Problem, dass auch Max angesprochen hat:
    Dateien, die Umlaute oder Ähnliches enthalten werden falsch kodiert und in der zip-Datei nicht wie das Original dargestellt. Habe schon im Internet gesucht und eventuell hängt es mit der Kodierung zusammen. Doch meine Änderungen an der Kodierung der archive.php sowie der example.php haben leider nichts geändert.
    Muss ich evtl. noch den header-Befehl anpassen?

    Habt ihr vielleicht weitere Ideen?

  22. skaldrom Schreibt:

    Hast Du das Problem mit den Pfaden, den Dateinamen oder mit Beidem? Unter welchem Betriebssystem? Am Besten könnte ich das debuggen mit einem Codebeispiel…

Lassen Sie eine Antwort hier...

XHTML: Sie können folgende Tags verwenden: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


7 − = one