PHP rocks! wünscht allen Mitgliedern einen guten Rutsch ins neue Jahr 2017 !!!
Hinweis: Das Forum zieht um! Um keine Datenverluste zu haben, schalten wir zwecks Übernahme der Daten das Forum am Sonntag, den 24.04.2016 um ca. 21:00 Uhr offline und passen anschliessend die DNS-Einträge an.
www.php-rocks.de wird euch dann nach den Aktualisierungen der DNS-Server wieder wie gewohnt uneingeschränkt zur Verfügung stehen.
Danke für euer Verständnis!

Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
PHP Grundlagen Verzeichnisse rekursiv iterieren mit der SPL
#1
Was bezweckt dieses Tutorial
In größeren Projekten kann es hilfreich sein, ab einem bestimmten Einstiegspunkt die komplette Verzeichnisstruktur inklusive der Datei-Informationen rekursiv bspw. in einem Array vorzuhalten. Ich möchte hier kurz zeigen, wie das mit Hilfe der SPL ( Standard PHP Library ) möglich ist.

Da die SPL über eine Auswahl an Iteratoren verfügt, brauchen wir uns um die Rekursion innerhalb der Verzeichnisstruktur keine Gedanken machen, geschweige denn dafür sich selbst aufrufende Funktionen/Methoden zu entwickeln.


Wir fangen an
...und zwar ganz einfach mit Angabe des Einstiegsverzeichnis $sRootDir und dem Initiieren der beiden SPL-Iteratoren RecursiveDirectoryIterator und RecursiveIteratorIterator. Für unser Beispiel gehen wir mal vom Einstiegsverzeichnis images aus:
PHP-Code:
$sRootDir 'images';

$itrDirectory = new RecursiveDirectoryIterator$sRootDir );
$itrIterator = new RecursiveIteratorIterator$itrDirectoryRecursiveIteratorIterator::SELF_FIRST ); 
Was wir jetzt haben ist ein Iterator, der es uns ermöglicht, uns im Dateisystem ab dem Einstiegspunkt zu bewegen und Informationen zu sammeln.
Zu Beachten ist, daß das Objekt an sich noch keine Daten enthält, sondern lediglich die Iteration und das Abrufen der Informationen über Methoden zur Verfügung stellt.

Die Iteration selbst kann praktischerweise wie bei Arrays mit foreach durchgeführt werden. Ich entscheide mich hier für die while-Variante, da ich dieser eine sinnigere Logik abgewinnen kann. Das ist allerdings nur meine persönliche Ansicht!


Sammeln der Informationen über die Iteration
Zunächst bereiten wir die Iteration vor, indem wir den Zeiger des Objektes mit der Methode rewind() zurücksetzen. Zudem deklarieren wir uns ein Array, das die gesammelten Daten am Ende enthält:
PHP-Code:
$aRecursiveDirContent = array();
$itrIterator->rewind(); 
Die Iteration an sich ist über while relativ einfach. Dazu bedienen wir uns der Methode valid(), die uns Auskunft darüber gibt, ob wir über ein gültiges Element verfügen:
PHP-Code:
while ( $itrIterator->valid() ) {

 
   // ... Informationen sammeln ( wird im nächsten Abschnitt detailliert beschrieben )

 
   $itrIterator->next();


Das ist bereits das Geheimnis der ganzen Iteration. Mit der Methode next() setzen wir den Zeiger des Objektes auf das nachfolgende Element.
Jetzt müssen wir nur noch...


Informationen sammeln
Jetzt kommt es auf den subjektiven Fall an, wie wir die Daten sammeln und welche überhaupt.
Ich habe für dieses kleine Tutorial mal für mich festgelegt, daß wir am Ende in $aRecursiveDirContent über alle Verzeichnisse als Schlüssel-Element verfügen, deren Werte auf Array-Basis die Dateien mit erweiterten Informationen enthalten.

Folgende Datei-Informationen wollen wir erhalten:
  • filename ( Dateiname )
  • filesize ( Dateigröße in Bytes )
  • permissions ( Dateiberechtigung Oktal )
  • created ( Erstellungsdatum, anhand der inode change Information )
  • modified ( letztes Änderungsdatum )
  • lastaccess ( letzter Dateizugriff )

Dazu holen wir uns zunächst über current() ein Objekt vom Typ SplFileInfo vom aktuellen Element und den Verzeichnisnamen mit der Methode getPath():
PHP-Code:
$splFileInfo $itrIterator->current();
$directory $splFileInfo->getPath(); 
Anhand dieser Daten entscheiden wir als erstes, ob es sich um ein neues Verzeichnis handelt, das noch nicht von uns "gesammelt" wurde und schreiben es bei Bedarf in unseren Container rein:
PHP-Code:
if ( $splFileInfo->isDir() && !isset($aRecursiveDirContent[$directory]) ) {

 
   $aRecursiveDirContent[$directory] = array();


Über die Methode isDir() prüfen wir, ob es sch bei dem aktuellen Element um ein Verzeichnis handelt.

Auf die gleiche Art prüfen wir mit der Methode isFile() im nächsten Step, ob es sich um eine Datei handelt und tragen unsere Informationen zusammen. Dazu möchte ich erstmal den gesamten Code-Block zeigen und die wichtigen Punkte hinterher ansprechen:
PHP-Code:
if ( $splFileInfo->isFile() ) {

 
   $aRecursiveDirContent[$directory][] = array(
 
           'filename' => $splFileInfo->getFileName(),
 
           'filesize' => $splFileInfo->getSize(),
 
           'permissions' => substrsprintf('%o'$splFileInfo->getPerms()), -),
 
           'created' => date'd.m.Y H:i:s'$splFileInfo->getCTime() ),
 
           'modified' => date'd.m.Y H:i:s'$splFileInfo->getMTime() ),
 
           'lastaccess' => date'd.m.Y H:i:s'$splFileInfo->getATime() )
 
       );


Im Prinzip ist das schon alles. Wie erkennbar ist, sammeln wir einfach alle Informationen über entsprechende Methoden in unserem Container-Array $aRecursiveDirContent.

Der Vollständigkeit, hier nochmal die verwendeten Methoden der Datei-Informationen:
  • getFilename()
    Gibt den Dateinamen zurück
  • getSize()
    Gibt die Dateigröße in Bytes an
  • getPerms()
    Liefert die Dateirechte als Integer. Über sprintf wandeln wir die Ausgabe oktal um und holen uns über substr nur die relevanten letzten vier Stellen.
  • getCTime()
    Liefert das Erstellungsdatum als Timestamp ( ermittelt anhand der change inode time )
  • getMTime()
    Liefert das Datum der letzten Aktualisierung als Timestamp.
  • getATime()
    Liefert das Datum des letzten Dateizugriffs als Timestamp.

Damit haben wir nun alle Daten in einem Array gesammelt, dies könnt ihr euch testweise mit print_r oder var_dump ausgeben lassen. Die Ausgabe kann bspw. so aussehen:
Code:
Array
(
   [/images] => Array
       (
           [0] => Array
               (
                   [filename] => logo.png
                   [filesize] => 14707
                   [permissions] => 0644
                   [created] => 30.03.2015 21:35:43
                   [modified] => 30.03.2015 21:36:32
                   [lastaccess] => 30.03.2015 21:36:32
               )

           [1] => Array
               (
                   [filename] => error.png
                   [filesize] => 623
                   [permissions] => 0644
                   [created] => 17.03.2015 17:41:18
                   [modified] => 15.02.2015 22:36:12
                   [lastaccess] => 15.02.2015 22:36:12
               )

           [2] => Array
               (
                   [filename] => close.png
                   [filesize] => 950
                   [permissions] => 0644
                   [created] => 17.03.2015 17:41:13
                   [modified] => 15.02.2015 22:36:10
                   [lastaccess] => 15.02.2015 22:36:10
               )

           [...]


Der komplette Code zur Übersicht
Um das kleine Tutorial damit abzuschliessen, hier nochmal der ganze Code als Übersicht:
PHP-Code:
$sRootDir 'images';

$itrDirectory = new RecursiveDirectoryIterator$sRootDir );
$itrIterator = new RecursiveIteratorIterator$itrDirectory );


$aRecursiveDirContent = array();
$itrIterator->rewind();


while ( 
$itrIterator->valid() ) {

 
   $splFileInfo $itrIterator->current();
 
   $directory $splFileInfo->getPath();

 
   if $splFileInfo->isDir() && !isset($aRecursiveDirContent[$directory]) ) {

 
      $aRecursiveDirContent[$directory] = array();

 
   }

 
   if $splFileInfo->isFile() ) {

 
       $aRecursiveDirContent[$directory][] = array(
 
               'filename' => $splFileInfo->getFileName(),
 
               'filesize' => $splFileInfo->getSize(),
 
               'permissions' => substrsprintf('%o'$splFileInfo->getPerms()), -),
 
               'created' => date'd.m.Y H:i:s'$splFileInfo->getCTime() ),
 
               'modified' => date'd.m.Y H:i:s'$splFileInfo->getMTime() ),
 
               'lastaccess' => date'd.m.Y H:i:s'$splFileInfo->getATime() )
 
           );

 
   }

 
   $itrIterator->next();




Gehe zu: