Как рекурсивно перебирать файлы в PHP?

Я установил базовый script, который отправляет массив путей для поиска файлов шаблонов внутри них; в настоящее время он только ищет два уровня в глубину, и у меня возникают проблемы, связанные с логикой для расширенного цикла для итерации всех дочерних каталогов до тех пор, пока длина не будет равна 0.

Итак, если у меня есть такая структура:

./components
./components/template.html
./components/template2.html
./components/side/template.html
./components/side/template2.html
./components/side/second/template.html
./components/side/second/template2.html
./components/side/second/third/template.html
./components/side/second/third/template2.html

Он ищет только в "боковом" каталоге .html файлов, когда я в идеале хочу, чтобы он проверял все дочерние каталоги и переданный каталог для файлов .html. Вот мой рабочий код:

<?php
function getFiles($path){
    $dh  = opendir($path);
    foreach(glob($path.'/*.html') as $filename){
        $files[] = $filename;
    }
    if (isset($files)) {
        return $files;
    }
}
foreach ($_POST as $path) {
    foreach (glob($path . '/*' , GLOB_ONLYDIR) as $secondLevel) {
        $files[] = getFiles($secondLevel);
    }
    $files[] = getFiles($path);
}
sort($files);
print_r(json_encode($files));
?>

Ответ 1

PHP имеет идеальное решение для вас.

Пример

// Construct the iterator
$it = new RecursiveDirectoryIterator("/components");

// Loop through files
foreach(new RecursiveIteratorIterator($it) as $file) {
    if ($file->getExtension() == 'html') {
        echo $file;
    }
}

Ресурсы

Ответ 2

PHP 5 представляет итераторы для быстрого итерации по многим элементам.

Вы можете использовать RecursiveDirectoryIterator для повторной рекурсии через каталоги.

Вы можете использовать RecursiveIteratorIterator, чтобы результат был сглажен.

Вы можете использовать RegexIterator для фильтрации на основе регулярного выражения.

 $directory_iterator = new RecursiveDirectoryIterator('.');
 $iterator       = new RecursiveIteratorIterator($directory_iterator);
 $regex_iterator = new RegexIterator($iterator, '/\.php$/');
 $regex_iterator->setFlags(RegexIterator::USE_KEY);
 foreach ($regex_iterator as $file) {
    echo $file->getPathname() . PHP_EOL;
 }

С помощью итераторов существует много способов сделать то же самое, вы также можете использовать FilterIterator (см. пример на страница)

Например, если вы хотите выбрать файлы, измененные на этой неделе, вы можете использовать следующее:

  $directory_iterator = new RecursiveDirectoryIterator('.');
  $iterator       = new RecursiveIteratorIterator($directory_iterator);

  class CustomFilterIterator extends FilterIterator {
       function accept() {
            $current=$this->getInnerIterator()->current();
            return ($current->isFile()&&$current->getMTime()>time()-3600*24*7);
       }
  }

  $filter_iterator=new CustomFilterIterator($iterator);
  foreach ($filter_iterator as $file) {
     echo $file->getPathname() . PHP_EOL;
  }

Ответ 3

Другим решением является использование компонента Finder из Symfony. Это проверенный и проверенный код. Взгляните на это здесь: http://symfony.com/doc/current/components/finder.html

Ответ 4

Вот рабочий код, который сканирует данный каталог $dir и все его подкаталоги на любые уровни и возвращает список html файлов и папок, содержащих их.

<?php

function find_all_files($dir)
{

    if(!is_dir($dir)) return false;

    $pathinfo = '';


    $root = scandir($dir);

    foreach($root as $value)
    {
        if($value === '.' || $value === '..') {continue;}




        if(is_file("$dir/$value")) {

            $pathinfo = pathinfo($dir.'/'.$value);

            if($pathinfo['extension'] == 'html') {
                $result[]="$dir/$value";


            }

            continue;

        }

        foreach(find_all_files("$dir/$value") as $value)
        {

            $result[]=$value;

        }
    }

    return $result;

}

//call function
$res = find_all_files('physical path to folder'); 

print_r($res);

?>

Ответ 5

Универсальный поиск файлов в папке, вложенной папке:

function dirToArray($dir,$file_name) {
   $result = array();
   $cdir = scandir($dir);
   foreach ($cdir as $key => $value)
   {
      if (!in_array($value,array(".","..")))
      {
         if (is_dir($dir . DIRECTORY_SEPARATOR . $value))
         {
            $result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value,$file_name);
         }
         else
         {
            if($value == $file_name){
                $result[] = $value; 
            }
         }
      }
   }
   return $result;
}

define('ROOT', dirname(__FILE__));
$file_name = 'template.html';
$tree = dirToArray(ROOT,$file_name);
echo "<pre>".print_r($tree,1)."</pre>";

OUTPUT:

Array
(
    [components] => Array
        (
            [side] => Array
                (
                    [second] => Array
                        (
                            [0] => template.html
                            [third] => Array
                                (
                                    [0] => template.html
                                )

                        )

                    [0] => template.html
                )

            [0] => template.html
        )

    [0] => template.html
)

Ответ 6

Альтернатива моего предыдущего ответа:

$dir = 'components';
function getFiles($dir, &$results = array(), $filename = 'template.html'){
    $files = scandir($dir);
    foreach($files as $key => $value){
        $path = realpath($dir.'/'.$value);
        if(!is_dir($path)) {
            if($value == $filename)         
                $results[] = $path;         
        } else if($value != "." && $value != "..") {
            getFiles($path, $results);
        }
    }
    return $results;
}
echo '<pre>'.print_r(getFiles($dir), 1).'</pre>';

OUTPUT:

Array
(
    [0] => /web/practise/php/others/test7/components/side/second/template.html
    [1] => /web/practise/php/others/test7/components/side/second/third/template.html
    [2] => /web/practise/php/others/test7/components/side/template.html
    [3] => /web/practise/php/others/test7/components/template.html
)

Ответ 7

Вот общее решение:

function parseDir($dir, &$files=array(), $extension=false){

if(!is_dir($dir)){
    $info =  pathinfo($dir);
    // add all files if extension is set to false
    if($extension === false || (isset($info['extension']) && $info['extension'] === $extension)){
        $files[] = $dir;
    }
}else{
    if(substr($dir, -1) !== '.' && $dh =  opendir($dir)){
        while($file = readdir($dh)){
            parseDir("$dir/$file", $files, $extension);
        }
    }
}
 }

$files = array();
parseDir('components', $files, 'html');
var_dump($files);

ВЫХОД

php parseDir.php 
array(7) {
  [0]=>
  string(25) "components/template2.html"
  [1]=>
  string(29) "components/side/template.html"
  [2]=>
  string(30) "components/side/template2.html"
  [3]=>
  string(36) "components/side/second/template.html"
  [4]=>
  string(37) "components/side/second/template2.html"
  [5]=>
  string(42) "components/side/second/third/template.html"
  [6]=>
  string(43) "components/side/second/third/template2.html"
}