Simon Staton
Simon Staton

Reputation: 4505

How to recursively iterate through files in PHP?

I have set up a basic script that is posting an array of paths to find template files inside them; currently it's only searching two levels deep and I'm having some troubles getting my head around the logic for an extensive loop to iterate all child directories until the length is 0.

So if I have a structure like this:

./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

It's only searching up to the "side" directory for .html files when ideally I want it to check all child directories and the passed directory for .html files. Here is my working code so far:

<?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));
?>

Upvotes: 28

Views: 16860

Answers (7)

Peter
Peter

Reputation: 9113

PHP has the perfect solution for you built in.

Example

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

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

Resources

Upvotes: 65

N&#39;faly Kaba
N&#39;faly Kaba

Reputation: 677

Here is a generic solution:

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);

OUTPUT

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"
}

Upvotes: 0

trongd
trongd

Reputation: 283

Another solution is using Finder component from Symfony. It's tested and proven code. Take a look at it here: http://symfony.com/doc/current/components/finder.html

Upvotes: 3

Monty Khanna
Monty Khanna

Reputation: 1120

Alternative of my previous answer :

$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
)

Upvotes: 1

Monty Khanna
Monty Khanna

Reputation: 1120

Universal File search in folder, sub-folder :

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
)

Upvotes: 1

Alpesh Panchal
Alpesh Panchal

Reputation: 1713

Here is working code which scans given directory $dir and all of its sub directories to any levels and return list of html files and folders containing them.

<?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);

?>

Upvotes: 1

Adam
Adam

Reputation: 18807

PHP 5 introduces iterators to iterate quickly through many elements.

You can use RecursiveDirectoryIterator to iterate recursively through directories.

You can use RecursiveIteratorIterator on the result to have a flatten view of the result.

You can use RegexIterator on the result to filter based on a regular expression.

 $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;
 }

With iterators, there are lot of ways to do the same thing, you can also use a FilterIterator (see the example on the page)

For instance, if you want to select the files modified this week, you can use the following:

  $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;
  }

Upvotes: 10

Related Questions