scandir()
Подробное руководство по функции PHP scandir(): возвращаемые значения, сортировка, фильтрация и обработка ошибок.
Введение
Работа с директориями — неотъемлемая часть программирования на PHP: практически каждый скрипт резервного копирования, загрузчик файлов или обработчик ресурсов должен уметь просматривать содержимое папки. В этой статье мы подробно рассмотрим функцию PHP scandir(), которая читает содержимое директории за один вызов. Вы узнаете, что она возвращает, как сортировать и фильтровать результат, чем она отличается от glob(), и как безопасно обрабатывать ошибки.
Что такое scandir?
scandir() читает директорию и возвращает имена всех её элементов — файлов и поддиректорий — в виде плоского массива строк. Массив всегда включает два специальных элемента: . (текущая директория) и .. (родительская директория), поэтому их почти всегда нужно отфильтровать перед использованием результата.
Если директория не может быть прочитана, scandir() возвращает false и выдаёт предупреждение. Функция доступна начиная с PHP 4.3.0 и работает как на Unix-системах, так и на Windows.
Синтаксис
scandir(string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, ?resource $context = null): array|false| Параметр | Описание |
|---|---|
$directory | Путь к директории, которую нужно прочитать. Может быть абсолютным или относительным рабочей директории скрипта. |
$sorting_order | Порядок сортировки результата: SCANDIR_SORT_ASCENDING (по умолчанию, A→Z), SCANDIR_SORT_DESCENDING (Z→A) или SCANDIR_SORT_NONE (порядок файловой системы — самый быстрый, без сортировки). |
$context | Необязательный ресурс контекста потока (редко используется; нужен для пользовательских обёрток потоков). |
Функция возвращает массив имён файлов в случае успеха или false в случае ошибки.
Имена возвращаются без пути к директории. Чтобы получить рабочий путь, добавьте директорию самостоятельно:
$directory . '/' . $entry.
Как работает scandir?
В простейшем виде достаточно передать только путь к директории. Содержимое возвращается в алфавитном порядке (по возрастанию), поскольку это значение $sorting_order по умолчанию. Пример ниже фильтрует . и .. с помощью array_diff(), чтобы оставить только реальные элементы:
Пример использования функции scandir() в PHP
<?php
$dir = "/path/to/directory";
$files = scandir($dir);
// Filter out the current and parent directory entries
$filtered = array_diff($files, ['.', '..']);
foreach ($filtered as $file) {
echo $file . "<br>";
}Этот код выводит список файлов и поддиректорий в указанной директории, исключая . и ...
Сортировка содержимого директории
Передайте второй аргумент для управления порядком результата. Доступны три варианта:
SCANDIR_SORT_ASCENDING— алфавитный порядок A→Z (по умолчанию).SCANDIR_SORT_DESCENDING— алфавитный порядок Z→A.SCANDIR_SORT_NONE— без сортировки; элементы возвращаются в том порядке, который предоставляет файловая система. Это самый быстрый вариант, и его стоит использовать, если вы всё равно собираетесь сортировать список самостоятельно или когда порядок не важен.
Например, для директории, содержащей archive.txt, data.csv, report.txt, notes.md, image.png и поддиректорию backups:
Как отсортировать вывод scandir() в порядке убывания
<?php
$dir = "/path/to/directory";
$files = scandir($dir, SCANDIR_SORT_DESCENDING);
print_r($files);
// Array
// (
// [0] => report.txt
// [1] => notes.md
// [2] => image.png
// [3] => data.csv
// [4] => backups
// [5] => ..
// [6] => .
// )Те же данные с SCANDIR_SORT_NONE возвращаются без сортировки (точный порядок зависит от файловой системы), что позволяет избежать небольших накладных расходов на сортировку.
Получение только файлов (или только директорий)
scandir() возвращает файлы и папки вперемешку. Чтобы оставить только файлы, проверьте каждый элемент с помощью is_file(); чтобы оставить только директории — используйте is_dir(). Не забудьте сначала построить полный путь:
<?php
$dir = "/path/to/directory";
$entries = array_diff(scandir($dir), ['.', '..']);
$filesOnly = array_filter($entries, fn($entry) => is_file($dir . '/' . $entry));
print_r(array_values($filesOnly));
// Array
// (
// [0] => archive.txt
// [1] => data.csv
// [2] => image.png
// [3] => notes.md
// [4] => report.txt
// )Фильтрация по расширению файла
Распространённая задача — получить только файлы определённого типа. Совместите scandir() с pathinfo() для чтения расширения каждого элемента:
<?php
$dir = "/path/to/directory";
$entries = array_diff(scandir($dir), ['.', '..']);
$textFiles = array_filter(
$entries,
fn($entry) => pathinfo($entry, PATHINFO_EXTENSION) === 'txt'
);
print_r(array_values($textFiles));
// Array
// (
// [0] => archive.txt
// [1] => report.txt
// )Если вам нужно только совпадение файлов по шаблону, glob() справится с этим за один шаг — например, glob("$dir/*.txt") — и вернёт полные пути. Используйте glob() для поиска по шаблону и scandir(), когда нужны все элементы и полный контроль над фильтрацией.
Обработка ошибок
Функция scandir может завершиться с ошибкой, если указанный путь к директории недействителен или у директории нет соответствующих прав доступа. В случае ошибки она возвращает false и вызывает предупреждение. Исключения не выбрасываются, поэтому следует проверять возвращаемое значение напрямую. Пример:
Пример использования функции scandir() в PHP с обработкой ошибок
<?php
$dir = "/path/to/directory";
$files = scandir($dir);
if ($files === false) {
echo "Error: Could not read the directory.";
} else {
foreach ($files as $file) {
echo $file . "<br>";
}
}Этот код проверяет возвращаемое значение scandir() и выводит сообщение об ошибке, если директория не может быть прочитана. Поскольку scandir() вызывает предупреждение (а не исключение) при ошибке, строгая проверка === false — это то, что реально защищает ваш код, а подавление предупреждения с помощью @scandir() не рекомендуется, так как вы теряете диагностическое сообщение.
Чтобы полностью избежать предупреждения, убедитесь, что путь является читаемой директорией перед вызовом scandir():
<?php
$dir = "/path/to/directory";
if (is_dir($dir)) {
$files = scandir($dir);
foreach (array_diff($files, ['.', '..']) as $file) {
echo $file . "<br>";
}
} else {
echo "Error: '$dir' is not a valid directory.";
}scandir() vs другие функции для работы с директориями
| Функция | Возвращает | Лучше всего для |
|---|---|---|
scandir() | Массив всех имён элементов сразу | Получение полного списка за один вызов с последующей фильтрацией/сортировкой |
glob() | Полные пути, соответствующие шаблону | Поиск по шаблону, например *.jpg |
opendir() + readdir() | Дескриптор директории, читаемый по одному элементу | Очень большие директории, когда не нужно загружать весь список в память |
Обзор более широкого набора инструментов см. в разделе Работа с директориями в PHP.
Заключение
Функция scandir() — это удобный способ прочитать содержимое директории в PHP за один вызов. Вы узнали, как перечислять элементы, сортировать их с помощью трёх констант SCANDIR_SORT_*, оставлять только файлы или только директории, фильтровать по расширению и безопасно обрабатывать ошибки. Используйте scandir(), когда нужен полный список и полный контроль; используйте glob(), когда достаточно простого поиска по шаблону.