phpBuddy

Code-Schnipsel

Jeder Programmierer sammelt im Laufe der Jahre Dutzende nützliche Funktionen, Klassen und sonstige Snipets. Hier gibt es einige nützliche Goodies, die jeder frei in seine eigenen Projekte einbauen kann.
Reinschauen lohnt sich!

Sie sind hier: Startseite Die Standard PHP Library
SPL - Die Standard PHP Library - Mit Verzeichnissen arbeiten
Beitragsseiten
SPL - Die Standard PHP Library
Unser erstes Iterator-Beispiel
Mit Verzeichnissen arbeiten
Zip-Dateien on-the-fly erstellen
Backup Basis Script
Inhalte filtern
Fazit und Schlußwort
Alle Seiten

Mit Verzeichnissen arbeiten - DirectoryIterator

Was für Arrays die ArrayIterator Klasse ist, ist für Verzeichnisse die DirectoryIterator Klasse. Diese Klasse stellt Methoden zu Verfügung mit der wir ohne großen Aufwand gängige Verzeichnis-Aktionen ausführen können. Schauen wir uns im Schnelldurchlauf mal die wichtigsten Methoden an, die weitestgehend selbsterklärend sind. Neben den üblichen 5 Verdächtigen der Iterator Klasse (siehe oben) stehen weiterhin zur Verfügung:

  • getFilename() - Der Dateiname ohne Pfad
  • getMTime() - Datum der letzten Modifikation
  • getPath() - Der Pfad zu einer Datei
  • getRealPath() - Der absolute Pfad zu einer Datei
  • getSize() - Dateigröße
  • isDir() - Gibt True zurück, wenn der Name ein Verzeichnis ist
  • isDot() - Gibt True zurück, wenn "." oder ".." gefunden wird
  • isFile() - Ist True, wenn es sich um eine Datei handelt
  • isReadable() - Ist True, wenn eine Datei lesbar ist
  • isWritable() - Ist True, wenn eine Datei schreibbar ist

Die DirectoryIterator Klasse umfasst etwa dreimal soviele Methoden wie die hier gezeigten, aber das sind meiner Meinung nach die wichtigsten.

Das Auslesen eines Verzeichnis ist sehr einfach und mit wenigen Zeilen Code erledigt.

$verzeichnis = new DirectoryIterator( "testdateien/" );
 
while ($verzeichnis->valid())
{
    echo $verzeichnis->current(). " (" .$verzeichnis->getSize(). ")<br />";
    $verzeichnis->next();
}

Wir erzeugen ein Objekt von der DirectoyIterator Klasse und übergeben dabei den Verzeichnisname dessen Inhalt wir ausgeben lassen möchten. Die Struktur der while()-Schleife sollte nun bekannt sein. Zusätzlich lassen wir uns noch zu jeder Datei die Größe ausgeben, was für uns die Methode getSize() der DirectoyIterator Klasse übernimmt. Das Ergebnis sieht allerdings nicht sonderlich ansprechend aus, wie man im folgenden Listing sieht:

. (0)
.. (0)
bilder (0)
controller.php (4901)
includes (0)
m3_saz.jpg (72517)
mixed (0)
whois.php (21563)
whois.zip (3718)

Da sind Dateien mit Ordnern vermischt und auch "." ".." sehen nicht sonderlich gut aus. Wir bekommen ausserdem nur die Dateien aus dem angegebenen Ordner, was meistens wenig nützlich ist. Um herauszufinden was in den anderen Ordnern steckt müssen wir anfangen eine umständliche Funktion zu schreiben, die uns rekursive durch die Verzeichnisse navigieren läßt. Für diesen Zweck gibt es ja auch die nötigen Boardmittel wie isDot() oder auch isDir().
Aber muß es wirklich so kompliziert werden oder kommt uns da vielleicht wieder die SPL zu Hilfe? In der Tat wurde auch daran gedacht und die SPL stellt für das rekursive arbeiten die entsprechenden Klassen zur Verfügung. Um es genau zu sagen bietet die SPL zu jedem Iterator-Typ auch eine Recursive-Version der Klasse an. Wie praktisch das ist zeigt das nächste Beispiel...

Verzeichnisse rekursive auslesen mit der RecursiveDirectoryIterator Klasse

Die RecursiveDirectoryIterator Klasse bringt im Vergleich zur DirectoryIterator Klasse nur 2 neue Methoden mit, aber die sind überaus nützlich. Diese beiden Methoden sind:

  • hasChildren() - Liefert True, wenn ein "Kind" (Unterverzeichnis) vorhanden ist
  • getChildren() - Liefert den Namen vom "Kind" (Unterverzeichnis)

Mit diesen beiden zusätzlichen Methoden können wir jetzt wirklich ganz bequem eine sehr übersichtliche Funktion erstellen, um rekursive durch Verzeichnisse zu navigieren. Here we go...

function VerzeichnisBaum( RecursiveDirectoryIterator $zeiger )
{
    echo '<ul>';
    for ($zeiger->rewind(); $zeiger->valid(); $zeiger->next())
    {
        if ($zeiger->isDir() && !$zeiger->isDot())
        {
            echo '<li><span class="hinweis">' .$zeiger->getFilename(). '</span></li>';
            if ($zeiger->hasChildren())
            {
                $unterverzeichnis = $zeiger->getChildren();
                echo '<ul>' . VerzeichnisBaum( $unterverzeichnis ) . '</ul>';
            }
        } elseif ($zeiger->isFile())
        {
            echo '<li><em>'. $zeiger->getFilename() . '</em></li>';
        }
    }
    echo '</ul>'; 
}
 
VerzeichnisBaum( new RecursiveDirectoryIterator( 'testdateien/' ) );

Die Basisversion dieser Funktion habe ich aus dem Buch "PHP 5 - Grundlagen und Profiwissen von Jörg Krause". Allerdings habe ich die Funktion etwas abgewandelt um sie verständlicher zu machen.
Die Funktionsweise ist einfach und weitestgehend selbsterklärend. Beim Funktionsaufruf (ganz unten) wird das Objekt der RecursiveDirectoryIterator Klasse übergeben. Der Klasse selbst geben wir nur den Pfad und Verzeichnisname mit den wir durchlaufen möchten.
Wie in der Funktion zu sehen ist prüfen wir ob der Zeiger auf einem Verzeichnis steht ($zeiger->isDir()) und geben den Element-Name ($zeiger->getFilename()) fett aus. Anschließend wird geprüft (mit $zeiger->hasChildren()) ob das Element (Verzeichnis) ein Kind (Unterverzeichnis) hat - trifft das zu, lesen wir den Namen des Kindes aus ($zeiger->getChildren()) und übergeben diesen Namen an die Funktion, die sich selbst mit dem Unterverzeichnisname aufruft. Am besten zwei oder drei mal diese Funktion durchlesen und nachvollziehen um das Prinzip zu verinnerlichen. Viel einfacher kann man Verzeichnisse nicht rekursive auslesen, oder?! Hmm, oder vielleicht doch!?!