Tutorials

Einige nützliche Hilfen und Code-Schnipsel, die ich immer wieder benötige und deshalb hier für alle sammle.

Zurück zur Übersicht

Ordner rekursiv mit Php zu einer Zip-Datei packen

#Tutorials#PHP

Hat man auf einem Webspace keinen SSH-Zugriff, kommt man schnell an die Grenzen des Machbaren. So lassen sich leider nicht so leicht Backups erstellen.

Aber Php bietet auch eine Möglichkeit ganze Ordner zu einer Zip-Datei zu packen. Das Ganze geht wie folgt:


<?
// die maximale Ausführzeit erhöhen
ini_set("max_execution_time", 300);

// Objekt erstellen und schauen, ob der Server zippen kann
$zip = new ZipArchive();
if ($zip->open("backup.zip", ZIPARCHIVE::CREATE) !== TRUE) {
	die ("Could not open archive");
}

// Gehe durch die Ordner und füge alles dem Archiv hinzu
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("folder/"));
foreach ($iterator as $key=>$value) {
	$zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}
// speicher die Zip-Datei

$zip->close();
echo "Archive erfolgreich erstellt.";
?>

Ich hoffe ich konnte euch damit weiterhelfen ;)

Jon aus den Kommentaren hier, hat die Funktion genommen und verbessert. Hier ist sein Code zu finden:

http://pastebin.com/1qmUyWYc


Kommentare

  • User12
    Was muss ich angeben wenn ich die Dateien in dem Ordner wo die Datei die das ausführt gerade liegt? Also wenn ich einen Ordner namens "Webseite" habe und in dem Ordner liegt auch das script welches das ausführt.
    Antworten
    • Sven
      Das würde mich auch interessieren. Ich habe schon mit '.\' und '.' usw. herumprobiert aber dann taucht im Ergebnis immer die komplette Ordnerstruktur bis ganz hoch auf.
      Jemand eine Idee?
      Antworten
  • Gerold
    Ordner rekursiv mit Php zu einer Zip-Datei packen

    Der Code ist Top.
    Jetzt bräuchte ich noch eine Erweiterung das die Zip-Datei vom Web-Server auf einen Localen QNAP-Server übertragen wird. (zum Beispiel:Jeden Tag um 03:00 Uhr)
    Hast Du vielleicht eine Idee.
    Gruß Gerold
    Antworten
  • Jon
    Hi,

    bei mir haut leider was nicht hin. Ich habe am Ende des Skripts (vor $zip->close();) mal ein var_dump($zip); eingefügt und die Ausgabe sieht vielversprechend aus:

    object(ZipArchive)#1 (5) { ["status"]=> int(0) ["statusSys"]=> int(0) ["numFiles"]=> int(9520) ["filename"]=> string(45) "/var/www/user/html/domain/backup.zip" ["comment"]=> string(0) "" } Archive erfolgreich erstellt.

    Ich sehe 9520 Dateien und den korrekten Pfadnamen. Das Problem ist nur, die Datei backup.zip existiert nicht. Sie wird nicht erstellt. Sollte das Skript in dem Fall aber nicht vorher schon abbrechen?

    Grüße
    Jon
    Antworten
    • Jon
      Nach einigen weiteren Stunden konnte ich das Problem für mich endlich lösen. Im lokalen Apache funktioniert das Skript, wie es da steht.

      Auf meinem Webhoster leider nicht mehr. Damit es das tut, müssen, wie auch so ähnlich schon oben beschrieben, die Ordner ".." und "." explizit ausgeschlossen werden.

      Die obigen Lösungen funktionieren bei mir nicht unmittelbar, da es hier leider keine Code Umgebung im Kommentar gibt und damit die Hochkommas nicht funktionieren.

      Meine Lösung sieht derzeit so aus:

      foreach ($iterator as $key=>$value) {
      // ordner ".." und "." ignorieren
      if(substr($key, -2)!=".." && substr($key, -1)!=".")
      {
      $zip->addFile(realpath($key), $key) or die ("ERROR: Kann Datei nicht anfuegen: $key");
      }
      }

      Was leider noch nicht klappt, sind leere Ordner. Die werden bisher ausgelassen und rekursives Blacklisting von Ordnern. Eine einzelne Datei lässt sich wie oben beschrieben mit einem Array blacklisten. Bei einem Ordner mit Unterordern klappt es so noch nicht.
      Wenn ich Ordner "foo/bar" blackliste und den in_array() Vergleich durchführe, dann würde eine Datei "foo/bar/goo.css" nicht matchen und ins ZIP übernommen.
      Antworten
    • Jon
      Abschließend hätte ich noch ne Variante vorzuschlagen, die bei mir prima läuft.

      Nach meinen Tests wird damit alles ins Archiv übernommen. Auch leere Dateien und Ordner. Auch so "verrückte" Namen wie foo.. oder A. Die Ordner . und .. werden dagegen ausgelassen.

      [code]
      foreach ($iterator as $key=>$value) {
      // ist es ein ordner?
      if(!is_dir($key)) { // nein
      $zip->addFile(realpath($key), $key) or die ("ERROR: Kann Datei nicht anfuegen: $key");
      }
      // ist der ordner leer?
      elseif (count(scandir($key)) addEmptyDir(substr($key, -1*strlen($key),strlen($key)-1));
      }
      }
      [/code]

      Vielen Dank für die Inspiration. :)
      Antworten
    • Jon
      Sorry, aber das ist bei letzten Post was schief gegangen. Evtl. kann man den letzten Code einfach löschen.

      Hier noch ein mal.

      (Leider müssen alle Hochkommas manuell korrigiert werden, weil das hier irgendwie automatisch ersetzt wird.)

      [code]
      foreach ($iterator as $key=>$value) {
      // ist es ein ordner?
      if(!is_dir($key)) { // nein
      $zip->addFile(realpath($key), $key) or die („ERROR: Kann Datei nicht anfuegen: $key“);
      }
      // ist der ordner leer?
      elseif (count(scandir($key)) addEmptyDir(substr($key, -1*strlen($key),strlen($key)-1));
      }
      }
      [/code]
      Antworten
      • Jon
        Ok, offensichtlich liegt es nicht an mir, sondern daran, dass die Software hier den Code verändert. Wahrscheinlich ein Sicherheitsfeature. Den entsprechenden Code Ausschnitt gibt es bei Pastebin.

        http://pastebin.com/YbUbebBK

        Btw.:
        Wäre vielleicht keine schlechte Idee auf einer Seite, die sich auch mit Softwareentwicklung befasst, einen BBCode für [code] in den Kommentaren zu erlauben.
        Cheers jd ;-)
        Antworten
        • Andre Knieriem
          Hallo Jon, da hast du Recht, das ist echt störend. Hast du evtl eine Empfehlung für die Kommentarbox? Ansonsten schonmal vielen Dank für das gute Snipped, ich werde es oben in deinem Namen ergänzen!

          Danke!

          Grüße
          André
          Antworten
          • Jon
            Wenn du es verlinken willst, dann nimm bitte gleich diesen Link: http://pastebin.com/QzQptyTy
            Ich hatte zum ersten mal Pastbin benutzt und hatte es als Gast gepostet, was nicht veränderbar ist. Deswegen habe ich mir da einen Account gemacht und kann so Verbesserungen einpflegen.

            Wegen den Kommentaren. Ich kenne mich nicht aus mit Wordpress, aber ne Suche nach "wordpress kommentar mit syntax highlighting" führte mich direkt zu: https://de.wordpress.org/plugins/syntax-highlighter-for-wp-editor/
            Das sieht schon vielversprechend aus. Bzw. einfach mal in den Plugins dort nach Syntax Highlighting suchen. Da gibt's bestimmt noch mehr.

            Aber ich weiß nicht, ob es das Problem löst, dass die Validierungsfunktionen dieses Textfeldes bestimmte Codesequenzen filtert. Müsste man probieren.
            Antworten
          • Jon
            Man lernt nie aus. Pastbin erlaubt das Anmelden mit "Trashmails", löscht diese dann aber nach einigen Stunden. Naja, eine weitere Account Leiche.
            Ich hab mich jetzt erneut angemeldet ;-) und mal meine persönliche Endversion gepostet:
            http://pastebin.com/1qmUyWYc

            Getestet habe ich es neben einem Testordner an ca. 10.000 Dateien/Ordnern einer Joomla Installation. Dauerte ca. 40s auf dem Server und ist einwandfrei geworden. Wirklich ne super Sache für Backups, wenn man keinen Shell Zugang beim Hoster hat.

            Vielen Dank noch mal für die Vorlage. Ich habe dich da auch erwähnt. ;)
            Antworten
            • Mike
              Hi,
              danke für den tollen Ansatz. Das Script läuft ohne Fehlermeldung durch, meldet Vollzug - ABER: Ich kann kein fertiges zip auf dem Server finden?!
              Antworten
  • Maurizio
    Habe das Problem gelöst:

    Ich fange den string $key ab und prüfe, ob ein Punkt am Ende steht...

    foreach ($iterator as $key=>$value) {
    if(substr($key,-1) != ".")
    $zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
    }

    Gruß
    Antworten
  • Maurizio
    Hallo Andre,

    ja auch ich habe das gleiche Problem. In der gezippten Datei sind zwar alle Dateien drin, die ich haben wollte, ABER es sind ganz oben in der Liste zwei weitere Verzeichnisse zu sehen. Das eine mit einem Punkt, das zweite mit zwei Punkten.
    Beim Entzippen kommt es sodann zu einem Fehler.

    Gruß
    Antworten
  • Julian
    Das Zippen funktioniert.
    Ich habe jedoch ein anderes Problem. Die erstellte ZIP-Datei kann nach dem Download unter Win7 nicht geöffnet werden (das Fenster erschein leer) obwohl die ZIP-Datei 66,6MB groß ist. Unter MacOS bekomme ich die Datei mit einem Zusatzprogramm geöffnet, welches mir mitteilt, dass Ordern, die auf . oder .. enden nicht entpackt werden können. Okay, also Filter eingebaut und $key per echo ausgegeben. In der Anzeige erscheinen keine Ordner mehr mi . oder .. .... AAABER wenn ich nun wieder entzogen möchte, habe ich das gleiche Drama wie zuvor, plötzlich sind die . und .. Ordner doch in der ZIP-Datei drin...

    // die maximale Ausführzeit erhöhen
    ini_set("max_execution_time", 500);

    // Objekt erstellen und schauen, ob der Server zippen kann
    $zip = new ZipArchive();
    if ($zip->open("backup/moodledata.zip", ZIPARCHIVE::CREATE) !== TRUE) {
    die ("Kann Archiv nicht oeffnen");
    }

    // Gehe durch die Ordner und füge alles dem Archiv hinzu
    $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("/home/www/xyz/files/moodledata/"));
    foreach ($iterator as $key=>$value)
    {
    if(substr($key, -2)!="..")
    {
    if(substr($key, -1)!=".")
    {
    echo $key."";
    $zip->addFile(realpath($key), $key) or die ("ERROR: Kann Datei nicht anfuegen: $key");
    }
    }
    }
    // speichert die Zip-Datei

    $zip->close();

    Hast Du evtl. einen Tipp für mich, was der Grund sein könnte?

    Grüße Julian
    Antworten
    • Andre Knieriem
      Hallo Julian, das ist ja ein seltsames Problem. Ich habe leider davon nichts gehört und kann dir dabei auch leider nicht helfen. Woher kommen diese Dateien/Ordner denn? Sind sie bei dir auf dem Space?
      Antworten
    • Franco
      Ich bin mir bewusst, dass Julians Frage 4 Jahre alt ist ;-).
      Aber vielleicht kommt auch nach dieser Zeit noch jemand auf diese Seite (so wie ich), den die Lösung interessiert.
      Wie auch immer: Ich hatte das gleiche Problem wie Julian.
      Die Ursache war bei mir, dass ich die erstellte ZIP-Datei als ASCII heruntergeladen habe. Diese Datei ließ sich dann nicht entpacken.
      Wenn man im FTP-Programm als Übertragungstyp binär oder automatisch wählt, klappt anschließend das Entpacken der ZIP-Datei.
      Grüße und danke für das Script!
      Antworten
  • Steffen
    Leider funktioniert das mit dem Ausschliessen bestimmter Dateien bei mir nicht.
    $blacklist = array('index.php,.htaccess,zip.php');

    ...

    if(!in_array($key,$blacklist)) {
    $zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
    }

    habe ich da etwas übersehen oder falsch geschrieben?

    Grüße
    Antworten
    • Andre Knieriem
      Hi Steffen, du hast einen Fehler in deinem Array. Das Ganze muss für jedes Element mit ' ' umschlossen sein. Also in deinem Beispiel statt:

      $blacklist = array(‘index.php,.htaccess,zip.php’);
      $blacklist = array(‘index.php', '.htaccess,zip.php’);

      Grüße
      André
      Antworten
  • andi
    Hat sich erledigt, hatte den localname nicht richtig.
    http://www.jacobbates.com/blog/2012/04/24/corrupt-zip-files-in-windows-from-phps-ziparchive/
    Antworten
    • Andre Knieriem
      Super, dann ist ja alles gut! Freut mich, dass das Skript dir weitergeholfen hat.

      Grüße
      Antworten
  • andi
    Hi, bei mir klappt es soweit,
    nur möchte ich einen Ordner mit .xls Files zippen und wenn ich den Ordnerpfad direkt einbinde , klappts nicht.
    (ordner realtiv ../../excelFiles/ )

    Weiterhin zeigt er mir bei Windows ein korruptes Verzeichnis an, woran könnte das liegen ?
    Grüße
    Antworten
  • Detlef
    Hallo, vielen Dank für das Script. Klappt super.
    Ich habe dazu noch eine Frage. Ist es möglich, das Archiv auf der selben Ebene zu beginnen zu lassen. Dein Script liegt bei mir in httpdocs, weil ich es nur so aufrufen kann. Ich würde gern den gesamten httpdocs-Ordner sichern. Es müssten also sozusagen die Dateien gesichert werden, die parallel zur Scriptdateien liegen und alle Unterordner.

    Grüße
    Antworten
    • Andre Knieriem
      Hi Detlef, ich weiß nicht, ob das geht aber du könntest probieren, dass an der Stelle

      $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("folder/"));

      das "folder/" durch ein "./" zu ersetzen. Das heißt ja das jetzige Directory. Vielleicht geht das.

      Grüße
      Antworten
      • Detlef
        Hallo, vielen Dank für deine Antwort. Das funktioniert leider nicht. Ich erhalte die Fehlermeldung "ERROR: Could not add file: ./.."
        Die Varianten * und . und ../ habe ich auch schon probiert.
        Antworten
        • Andre Knieriem
          Hallo Detlef, das dachte ich mir schon :( Schade, dann weiß ich leider keine gute Möglichkeit das zu tun. Oder hast du vielleicht shell_exec Zugriff? Weil damit könntest du einfach shell_exec(‘zip -9 -r ‘) machen oder so.

          Grüße
          André
          Antworten
          • Detlef
            Nö. Da versteh ich auch nichts von. Auf jeden Fall Danke. Falls ich etwas rausfinde (was ich nicht glaube) schreib ich es hier als Kommentar.

            Grüße
            Antworten
  • princip1
    Danke!! funktioniert bei mir ! Hat mir sehr geholfen!
    Antworten
  • Sascha
    Hi,

    kann ich auch Ordner ausschließen und wenn ja wie?

    Gruß und Danke
    Antworten
    • admin
      Hi Sascha, das geht natürlich auch,

      ich würde hierfür ein Array machen mit Ordnern oder Dateinamen, die auf der Blacklist sind. Also

      $blacklist = array('Order1, index2.html,...');

      Dann müsste es eigentlich reichen, wenn du in Zeile 14 dann guckst, ob das was gerade an der Reihe in der Blacklist ist und wenn nicht dann wird es zum Zip hinzugefügt.

      Also ca so:
      if(!in_array($key,blacklist) { ...}

      Grüße
      André
      Antworten
  • bormolino
    Das Skript funktioniert bei mir leider nicht :(
    Antworten
    • admin
      Hi, bekommst du eine Fehlermeldung? Hast du vielleicht einen Link zu der Seite, wo es nicht geht? Bei mir funktioniert das Skript noch reibungslos, gerade erst benutzt ;)

      Grüße
      Antworten
      • bormolino
        Nein, ich bekomme keine Fehlermeldung und in den Logs steht auch nichts.

        Hier der Link: http://home.mborm.net/mbblog/zip.php
        Antworten
    • admin
      Hi, das hört sich seltsam an. Ist das error_reporting bei dir vielleicht ausgestellt? Du könntest mal gucken, ob bei mir überhaupt zippen möglich ist.

      $zip = new ZipArchive;
      var_dump($zip);

      Wenn das leer ist, oder einen Fehler wirft, dann kann dein Server womöglich gar keine Zips erstellen.

      Grüße
      Antworten
      • bormolino
        Error reporting ist an.

        Die Ausgabe lautet:

        object(ZipArchive)#1 (5) { ["status"]=> int(0) ["statusSys"]=> int(0) ["numFiles"]=> int(0) ["filename"]=> string(0) "" ["comment"]=> string(0) "" }
        Antworten
    • admin
      Das sieht richtig aus... Hm seltsam. Der Pfad zu deinem Ordner vielleicht falsch? In Zeile 12 muss der Ordner ja angepasst werden ;)

      Grüße
      Antworten
    • admin
      Dann weiß ich leider nicht mehr weiter. Du könntest höchstens noch probieren mit shell_exec('zip -9 -r '). Das geht aber nur, wenn du die richtigen Rechte hast, deswegen ist das Php Skript ja so praktisch.
      Antworten
      • bormolino
        Die richtigen Rechte habe ich und es klappt. Vielen Dank für deine Hilfe! :)
        Antworten

Hinterlasse einen Kommentar

Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Kommentar wird gespeichert
Danke für deinen Kommentar! Sobald er freigegeben wurde erscheint er hier.