Wer mit PHP auf dem Server arbeitet, muss früher oder später den Inhalt eines Verzeichnisses auslesen. Die Funktion scandir() liefert dafür ein Array mit allen Dateinamen und Verzeichnisnamen eines angegebenen Ordners zurück. Ob es darum geht, hochgeladene Bilder aufzulisten, Konfigurationsdateien zu durchsuchen oder eine Ordnerstruktur abzubilden: scandir() ist die erste Anlaufstelle. In diesem Tutorial werden Syntax, Parameter, typische Stolperfallen und fortgeschrittene Anwendungsfälle Schritt für Schritt erklärt.

Los geht es mit der grundlegenden Arbeitsweise der Funktion und dem Aufbau des zurückgegebenen Arrays.
Was macht scandir()?
Die Funktion scandir() liest ein Verzeichnis auf dem Server und gibt dessen Inhalt als indiziertes Array zurück. Jeder Eintrag im Array entspricht einem Dateinamen oder Ordnernamen innerhalb des angegebenen Pfads. Standardmäßig sortiert PHP die Einträge in aufsteigender alphabetischer Reihenfolge. Dabei werden auch die beiden speziellen Einträge . (aktuelles Verzeichnis) und .. (übergeordnetes Verzeichnis) mit aufgenommen. Schlägt das Auslesen fehl, gibt die Funktion false zurück.
<?php
$inhalt = scandir("/var/www/html/uploads");
print_r($inhalt);
/*
Array
(
[0] => .
[1] => ..
[2] => bild.jpg
[3] => dokument.pdf
[4] => notizen.txt
)
*/
Syntax und Parameter
Bevor scandir() in der Praxis eingesetzt wird, lohnt sich ein Blick auf die vollständige Signatur der Funktion.
<?php
scandir(
string $directory,
int $sorting_order = SCANDIR_SORT_ASCENDING,
?resource $context = null
);
Die Funktion akzeptiert drei Parameter, von denen zwei optional sind. Im Folgenden werden alle drei einzeln erläutert.
Verzeichnispfad
Der erste Parameter erwartet den Pfad zum Verzeichnis als String. Es kann sich um einen absoluten Pfad wie /var/www/html oder einen relativen Pfad wie ./uploads handeln. Der Pfad muss auf ein tatsächlich existierendes und lesbares Verzeichnis zeigen, andernfalls gibt scandir() den Wert false zurück.
Sortierreihenfolge
Der zweite Parameter steuert die Sortierung der zurückgegebenen Einträge. PHP stellt dafür drei Konstanten bereit: SCANDIR_SORT_ASCENDING sortiert alphabetisch aufsteigend und ist der Standardwert. SCANDIR_SORT_DESCENDING sortiert alphabetisch absteigend. SCANDIR_SORT_NONE überlässt die Reihenfolge dem Dateisystem und ist dadurch geringfügig schneller bei sehr großen Verzeichnissen.
Stream-Kontext
Der dritte Parameter nimmt einen optionalen Stream-Kontext entgegen, der mit stream_context_create() erzeugt wird. In der Praxis wird dieser Parameter selten benötigt. Er kommt zum Einsatz, wenn auf entfernte Verzeichnisse zugegriffen oder das Verhalten des zugrunde liegenden Streams angepasst werden soll.
Das folgende Diagramm zeigt den Ablauf von scandir() im Überblick.
flowchart TD
A["scandir() aufrufen"] --> B{"Verzeichnis existiert?"}
B -- "Nein" --> C["false Rückgabe"]
B -- "Ja" --> D["Einträge lesen"]
D --> E{"Sortierung?"}
E -- "ASCENDING" --> F["Aufsteigend"]
E -- "DESCENDING" --> G["Absteigend"]
E -- "NONE" --> H["Keine"]
F --> I["Array zurückgeben"]
G --> I
H --> I
Die Punkte-Einträge entfernen (. und ..)
In fast jedem Anwendungsfall stören die beiden Einträge . und .. im Ergebnis. Die Funktion array_diff() entfernt sie zuverlässig aus dem Array.
<?php
$verzeichnis = "/var/www/html/uploads";
$dateien = scandir($verzeichnis);
/* Punkte-Einträge entfernen */
$dateien = array_diff($dateien, [".", ".."]);
foreach ($dateien as $datei) {
echo $datei . "\n";
}
/*
bild.jpg
dokument.pdf
notizen.txt
*/
Alternativ lässt sich array_values() im Anschluss aufrufen, um die Array-Keys nach dem Entfernen wieder fortlaufend zu nummerieren.
Dateien und Ordner unterscheiden
Die Funktion scandir() liefert Dateinamen und Ordnernamen gleichermaßen zurück. Um beide Typen zu unterscheiden, kommen is_file() und is_dir() zum Einsatz. Dabei muss der vollständige Pfad zusammengesetzt werden.
<?php
$verzeichnis = "/var/www/html/projekt";
$eintraege = array_diff(scandir($verzeichnis), [".", ".."]);
$dateien = [];
$ordner = [];
foreach ($eintraege as $eintrag) {
$pfad = $verzeichnis . "/" . $eintrag;
if (is_file($pfad)) {
$dateien[] = $eintrag;
} elseif (is_dir($pfad)) {
$ordner[] = $eintrag;
}
}
echo "Dateien: " . implode(", ", $dateien) . "\n";
echo "Ordner: " . implode(", ", $ordner) . "\n";
/*
Dateien: index.php, style.css
Ordner: assets, includes
*/
Dateien nach Typ filtern
Häufig sollen nur Dateien mit einer bestimmten Endung aufgelistet werden. Eine Kombination aus scandir() und pathinfo() ermöglicht das Filtern nach Dateitypen.
<?php
$verzeichnis = "/var/www/html/uploads";
$eintraege = array_diff(scandir($verzeichnis), [".", ".."]);
$bilder = [];
foreach ($eintraege as $eintrag) {
$endung = strtolower(pathinfo($eintrag, PATHINFO_EXTENSION));
if (in_array($endung, ["jpg", "jpeg", "png", "gif", "webp"])) {
$bilder[] = $eintrag;
}
}
print_r($bilder);
/*
Array
(
[0] => foto.jpg
[1] => logo.png
[2] => banner.webp
)
*/
Verzeichnis rekursiv auslesen
Die Funktion scandir() liest nur eine einzelne Verzeichnisebene. Um auch alle Unterverzeichnisse zu erfassen, wird eine rekursive Funktion benötigt. Diese ruft sich selbst auf, sobald ein Unterordner gefunden wird.
<?php
function verzeichnisRekursiv(string $pfad): array
{
$ergebnis = [];
$eintraege = array_diff(scandir($pfad), [".", ".."]);
foreach ($eintraege as $eintrag) {
$vollpfad = $pfad . "/" . $eintrag;
if (is_dir($vollpfad)) {
/* Unterverzeichnis rekursiv auslesen */
$ergebnis = array_merge(
$ergebnis,
verzeichnisRekursiv($vollpfad)
);
} else {
$ergebnis[] = $vollpfad;
}
}
return $ergebnis;
}
$alleDateien = verzeichnisRekursiv("/var/www/html/projekt");
foreach ($alleDateien as $datei) {
echo $datei . "\n";
}
/*
/var/www/html/projekt/assets/style.css
/var/www/html/projekt/assets/script.js
/var/www/html/projekt/includes/config.php
/var/www/html/projekt/index.php
*/
Die Funktion sammelt alle Dateipfade in einem flachen Array. Ordner selbst werden nicht als Einträge aufgenommen, sondern dienen nur als Einstiegspunkt für die nächste Rekursionsebene.
Fehlerbehandlung
Wenn das angegebene Verzeichnis nicht existiert oder nicht lesbar ist, gibt scandir() den Wert false zurück und erzeugt eine Warnung. Eine saubere Fehlerbehandlung prüft den Rückgabewert, bevor mit dem Array gearbeitet wird.
<?php
$verzeichnis = "/var/www/html/unbekannt";
$inhalt = @scandir($verzeichnis);
if ($inhalt === false) {
echo "Fehler: Das Verzeichnis konnte nicht gelesen werden.\n";
} else {
$inhalt = array_diff($inhalt, [".", ".."]);
foreach ($inhalt as $eintrag) {
echo $eintrag . "\n";
}
}
Der @-Operator unterdrückt die von PHP erzeugte Warnung. Die eigentliche Fehlerbehandlung übernimmt die anschließende Prüfung auf false. In produktivem Code empfiehlt es sich, den Fehler zusätzlich zu protokollieren, etwa mit error_log().
Fazit
Die Funktion scandir() ist ein einfaches und zuverlässiges Werkzeug, um den Inhalt eines Verzeichnisses in PHP auszulesen. Mit array_diff() lassen sich die Punkte-Einträge entfernen, mit is_file() und is_dir() können Dateien und Ordner unterschieden werden. Für das Filtern nach Dateitypen bietet sich pathinfo() an. Rekursives Auslesen erfordert eine eigene Funktion, die sich bei jedem Unterverzeichnis selbst aufruft. Wer den Rückgabewert auf false prüft, ist auch bei fehlenden oder nicht lesbaren Verzeichnissen auf der sicheren Seite.