Списки файлов и директорий на PHP

Прочитать список файлов и поддиректорий, находящихся по заданному пути можно с помощью трех основных встроенных функций PHP: scandir(), glob() и readdir(). Каждая из этих функций полезна по своему и применять их нужно в зависимости от поставленной задачи. Методы использования и отличия в функциях PHP scandir(), glob() и readdir() и будут рассмотрены ниже.

Glob

Получить список файлов и директорий на PHP можно с помощью встроенной функции PHP glob(). Официальная документация использования функции glob() находится тут.

Список файлов и всех поддиректорий
$path = 'my_dir';
$result = glob($path.'/*');
print_r($result);

В результате выполнения функции glob() будет получен массив, содержащий все каталоги и почти все файлы, заданной в переменной $path директории, без элементов ".", ".." (точка - указывает на текущую директорию, две точки - предыдущая директория), которые, к примеру, будут прочитаны при использовании функции readdir() или scandir(). Почти все, а не все файлы будут получены потому, что шаблон "*" не включает файлы, начинающиеся с символа точки, например: .htaccess. Чтобы получить список всех файлов - можно использовать шаблон с константой, опубликованные ниже:

Список ВСЕХ файлов и всех поддиректорий
$result = glob('my_dir/{,.}*', GLOB_BRACE);

При использовании шаблона {,.} будут показаны не только файлы, начинающиеся с точки, но и директории-точки (точка и две точки, если есть вышестоящая директория) - при необходимости их нужно дополнительно отфильтровать, например при помощи условного оператора if().

Вообще, функция glob() существует для поиска файлов и директорий, в соответствии с заданным шаблоном. То есть с ее помощью лучше искать, например, все файлы с расширением jpg. Казалось бы, нет ничего проще: указываем шаблон *.jpg и ищем, но если расширение файла написано не только прописными буквами, например Jpg, то в регистрозависимых файловых системах, таких, как в операционных системах FreeBSD, Linux и подобных, это задание вызовет некоторые трудности. Пример, задания регистронезависимого поиска по шаблону - нужно найти все файлы, с расширением jpg, JPG, jPG и подобные:

Регистронезависимый поиск по шаблону
$result = glob('my_dir/*/number?/*.[jJ][pP][gG]');

Более подробнее про синтаксис шаблона glob() можно прочитать тут: "Основы Linux от основателя Gentoo. Glob-подстановки".

Если порядок сортировки файлов и директорий на выходе функции glob() не важен - необходимо использовать константу GLOB_NOSORT. В этом случае функция будет работать заметно быстрее.

Scandir

Встроенная функция scandir() добавлена в PHP версии 5 и выше. Как и glob(), scandir() возвращает массив с данными о файлах и каталогах по заданному пути, вот только для scandir() задается точный путь - шаблоны в нем применить не удастся. Официальная документация по scandir() расположена тут.

Readdir

С помощью функции readdir() также можно просмотреть список файлов и директорий по заданному пути. Вот только для неё необходима специальная обертка. Актуальную информацию по использованию readdir() можно посмотреть в официальной документации PHP тут.

Не смотря на то, что для использования readdir() необходимо использовать больше строк кода, в некоторых случаях её применение остается актуальным. Прочитав статью на сайте lab.ixblogs.com можно выяснить, что скорость работы readdir() выше, чем у аналогичных функций PHP.

Примеры использования функций

Список поддиректорий и файлов

С помощью функции bfglob() можно записать пути всех директорий, поддиректорий и файлов, находящихся в них, в одномерный массив. Эта функция взята из официальной документации по PHP из комментариев к странице с описанием glob() и немного усовершенствована. Эта функция не использует рекурсию - применен простой, но полностью рабочий механизм с использованием функций по работе с массивами.

// $path - путь к директории
// $pattern - шаблон поиска
// $flags - константа для функции glob()
// $depth - глубина вложенности, просматриваемая функцией. -1 - без ограничений.
function bfglob($path, $pattern = '*', $flags = GLOB_NOSORT, $depth = 0)
  {
  $matches = array();
  $folders = array(rtrim($path, DIRECTORY_SEPARATOR));

  while($folder = array_shift($folders))
    {
    $matches = array_merge($matches, glob($folder.DIRECTORY_SEPARATOR.$pattern, $flags));
    if($depth != 0)
      {
      $moreFolders = glob($folder.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR);
      $depth   = ($depth < -1) ? -1: $depth + count($moreFolders) - 2;
      $folders = array_merge($folders, $moreFolders);
      }
    }
  return $matches;
  }
 
$file = bfglob('my_dir', "*", GLOB_NOSORT, -1);
print_r($file);

Стоит обратить внимание, на константу DIRECTORY_SEPARATOR, использующуюся в функции bfglob(). Эта константа хранит символ, разделяющий директории, для операционной системы, под управлением которой запущен скрипт: например Linux понимает только "/", Windows, по умолчанию использует разделитель директорий "\", но понимает и "/". Если функция bfglob() будет запускаться из под различных операционных систем, с последующим хранением результатов работы - желательно заменить константу DIRECTORY_SEPARATOR на символ "/", чтобы избежать проблем с несовместимостью путей.

Рекурсивное удаление файлов и директорий

Как удалить не пустую директорию с использованием PHP? Ниже - пример двух функций, которые извлекают списки путей ко всем файлам и директориям. Отличия от пользовательской функции bfglob() - на выходе пути к директориям и файлам лежат в разных ячейках массива и подсчитывается общий объем занимаемого файлами места. Если раскомментировать unlinc() и rmdir() - будут также удалены все файлы, по заданному пути. ВНИМАНИЕ: перед тем, как запустить процесс удаления файлов и директорий следует несколько раз проверить, что вы собираетесь удалить именно то, что нужно!

$dir = 'MyDir';
function remove_all_g($dir, $result = array())
  {
  if ($paths = glob($dir.'/*', GLOB_NOSORT))
    {
    foreach($paths as $path)
      {
      if (is_dir($path))
        {
        $result = remove_all_g($path, $result);
        }
      else
        {
        $result['path']['file'][] = $path;
        $result['counter_filesize'] += filesize($path);
        //unlink($path);
        }
      }
    }
  $result['path']['dir'][] = $dir;
  //rmdir($dir);
  return $result;
  }
print_r(remove_all_g($dir));


function remove_all_sd($dir, $result = array())
  {
  if ($paths = array_diff(scandir($dir), array('..', '.')))
    {
    foreach($paths as $path)
      {
      if (is_dir($dir.'/'.$path))
        {
        $result = remove_all_sd($dir.'/'.$path, $result);
        }
      else
        {
        $result['path']['file'][] = $dir.'/'.$path;
        $result['counter_filesize'] += filesize($dir.'/'.$path);
        // unlink($dir.'/'.$path);
        }
      }
    }
  $result['path']['dir'][] = $dir;
  // rmdir($dir);
  return $result;
  }
print_r(remove_all_sd($dir));

Функция remove_all_g() для чтения содержимого директории применяется glob(), в remove_all_sd() - scandir(). При работе с 10 000 файлов, расположенных в 200 директориях различного уровня вложенности, функция remove_all_sd() отрабатывала, приблизительно на 20% быстрее.

Также, функция remove_all_g() не обнаруживает файлы, начинающиеся с точки, а если добавить ей эту функциональность - работать она будет еще медленнее.

Вывод: функцию glob() для рекурсивного чтения файлов, директорий и поддиректорий следует использовать только на PHP ниже 5 версии, во всех остальных случаях, выбор между функциями glob() и scandir() очевиден.

Опубликовано: 2012/04/30
HTML-код ссылки на эту страницу:
<a href="http://petrenco.com/php.php?txt=133" target="_blank">Списки файлов и директорий на PHP</a>
23305
Комментарии
Может кому пригодится, писал как-то для сайта. В $dirname передаёте путь к директории. В $result[] формируется массив из файлов с полным путём:
[code]
class UploadAnalize {

public function ListFilesDirectory($dirname){
static $result = array();
$handle = opendir($dirname);

while (($file = readdir($handle)) !== false)
{
if($file != "." && $file != "..")
{
if(is_file($dirname."/".$file))
{
$result[] = substr($dirname, 3)."/".$file;
}
// Если директория
if(is_dir($dirname."/".$file))
{
$this -> ListFilesDirectory($dirname."/".$file);
}
}
}

closedir($handle);
return $result;
}
}
[/code]
Добавить комментарий
Ваш e-mail: (не виден посетителям сайта)
Ваше имя:
Комментарий:
Символы с картинки:
Только выделенные поля формы добавления комментариев обязательны к заполнению.