- PHP: список файлов и директорий
- Базовые решения
- Использование glob()
- Используем opendir() , readdir() , и closedir() .
- Использование scandir()
- Воспользуемся итераторами SPL
- FilesystemIterator
- Поиск файлов в PHP
- Поиск в директории
- Список всех файлов и директорий
- Результат:
- Только файлы
- Результат:
- Только директории
- Результат:
- Поиск по расширению
- Результат:
- Поиск по нескольким расширениям
- Результат:
- Поиск по имени файла
- Результат:
- Результат:
- Поиск в дереве
- Список всех файлов
- Результат:
- Список всех директорий
- Результат:
- Поиск по имени/расширению
- Результат:
PHP: список файлов и директорий
В данном уроке мы разберемся с типовой задачей, которая возникает во время работы над проектом PHP: получение списка файлов и директорий. Обсудим несколько базовых и более изощренных подходов, с перечисление плюсов и минусов каждого. Первые три решения будут использовать типовые функции PHP, а затем представим более надежное с применением итераторов SPL.
Для предметного обсуждения решения и демонстраций предположим, что структура директорий имеет следующий вид:
\---manager | \---user | \---document.txt | \---data.dat | \---style.css |---article.txt |---master.dat |---script.php |---test.dat |---text.txt
Базовые решения
Первый набор решений основан на использовании функции glob() , комбинации функций opendir() , readdir() и closedir() , и также функции scandir() .
Использование glob()
Первое решение базируется на использовании функции glob(), которая позволяет выполнять поиск пути с помощью шаблонов. Функция имеет два параметра:
- $pattern (обязательный): шаблон поиска
- $flags (опциональный): один или несколько флагов, описание которых можно найти в документации
Рассмотрим примеры. Для поиска в директории всех файлов и директорий, имена которых заканчиваются на .txt, следует использовать код:
Если вывести переменную $filelist , то получим:
array ( 0 => 'article.txt', 1 => 'text.txt' )
Если нужен список файлов и директорий, имена которых начинаются на “te”, то код будет выглядеть так:
array ( 0 => 'test.dat', 1 => 'text.txt' )
А для получения списка только директорий с именами, содержащих “ma”, используем код:
Обратите внимание, что в последнем примере использован флаг GLOB_ONLYDIR в качестве второго параметра функции. Поэтому файл master.dat исключен из списка. Хотя функция glob() очень проста в использовании, иногда она недостаточно гибкая. Например, нет флага для получения только файлов (без директорий), которые соответствуют шаблону.
Используем opendir() , readdir() , и closedir() .
Второй подход к получению списка файлов и директорий, который мы обсудим, заключается в использовании функций opendir() , readdir() , и closedir() .
Функция opendir() открывает директорию и возвращает дескриптор соединения. Как только дескриптор получен, можно использовать функцию readdir() . С каждым обращением данная функция выдает имя следующего файла или директории внутри открытого каталога. Если все имена уже были перечислены, функция возвращает false. Для закрытия дескриптора используется функция closedir() .
В отличие от использования функции glob() , данный подход сложнее, так как у вас нет параметров, которые помогают фильтровать список возвращаемых имен файлов и директорий. Вы должны выполнить фильтрацию самостоятельно, чтобы получить нужный результат.
Ниже приведенный пример возвращает список имен файлов и директорий начинающихся на “te”:
При выполнении выше приведенного кода, переменная $entry будет содержать такие включения, как “.” и “..”. Это две виртуальные директории, которые имеются в каждом каталоге файловой системы. Они представляют текущий каталог и родительский каталог соответственно.
Второй пример выводит только файлы, содержащиеся в заданном каталоге.
array ( 0 => 'article.txt', 1 => 'master.dat', 2 => 'script.php', 3 => 'test.dat', 4 => 'text.txt' )
Использование scandir()
В завершение представим функцию scandir() . Она имеет только один обязательный параметр: путь для чтения. Функция возвращает массив файлов и директорий, расположенных по указанному пути. Для получения списка файлов и директорий по определенному критерию нужно выполнить дополнительную фильтрацию. С другой стороны, решение получается более кратким и не требует управления дескрипторами.
Данный пример показывает, как получить список файлов и каталогов, имена которых начинаются на “te”:
Воспользуемся итераторами SPL
Теперь рассмотрим использование итераторов SPL. Но прежде, чем приступить к решению нашей задачи, проведем введение в библиотеку SPL и итераторы. Библиотека SPL предоставляет серию классов для объектно ориентированных структур данных, итераторов, дескрипторов файлов и прочее.
Одно из преимуществ итераторов заключается в том, что они являются классами и их можно расширить для удовлетворения собственных нужд. Другой плюс состоит в том, что итераторы имеют собственные методы, которые являются полезными при решении множества типовых задач и располагаются в одном месте. Посмотрите на пример использования FilesystemIterator в сравнении с readdir() . Оба метода применяют цикл, но в случае readdir() вы обрабатываете только строку, а FilesystemIterator работает с объектом, который может содержать дополнительную информацию о файле или директории (размер, владелец, права доступа и так далее).
Конечно, PHP представляет возможность для получения такой информации с помощью функций,например filesize() и fileowner(). Но PHP5 основан на использовании концепции ООП. Поэтому лучше использовать современные методы работы с языком программирования. На нашем сайте есть уроки, посвященные работе с итераторами.
Как уже сообщалось во водной части урока, мы рассмотрим использование FilesystemIterator , RecursiveDirectoryIterator и GlobIterator . Первый наследуется от DirectoryIterator , а остальные от FilesystemIterator . Они все имеют один и тот же конструктор, который принимает два параметра:
- $path (обязательный): путь к пункту файловой системы, над которым совершаются операции
- $flags (опциональный): один или несколько флагов, перечисленных в документации
Реальное различие в данных итераторах заключается в их использовании для навигации по заданному пути.
FilesystemIterator
Использовать FilesystemIterator очень просто. Рассмотрим в действии. Представляем два примера. Первый показывает поиск всех файлов и каталогов, имена которых начинаются на “te”. Второй пример использует другой итератор RegexIterator для поиска всех файлов и каталогов, имена которых заканчиваются на “t.dat” или “t.php”. Итератор RegexIterator используется для фильтрации результата на основе регулярных выражений.
getFilename(), "te") === 0) < $filelist[] = $entry->getFilename(); > >
Выше приведенный код выдаст результат, аналогичный предыдущим примерам.
Второй пример с применением RegexIterator :
Поиск файлов в PHP
Для поиска файлов на сервере хорошо подходит функция glob(), которая возвращает список файлов по заданной маске, например:
В маске можно использовать следующие специальные символы:
* | Соответствует нулю или большему количеству любых символов. |
? | Один любой символ. |
[. ] | Один символ входящий в группу. |
[. ] | Один символ не входящий в группу. |
Вхождение подстрок, работает с флагом GLOB_BRACE . | |
\ | Экранирует следующий символ, кроме случаев, когда используется флаг GLOB_NOESCAPE . |
GLOB_MARK | Добавляет слеш к каждой возвращаемой директории. |
GLOB_NOSORT | Возвращает файлы в том виде, в котором они содержатся в директории (без сортировки). Если этот флаг не указан, то имена сортируются по алфавиту. |
GLOB_NOCHECK | Возвращает шаблон поиска, если с его помощью не был найден ни один файл. |
GLOB_NOESCAPE | Обратные слеши не экранируют метасимволы. |
GLOB_BRACE | Раскрывает для совпадения с « a », « b » или « c ». |
GLOB_ONLYDIR | Возвращает только директории, совпадающие с шаблоном. |
GLOB_ERR | Останавливается при ошибках чтения (например, директории без права чтения), по умолчанию ошибки игнорируются. |
Возможно использовать несколько флагов:
$files = glob('/tmp/*.jpg', GLOB_NOSORT|GLOB_ERR);
Далее во всех примерах используется папка tmp со следующим содержимым:
Поиск в директории
Список всех файлов и директорий
$dir = __DIR__ . '/tmp'; $files = array(); foreach(glob($dir . '/*') as $file) < $files[] = basename($file); >print_r($files);
Результат:
Array ( [0] => 1.svg [1] => 2.jpg [2] => 22-f.gif [3] => 22.svg [4] => img.png [5] => path [6] => prod.png [7] => style-1.txt [8] => style-2.css )
Только файлы
$dir = __DIR__ . '/tmp'; $files = array(); foreach(glob($dir . '/*') as $file) < if (is_file($file)) < $files[] = basename($file); >> print_r($files);
Результат:
Array ( [0] => 1.svg [1] => 2.jpg [2] => 22-f.gif [3] => 22.svg [4] => img.png [5] => prod.png [6] => style-1.txt [7] => style-2.css )
Только директории
$dir = __DIR__ . '/tmp'; $files = array(); foreach(glob($dir . '/*') as $file) < if (is_dir($file)) < $files[] = basename($file); >> print_r($files);
Результат:
Поиск по расширению
$dir = __DIR__ . '/tmp'; $files = array(); foreach(glob($dir . '/*.svg') as $file) < $files[] = basename($file); >print_r($files);
Результат:
Поиск по нескольким расширениям
$dir = __DIR__ . '/tmp'; $files = array(); foreach(glob($dir . '/*.', GLOB_BRACE) as $file) < $files[] = basename($file); >print_r($files);
Результат:
Array ( [0] => 2.jpg [1] => img.png [2] => prod.png )
Поиск по имени файла
$dir = __DIR__ . '/tmp'; $files = array(); foreach(glob($dir . '/style*.*') as $file) < $files[] = basename($file); >print_r($files);
Результат:
Array ( [0] => style-1.txt [1] => style-2.css )
$dir = __DIR__ . '/tmp'; $files = array(); foreach(glob($dir . '/2*.*', GLOB_BRACE) as $obj) < $files[] = basename($obj); >print_r($files);
Результат:
Array ( [0] => 1.svg [1] => 2.jpg [2] => 22-f.gif [3] => 22.svg )
Поиск в дереве
Список всех файлов
function glob_tree_files($path, $_base_path = null) < if (is_null($_base_path)) < $_base_path = ''; >else < $_base_path .= basename($path) . '/'; >$out = array(); foreach(glob($path . '/*') as $file) < if (is_dir($file)) < $out = array_merge($out, glob_tree_files($file, $_base_path)); >else < $out[] = $_base_path . basename($file); >> return $out; > $dir = __DIR__ . '/tmp'; $files = glob_tree_files($dir); print_r($files);
Результат:
Array ( [0] => 1.svg [1] => 2.jpg [2] => 22-f.gif [3] => 22.svg [4] => img.png [5] => path/icon-rew.png [6] => path/marker.png [7] => path/psd/1.psd [8] => path/psd/2.psd [9] => path/psd/index.psd [10] => path/sh-1.png [11] => path/title-1.png [12] => prod.png [13] => style-1.txt [14] => style-2.css )
Список всех директорий
function glob_tree_dirs($path, $_base_path = null) < if (is_null($_base_path)) < $_base_path = ''; >else < $_base_path .= basename($path) . '/'; >$out = array(); foreach(glob($path . '/*', GLOB_ONLYDIR) as $file) < if (is_dir($file)) < $out[] = $_base_path . basename($file); $out = array_merge($out, glob_tree_dirs($file, $_base_path)); >> return $out; > $dir = __DIR__ . '/tmp'; $files = glob_tree_dirs($dir); print_r($files);
Результат:
Array ( [0] => path [1] => path/psd )
Поиск по имени/расширению
function glob_tree_search($path, $pattern, $_base_path = null) < if (is_null($_base_path)) < $_base_path = ''; >else < $_base_path .= basename($path) . '/'; >$out = array(); foreach(glob($path . '/' . $pattern, GLOB_BRACE) as $file) < $out[] = $_base_path . basename($file); >foreach(glob($path . '/*', GLOB_ONLYDIR) as $file) < $out = array_merge($out, glob_tree_search($file, $pattern, $_base_path)); >return $out; > $path = __DIR__ . '/tmp'; $files = glob_tree_search($path, '*.'); print_r($files);
Результат:
Array ( [0] => 2.jpg [1] => img.png [2] => prod.png [3] => path/icon-rew.png [4] => path/marker.png [5] => path/sh-1.png [6] => path/title-1.png )
Чтобы в результирующих списках выводились полные пути к файлам, достаточно удалить функцию basename() .