Navigation
 Startseite
 Fachbücher
 Anzeigenmarkt
 Forum
 Webmaster News
 Script Newsletter
 Kontakt
 Script Installation
 Php
 Php Tutorials
 Webhoster Vergleich
 Impressum

Community-Bereich
 kostenlos Registrieren
 Anmelden
 Benutzerliste

Script Datenbank
 Script Archiv
 Script Top 20
 Screenshots
 Testberichte

Suche
 

Unsere Php Scripts
 Counter Script
 Umfrage Script
 Bilder Upload Script
 Terminverwaltung
 Simple PHP Forum
 RSS Grabber

Script Mods
 phpBB Adsense Mode

Tools und Generatoren
 .htpasswd Generator
 md5 Generator
 base64 Generator
 Markdown to HTML
 Colorpicker
 Unix timestamp Tool
 TLD Liste
 Webkatalog‑Verzeichnis

Partner
 Sprüche Treff

Artfiles.de
Bietet Serviceorientierte...
https://www.Artfiles.de
Hosterplus.de
Bekommen Sie Speicherplatz (Webspace), Domains...
https://www.Hosterplus.de
 
 
 

PHP opendir() - Verzeichnisse öffnen und auslesen

Sie befinden sich: Home > Php Tutorial > PHP opendir() -...

PHP opendir() - Verzeichnisse öffnen und auslesen


Eintrag am:  11.03.2024
Hits / Besucher:  2995
Sprache:  Deutsch
Kategorie:  Einsteiger Tutorials
Tutorial Art:  eigenes
Eingetragen von   schubertmedia schubertmedia
 
Beschreibung

Wer mit PHP Dateien aus Verzeichnissen auflisten möchte, kommt an den Verzeichnisfunktionen nicht vorbei. Die klassische Kombination aus opendir(), readdir() und closedir() ist seit den Anfängen von PHP verfügbar und bildet die Grundlage für das Arbeiten mit Ordnerstrukturen. Dieses Tutorial erklärt die drei Funktionen im Detail, zeigt typische Stolperfallen und stellt mit scandir(), glob() und den SPL-Iteratoren auch die modernen Alternativen vor.

Diagramm zur opendir Funktion in PHP mit Vergleich der Vorteile und Nachteile

Grundlagen: opendir(), readdir() und closedir()

Die drei Funktionen arbeiten zusammen wie fopen(), fread() und fclose() bei Dateien. Zuerst wird das Verzeichnis geöffnet, dann werden die Einträge einzeln gelesen, und am Ende wird das Verzeichnis-Handle wieder geschlossen.

opendir() öffnet ein Verzeichnis

opendir() erwartet einen Verzeichnispfad als Parameter und gibt bei Erfolg ein Handle zurück. Bei einem Fehler (Verzeichnis existiert nicht oder keine Leserechte) gibt die Funktion false zurück.

<?php

$handle = opendir('/var/www/uploads');

if ($handle === false) {
die('Verzeichnis konnte nicht geöffnet werden.');
}
?>

readdir() liest den nächsten Eintrag

readdir() gibt bei jedem Aufruf den Namen des nächsten Eintrags im Verzeichnis zurück. Wenn alle Einträge gelesen wurden, gibt die Funktion false zurück. Wichtig: Der Vergleich in der while-Schleife muss mit !== erfolgen, weil ein Verzeichniseintrag den Namen "0" tragen könnte, was bei einem losen Vergleich als false interpretiert würde.

closedir() schliesst das Handle

closedir() gibt das Verzeichnis-Handle wieder frei. Das sollte immer aufgerufen werden, sobald die Arbeit mit dem Verzeichnis abgeschlossen ist, um Ressourcen freizugeben.

Die klassische Schleife

Das folgende Beispiel zeigt das vollständige Muster mit Fehlerbehandlung und Filterung der Pseudo-Einträge . und ..:

<?php

$verzeichnis = __DIR__ . '/uploads';

if (!is_readable($verzeichnis)) {
die('Verzeichnis nicht lesbar: ' . $verzeichnis);
}

$handle = opendir($verzeichnis);
if ($handle === false) {
die('Verzeichnis konnte nicht geöffnet werden.');
}

$dateien = [];
while (($eintrag = readdir($handle)) !== false) {
/* Die Pseudo-Eintraege . und .. ueberspringen */
if ($eintrag === '.' || $eintrag === '..') {
continue;
}
$dateien[] = $eintrag;
}
closedir($handle);

echo 'Gefunden: ' . count($dateien) . ' Einträge';
?>

Die Einträge . (aktuelles Verzeichnis) und .. (übergeordnetes Verzeichnis) werden von readdir() immer mitgeliefert. Ohne die Filterung mit continue würden sie in der Ergebnisliste auftauchen und spätere Verarbeitungsschritte stören.

Fehlerbehandlung bei Verzeichnisoperationen

Robuster Code muss damit rechnen, dass ein Verzeichnis nicht existiert, nicht lesbar ist oder während der Verarbeitung gelöscht wird. opendir() gibt bei einem Fehler false zurück und erzeugt zusätzlich eine PHP-Warning. Es gibt mehrere Möglichkeiten, damit umzugehen.

Vorab-Prüfung mit is_dir() und is_readable()

Die sicherste Methode ist eine Prüfung vor dem Öffnen. Mit is_readable() lässt sich feststellen, ob das Verzeichnis überhaupt gelesen werden kann.

<?php

$pfad = '/var/www/uploads/bilder';

if (!is_dir($pfad)) {
echo 'Pfad ist kein Verzeichnis: ' . $pfad;
return;
}

if (!is_readable($pfad)) {
echo 'Keine Leseberechtigung für: ' . $pfad;
return;
}

$handle = opendir($pfad);
/* Ab hier ist sicher, dass das
Verzeichnis geoeffnet werden kann */
?>

Fehlerbehandlung mit set_error_handler

Alternativ kann ein eigener Error-Handler gesetzt werden, der die Warning von opendir() abfängt und in eine Exception umwandelt. Das ermöglicht eine saubere Fehlerbehandlung mit try/catch.

<?php

function verzeichnisAuslesen(string $pfad): array
{
set_error_handler(function ($errno, $msg) {
throw new RuntimeException($msg);
});

try {
$handle = opendir($pfad);
$dateien = [];

while (($e = readdir($handle)) !== false) {
if ($e !== '.' && $e !== '..') {
$dateien[] = $e;
}
}
closedir($handle);

return $dateien;
} catch (RuntimeException $e) {
return [];
} finally {
restore_error_handler();
}
}

$ergebnis = verzeichnisAuslesen('/tmp/test');
echo count($ergebnis) . ' Einträge gefunden.';
?>

Der finally-Block stellt sicher, dass der ursprüngliche Error-Handler wiederhergestellt wird, egal ob ein Fehler aufgetreten ist oder nicht.

Dateitypen unterscheiden: is_file() und is_dir()

Wenn ein Verzeichnis sowohl Dateien als auch Unterverzeichnisse enthält, müssen die Einträge oft nach Typ getrennt werden. readdir() gibt nur den Namen zurück, nicht den Typ. Dafür werden is_file() und is_dir() benötigt.

<?php

$pfad = __DIR__ . '/projekte';
$handle = opendir($pfad);

$dateien = [];
$ordner = [];

while (($eintrag = readdir($handle)) !== false) {
if ($eintrag === '.' || $eintrag === '..') {
continue;
}

$vollpfad = $pfad . '/' . $eintrag;

if (is_file($vollpfad)) {
$dateien[] = $eintrag;
} elseif (is_dir($vollpfad)) {
$ordner[] = $eintrag;
}
}
closedir($handle);

echo count($ordner) . ' Ordner, '
. count($dateien) . ' Dateien';
?>

Wichtig ist, dass is_file() und is_dir() den vollständigen Pfad erwarten, nicht nur den Dateinamen. Ohne die Verknüpfung mit dem Verzeichnispfad würden die Funktionen im aktuellen Arbeitsverzeichnis suchen und falsche Ergebnisse liefern.

Rekursive Verzeichnissuche mit opendir()

Bevor es die SPL-Iteratoren gab, musste man für eine rekursive Suche eine eigene Funktion schreiben. Das folgende Beispiel zeigt, wie alle Dateien in einem Verzeichnis einschliesslich aller Unterverzeichnisse gefunden werden.

<?php

function dateienSammeln(
string $pfad,
string $endung = ''
): array {
$ergebnis = [];
$handle = opendir($pfad);

if ($handle === false) {
return $ergebnis;
}

while (($e = readdir($handle)) !== false) {
if ($e === '.' || $e === '..') {
continue;
}

$vollpfad = $pfad . '/' . $e;

if (is_dir($vollpfad)) {
/* Rekursiver Aufruf */
$ergebnis = array_merge(
$ergebnis,
dateienSammeln($vollpfad, $endung)
);
} elseif ($endung === ''
|| str_ends_with($e, $endung)
) {
$ergebnis[] = $vollpfad;
}
}
closedir($handle);

return $ergebnis;
}

$phpDateien = dateienSammeln(__DIR__, '.php');
echo count($phpDateien) . ' PHP-Dateien';
?>

Diese manuelle Rekursion funktioniert, ist aber umständlich. Der weiter unten vorgestellte RecursiveDirectoryIterator löst dieselbe Aufgabe eleganter und mit weniger Code.

Verzeichnisinhalt als HTML-Liste ausgeben

Ein häufiger Anwendungsfall ist die Darstellung eines Verzeichnisinhalts als strukturierte HTML-Liste. Das folgende Beispiel unterscheidet zwischen Dateien und Ordnern und zeigt für jede Datei die Grösse und das letzte Änderungsdatum an.

<?php

function verzeichnisAlsListe(string $pfad): string
{
if (!is_readable($pfad)) {
return '<p>Verzeichnis nicht lesbar.</p>';
}

$eintraege = array_diff(
scandir($pfad), ['.', '..']
);

if (count($eintraege) === 0) {
return '<p>Verzeichnis ist leer.</p>';
}

$html = '<ul class="dateiliste">';

foreach ($eintraege as $name) {
$voll = $pfad . '/' . $name;

if (is_dir($voll)) {
$html .= '<li class="ordner">'
. htmlspecialchars($name)
. '/</li>';
} else {
$kb = round(filesize($voll) / 1024, 1);
$datum = date('d.m.Y', filemtime($voll));
$html .= '<li>'
. htmlspecialchars($name)
. ' <small>(' . $kb . ' KB, '
. $datum . ')</small></li>';
}
}

$html .= '</ul>';
return $html;
}

echo verzeichnisAlsListe(__DIR__ . '/downloads');
?>

Die Funktion gibt einen fertigen HTML-String zurück, der direkt in eine Seite eingebettet werden kann. Ordner werden mit einem abschliessenden Schrägstrich gekennzeichnet, Dateien mit Grössen- und Datumsangabe.

Performance bei grossen Verzeichnissen

Bei Verzeichnissen mit mehreren tausend Dateien wird die Wahl der Methode relevant. scandir() lädt alle Einträge auf einmal in den Speicher und sortiert sie. Bei 100.000 Dateien kann das mehrere Megabyte RAM verbrauchen. opendir() mit readdir() verarbeitet die Einträge dagegen einzeln und verbraucht konstant wenig Speicher.

In der Praxis ist der Unterschied aber nur bei wirklich grossen Verzeichnissen spürbar. Bei weniger als 1.000 Einträgen ist scandir() fast immer die bessere Wahl, weil der Code kürzer und lesbarer ist. Erst wenn der Speicherverbrauch zum Problem wird oder die Dateien während des Lesens verarbeitet werden sollen (zum Beispiel bei einem Stream-Export), lohnt sich der Griff zu opendir().

Ein Tipp für scandir() in Hochlast-Szenarien: Der dritte Parameter SCANDIR_SORT_NONE überspringt die Sortierung und ist dadurch schneller. Wenn die Reihenfolge nicht wichtig ist, kann dieser Parameter den Aufruf deutlich beschleunigen.

<?php

/* Sortiert (Standard) */
$sortiert = scandir('/var/www/uploads');

/* Unsortiert (schneller bei vielen Dateien) */
$unsortiert = scandir(
'/var/www/uploads',
SCANDIR_SORT_NONE
);
?>

Sortierung der Ergebnisse

Ein Detail, das viele Entwickler überrascht: readdir() gibt die Einträge in der Reihenfolge zurück, in der sie im Dateisystem gespeichert sind. Das ist nicht alphabetisch sortiert. Die Reihenfolge hängt vom Dateisystem ab (ext4, NTFS, etc.) und kann sich bei jedem Aufruf unterscheiden.

Für eine sortierte Ausgabe müssen die Einträge zuerst in einem Array gesammelt und anschliessend sortiert werden:

<?php

$verzeichnis = __DIR__ . '/dokumente';
$handle = opendir($verzeichnis);
$dateien = [];

while (($eintrag = readdir($handle)) !== false) {
if ($eintrag === '.' || $eintrag === '..') {
continue;
}
$dateien[] = $eintrag;
}
closedir($handle);

/* Alphabetisch sortieren (Gross/Klein ignorieren) */
natcasesort($dateien);

foreach ($dateien as $datei) {
echo $datei . PHP_EOL;
}
?>

natcasesort() sortiert natürlich und ignoriert die Gross- und Kleinschreibung. Das bedeutet, dass bild10.jpg nach bild2.jpg einsortiert wird, nicht davor. Für eine rein alphabetische Sortierung kann stattdessen sort() verwendet werden.

scandir() als einfachere Alternative

Für die meisten Anwendungsfälle ist scandir() die bessere Wahl. Die Funktion kombiniert das Öffnen, Lesen und Schliessen in einem einzigen Aufruf und gibt direkt ein sortiertes Array zurück.

<?php

/* opendir-Variante: 10 Zeilen */
$handle = opendir('/var/www/uploads');
$dateien = [];
while (($e = readdir($handle)) !== false) {
if ($e !== '.' && $e !== '..') {
$dateien[] = $e;
}
}
closedir($handle);

/* scandir-Variante: 1 Zeile */
$dateien = array_diff(
scandir('/var/www/uploads'), ['.', '..']
);
?>

scandir() akzeptiert als zweiten Parameter die Sortierreihenfolge: SCANDIR_SORT_ASCENDING (Standard), SCANDIR_SORT_DESCENDING oder SCANDIR_SORT_NONE (unsortiert, dafür schneller bei grossen Verzeichnissen).

Wann ist opendir() trotzdem sinnvoll? Bei sehr grossen Verzeichnissen mit tausenden Dateien verbraucht scandir() mehr Speicher, weil es alle Einträge auf einmal in ein Array lädt. Mit opendir() und readdir() können die Einträge einzeln verarbeitet werden, ohne das gesamte Verzeichnis im Speicher halten zu müssen.

Moderne Alternativen: glob() und SPL-Iteratoren

PHP bietet neben den klassischen Verzeichnisfunktionen auch modernere Werkzeuge, die je nach Aufgabe komfortabler oder leistungsfähiger sind.

glob() für Pattern-basierte Suche

glob() durchsucht ein Verzeichnis nach Dateien, die einem bestimmten Muster entsprechen. Das ist besonders praktisch, wenn nur bestimmte Dateitypen gesucht werden.

<?php

/* Alle PHP-Dateien im aktuellen Verzeichnis */
$phpDateien = glob(__DIR__ . '/*.php');

/* Alle Bilder (mehrere Endungen) */
$bilder = glob(
__DIR__ . '/uploads/*.{jpg,png,webp,gif}',
GLOB_BRACE
);

echo count($bilder) . ' Bilder gefunden.';
?>

Im Gegensatz zu scandir() gibt glob() die vollständigen Pfade zurück, nicht nur die Dateinamen. Die Pseudo-Einträge . und .. werden automatisch herausgefiltert.

FilesystemIterator für objektorientiertes Arbeiten

Der FilesystemIterator aus der SPL-Bibliothek bietet eine objektorientierte Schnittstelle zum Durchlaufen von Verzeichnissen. Jeder Eintrag ist ein SplFileInfo-Objekt mit nützlichen Methoden wie getSize(), getExtension() oder isFile().

<?php

$iterator = new FilesystemIterator(
__DIR__ . '/uploads',
FilesystemIterator::SKIP_DOTS
);

foreach ($iterator as $info) {
if ($info->isFile()) {
echo $info->getFilename()
. ' (' . $info->getSize() . ' Bytes)'
. PHP_EOL;
}
}
?>

Das Flag SKIP_DOTS sorgt dafür, dass . und .. automatisch übersprungen werden.

RecursiveDirectoryIterator für Unterverzeichnisse

Wenn alle Dateien in einem Verzeichnis einschliesslich aller Unterverzeichnisse gefunden werden sollen, ist der RecursiveDirectoryIterator die sauberste Lösung. Er durchläuft die gesamte Verzeichnisstruktur rekursiv, ohne dass eine eigene Rekursion programmiert werden muss.

<?php

$verzeichnis = __DIR__ . '/projekt';

$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$verzeichnis,
FilesystemIterator::SKIP_DOTS
)
);

$phpDateien = [];
foreach ($iterator as $info) {
if ($info->getExtension() === 'php') {
$phpDateien[] = $info->getPathname();
}
}

echo count($phpDateien) . ' PHP-Dateien gefunden.';
?>

Vergleich: Welche Funktion wann?

Die folgende Übersicht hilft bei der Wahl der richtigen Funktion für die jeweilige Aufgabe:

FunktionLiefertSortiertRekursivIdeal für
opendir()/readdir()Einzelne NamenNeinNeinSehr grosse Verzeichnisse, Stream-Verarbeitung
scandir()Array mit NamenJaNeinEinfaches Auflisten aller Einträge
glob()Array mit PfadenJaNeinDateien nach Muster filtern (*.php, *.jpg)
FilesystemIteratorSplFileInfo-ObjekteNeinNeinOOP-Stil, Metadaten pro Datei
RecursiveDirectoryIteratorSplFileInfo-ObjekteNeinJaGesamte Verzeichnisbäume durchsuchen

Praxisbeispiel: Bildergalerie aus einem Verzeichnis

Das folgende Beispiel zeigt, wie alle Bilder eines Upload-Ordners als HTML-Galerie ausgegeben werden. Es kombiniert glob() für die Dateisuche mit filesize() und getimagesize() für die Metadaten.

<?php

$uploadDir = __DIR__ . '/uploads/bilder';

if (!is_dir($uploadDir) || !is_readable($uploadDir)) {
echo '<p>Bildverzeichnis nicht verfügbar.</p>';
return;
}

$bilder = glob(
$uploadDir . '/*.{jpg,jpeg,png,webp,gif}',
GLOB_BRACE
);

if (count($bilder) === 0) {
echo '<p>Keine Bilder gefunden.</p>';
return;
}

/* Nach Aenderungsdatum sortieren (neueste zuerst) */
usort($bilder, function ($a, $b) {
return filemtime($b) - filemtime($a);
});

echo '<div class="galerie">';
foreach ($bilder as $pfad) {
$name = basename($pfad);
$groesse = round(filesize($pfad) / 1024);
$abmessungen = getimagesize($pfad);
$breite = $abmessungen[0] ?? 0;
$hoehe = $abmessungen[1] ?? 0;

echo '<figure>';
echo '<img src="uploads/bilder/'
. htmlspecialchars($name) . '" '
. 'alt="' . htmlspecialchars($name)
. '" loading="lazy">';
echo '<figcaption>'
. htmlspecialchars($name)
. ' (' . $breite . 'x' . $hoehe
. ', ' . $groesse . ' KB)</figcaption>';
echo '</figure>';
}
echo '</div>';
?>

Sicherheit: Directory Traversal verhindern

Wenn Benutzereingaben in Verzeichnispfade einfliessen, besteht die Gefahr eines Directory-Traversal-Angriffs. Ein Angreifer könnte über Eingaben wie ../../etc/passwd auf Systemdateien zugreifen, die ausserhalb des vorgesehenen Verzeichnisses liegen.

<?php

/* UNSICHER: Benutzereingabe direkt im Pfad */
$ordner = $_GET['ordner'] ?? '';
$pfad = '/var/www/uploads/' . $ordner;
/* Ein Angreifer koennte ?ordner=../../etc senden */

/* SICHER: Pfad mit realpath() validieren */
$basisPfad = realpath('/var/www/uploads');
$angefragterPfad = realpath(
'/var/www/uploads/' . $ordner
);

if ($angefragterPfad === false
|| strpos($angefragterPfad, $basisPfad) !== 0
) {
die('Ungültiger Pfad.');
}

/* Jetzt ist sicher, dass der Pfad
innerhalb von /var/www/uploads liegt */
$dateien = scandir($angefragterPfad);
?>

realpath() löst alle .. und Symlinks auf und gibt den tatsächlichen absoluten Pfad zurück. Durch den anschliessenden Vergleich mit dem Basispfad wird sichergestellt, dass der Benutzer nur auf Dateien innerhalb des erlaubten Verzeichnisses zugreifen kann. Zusätzlich kann basename() verwendet werden, um nur den Dateinamen ohne Pfadbestandteile zu extrahieren.

Log-Dateien auflisten und nach Datum sortieren

Ein weiteres Praxisbeispiel: Alle Log-Dateien eines Verzeichnisses nach ihrem letzten Änderungsdatum sortiert auflisten.

<?php

$logDir = __DIR__ . '/logs';

if (!is_readable($logDir)) {
die('Log-Verzeichnis nicht lesbar.');
}

$logDateien = glob($logDir . '/*.log');

/* Nach Aenderungsdatum sortieren (neueste zuerst) */
usort($logDateien, function ($a, $b) {
return filemtime($b) - filemtime($a);
});

echo '<table>';
echo '<tr><th>Datei</th><th>Grösse</th>'
. '<th>Letzte Änderung</th></tr>';

foreach ($logDateien as $log) {
$name = basename($log);
$kb = round(filesize($log) / 1024, 1);
$datum = date('d.m.Y H:i', filemtime($log));

echo '<tr>';
echo '<td>' . htmlspecialchars($name)
. '</td>';
echo '<td>' . $kb . ' KB</td>';
echo '<td>' . $datum . '</td>';
echo '</tr>';
}
echo '</table>';
?>

Versteckte Dateien und Systemdateien

Unter Linux beginnen versteckte Dateien mit einem Punkt, zum Beispiel .htaccess oder .gitignore. Sowohl readdir() als auch scandir() geben diese Dateien zurück. glob() hingegen überspringt versteckte Dateien standardmässig. Um auch versteckte Dateien mit glob() zu finden, muss ein spezielles Muster verwendet werden.

<?php

$pfad = __DIR__;

/* glob() findet KEINE versteckten Dateien */
$normal = glob($pfad . '/*');

/* Versteckte Dateien separat suchen */
$versteckt = glob($pfad . '/.[!.]*');

/* Alles zusammen */
$alle = array_merge($normal, $versteckt);

echo count($normal) . ' normale Dateien, '
. count($versteckt) . ' versteckte Dateien';
?>

Das Muster /.[!.]* bedeutet: ein Punkt, gefolgt von einem Zeichen das kein Punkt ist, gefolgt von beliebigen weiteren Zeichen. Dadurch werden . und .. ausgeschlossen, aber Dateien wie .htaccess gefunden.

Unter Windows gibt es kein einheitliches Konzept für versteckte Dateien auf Dateinamensebene. Stattdessen wird das Hidden-Attribut im Dateisystem gesetzt. PHP kann dieses Attribut nicht direkt abfragen. Wer unter Windows versteckte Dateien filtern muss, kann auf den Befehl attrib über exec() zurückgreifen, was in den meisten Webanwendungen aber nicht nötig ist.

Dateien nach Endung filtern

Ein sehr häufiges Szenario ist das Filtern nach Dateiendungen. Während glob() dafür bereits ein Pattern bietet, muss bei opendir() oder scandir() die Endung manuell geprüft werden.

<?php

$pfad = __DIR__ . '/uploads';
$erlaubteEndungen = ['jpg', 'png', 'webp', 'pdf'];

$gefilterteDateien = array_filter(
array_diff(scandir($pfad), ['.', '..']),
function ($datei) use ($erlaubteEndungen) {
$endung = strtolower(
pathinfo($datei, PATHINFO_EXTENSION)
);
return in_array($endung, $erlaubteEndungen);
}
);

foreach ($gefilterteDateien as $datei) {
echo $datei . PHP_EOL;
}
?>

Die Funktion pathinfo() mit dem Flag PATHINFO_EXTENSION extrahiert die Dateiendung zuverlässig, auch bei Dateinamen mit mehreren Punkten wie backup.2024.tar.gz. Die Kombination mit strtolower() stellt sicher, dass auch Dateien mit Grossbuchstaben-Endungen wie .JPG oder .PDF gefunden werden.

Häufige Fragen zu Verzeichnisoperationen

Warum gibt readdir() die Einträge unsortiert zurück?

readdir() liest die Einträge in der Reihenfolge, in der sie physisch im Dateisystem gespeichert sind. Das hat nichts mit dem Dateinamen oder dem Erstellungsdatum zu tun. Die Reihenfolge hängt vom Dateisystem ab: Unter ext4 (Linux) werden Einträge oft nach Hash sortiert, unter NTFS (Windows) alphabetisch. Wer eine definierte Reihenfolge braucht, muss die Ergebnisse nach dem Einlesen explizit sortieren.

Muss closedir() aufgerufen werden?

Technisch wird das Handle am Script-Ende automatisch freigegeben. In der Praxis sollte closedir() aber immer explizit aufgerufen werden. Bei Scripts, die viele Verzeichnisse nacheinander öffnen, können sonst Dateideskriptoren knapp werden. Ausserdem macht der explizite Aufruf den Code lesbarer, weil deutlich wird, wo die Arbeit mit dem Verzeichnis endet.

Kann man mit opendir() auch FTP-Verzeichnisse lesen?

Ja, wenn die PHP-Extension ftp aktiviert ist und allow_url_fopen auf On steht, kann opendir() auch FTP-Verzeichnisse öffnen. In der Praxis ist das aber langsam und fehleranfällig. Für FTP-Operationen sind die dedizierten FTP-Funktionen wie ftp_nlist() die bessere Wahl.

Was ist der Unterschied zwischen scandir() und glob()?

scandir() gibt alle Einträge eines Verzeichnisses zurück, einschliesslich . und ... Es sortiert das Ergebnis automatisch. glob() dagegen filtert nach einem Muster (z.B. *.php), gibt vollständige Pfade zurück und überspringt . und .. automatisch. Wenn alle Dateien eines Verzeichnisses benötigt werden, ist scandir() die richtige Wahl. Wenn nur bestimmte Dateitypen gesucht werden, ist glob() komfortabler.

Wie prüft man, ob ein Wert in einem Array vorkommt?

Wenn die gesammelten Dateinamen nach einem bestimmten Eintrag durchsucht werden sollen, bietet PHP die Funktion in_array(). Sie prüft, ob ein Wert in einem Array existiert, und gibt true oder false zurück.

Zusammenfassung

PHP bietet verschiedene Wege, um Verzeichnisse zu öffnen und deren Inhalt auszulesen. Die klassische Kombination aus opendir(), readdir() und closedir() gibt maximale Kontrolle über den Lesevorgang und eignet sich besonders für sehr grosse Verzeichnisse, bei denen der Speicherverbrauch eine Rolle spielt.

Für den Alltag ist scandir() meist die pragmatischere Wahl, weil es das Öffnen, Lesen und Schliessen in einer Zeile erledigt. glob() ist ideal, wenn nur bestimmte Dateitypen gesucht werden. Und die SPL-Iteratoren wie FilesystemIterator und RecursiveDirectoryIterator bieten den modernsten und flexibelsten Ansatz, insbesondere wenn Metadaten pro Datei benötigt werden oder ganze Verzeichnisbäume durchsucht werden sollen.

Unabhängig von der gewählten Methode sollten Verzeichnispfade immer vor der Verwendung geprüft werden, zum Beispiel mit is_readable(). Und wenn Benutzereingaben in Pfade einfliessen, ist die Validierung mit realpath() Pflicht, um Directory-Traversal-Angriffe zu verhindern.

 

Tags:

 

Bücherregal mit drei Büchern: 'PHP 4 - Grundlagen und Profiwissen' von Hanser Verlag, 'Webdesign in a Nutshell' von O'Reilly Verlag, und 'Webgestaltung' von Galileo Computing.