Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP List Directory structure and exclude some directories

Tags:

php

I have this PHP Code:

$rootpath = '../admin/';
$inner = new RecursiveDirectoryIterator($rootpath);
$fileinfos = new RecursiveIteratorIterator($inner);

foreach ($fileinfos as $pathname => $fileinfo)
{
    $pathname2 = substr($pathname,2);
    $sql = "SELECT * from admin_permissions where page_name = '$pathname2'";
    $rs = mysql_query($sql,$conn);
    if (mysql_num_rows($rs) == 0)
    {
        if (!$fileinfo->isFile()) continue;
        $sql2 = "INSERT into admin_permissions (page_name) values ('$pathname2')";
        $rs2 = mysql_query($sql2,$conn);
        echo "$pathname<br>";
    }
}

That is displaying my directory structure and inserting the directories and file names into a database (removing the first 2 characters ..).

Since the RecursiveDirectoryIterator iterates through all files in all directories, how can I exclude whole directories, including all files within them?

like image 955
charlie Avatar asked Nov 28 '13 11:11

charlie


5 Answers

In essence, my answer is not much different from Thomas' answer. However, he does not get a few things correct:

  • The semantics correct for the RecursiveCallbackFilterIterator require you to return true to recurse into subdirectories.
  • He doesn't skip the . and .. directories inside each sub-directory
  • His in_array check doesn't quite do what he expects

So, I wrote this answer instead. This will work correctly, assuming I understand what you want:

Edit: He has since fixed 2 of those three issues; the third may not be an issue because of the way he wrote his conditional check but I am not quite sure.

<?php

$directory = '../admin';

// Will exclude everything under these directories
$exclude = array('.git', 'otherDirToExclude');

/**
 * @param SplFileInfo $file
 * @param mixed $key
 * @param RecursiveCallbackFilterIterator $iterator
 * @return bool True if you need to recurse or if the item is acceptable
 */
$filter = function ($file, $key, $iterator) use ($exclude) {
    if ($iterator->hasChildren() && !in_array($file->getFilename(), $exclude)) {
        return true;
    }
    return $file->isFile();
};

$innerIterator = new RecursiveDirectoryIterator(
    $directory,
    RecursiveDirectoryIterator::SKIP_DOTS
);
$iterator = new RecursiveIteratorIterator(
    new RecursiveCallbackFilterIterator($innerIterator, $filter)
);

foreach ($iterator as $pathname => $fileInfo) {
    // do your insertion here
}
like image 199
Levi Morrison Avatar answered Nov 04 '22 09:11

Levi Morrison


I suggest using the RecursiveCallbackFilterIterator.

$directory = '../admin/';
$filter = array('.git');

$fileinfos = new RecursiveIteratorIterator(
  new RecursiveCallbackFilterIterator(
    new RecursiveDirectoryIterator(
      $directory,
      RecursiveDirectoryIterator::SKIP_DOTS
    ),
    function ($fileInfo, $key, $iterator) use ($filter) {
      return $fileInfo->isFile() || !in_array($fileInfo->getBaseName(), $filter);
    }
  )
);

foreach($fileinfos as $pathname => $fileinfo) {
  //...
}
like image 26
ThW Avatar answered Nov 04 '22 09:11

ThW


I feel that some of the other answers are good, but more verbose than they need to be. Here is a some simple code. My example only filters the .git directory, but you can easily expand it to other items:

<?php

$f_filter = fn ($o_file) => $o_file->getFilename() == '.git' ? false : true;
$o_dir = new RecursiveDirectoryIterator('.');
$o_filter = new RecursiveCallbackFilterIterator($o_dir, $f_filter);
$o_iter = new RecursiveIteratorIterator($o_filter);

foreach ($o_iter as $o_file) {
   echo $o_file->getPathname(), "\n";
}

https://php.net/class.recursivecallbackfilteriterator

like image 34
Zombo Avatar answered Nov 04 '22 09:11

Zombo


My suggestion is to try using Symfony's finder library as it makes alot of this much easier and is easily installed via composer here are the docs

http://symfony.com/doc/current/components/finder.html

and here is a simple example of something similar to what i think you're asking

<?php
use Symfony\Component\Finder\Finder;

/**
 * @author Clark Tomlinson  <[email protected]>
 * @since 12/6/13, 12:52 PM
 * @link http://www.clarkt.com
 * @copyright Clark Tomlinson © 2013
 *
 */

require_once('vendor/autoload.php');

$finder = new Finder();
$directories = $finder->directories()
                      ->in(__DIR__)
                      ->ignoreDotFiles(true)
                      ->exclude(array('one', 'two', 'three', 'four'))
                      ->depth(0);

foreach ($directories as $dir) {
    echo '<pre>';
    print_r($dir->getRealPath());
    echo '</pre>';
}

That example will return all directories without transversing into them to change that change or remove the depth.

To get all files in that directory do something similar to this

<?php
use Symfony\Component\Finder\Finder;

/**
 * @author Clark Tomlinson  <[email protected]>
 * @since 12/6/13, 12:52 PM
 * @link http://www.clarkt.com
 * @copyright Clark Tomlinson © 2013
 *
 */

require_once('vendor/autoload.php');

$finder = new Finder();
$directories = $finder->directories()
                      ->in(__DIR__)
                      ->ignoreDotFiles(true)
                      ->exclude(array('one', 'two', 'three', 'four'))
                      ->depth(0);

foreach ($directories as $dir) {
    $files = $finder->files()
                    ->ignoreDotFiles(true)
                    ->in($dir->getRealPath());

    foreach ($files as $file) {
        echo '<pre>';
        print_r($file);
        echo '</pre>';
    }
}
like image 28
Clark T. Avatar answered Nov 04 '22 09:11

Clark T.


You can use RecursiveFilterIterator to filter dirs and in fooreach loop you have only accepted dirs.

class MyDirFilter extends RecursiveFilterIterator {
    public function accept() {

        $excludePath = array('exclude_dir1', 'exclude_dir2');
        foreach($excludePath as $exPath){
            if(strpos($this->current()->getPath(), $exPath) !== false){
                return false;
            }
        }
        return true;

    }
}

$rootpath = '../admin/';
$dirIterator = new RecursiveDirectoryIterator($rootpath);
$filter   = new MyDirFilter($dirIterator);
$fileinfos   = new RecursiveIteratorIterator($filter);

foreach($fileinfos as $pathname => $fileinfo)
{
    // only accepted dirs in loop
}
like image 40
PKolos Avatar answered Nov 04 '22 08:11

PKolos