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?
In essence, my answer is not much different from Thomas' answer. However, he does not get a few things correct:
RecursiveCallbackFilterIterator
require you to return true
to recurse into subdirectories..
and ..
directories inside each sub-directoryin_array
check doesn't quite do what he expectsSo, 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
}
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) {
//...
}
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
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>';
}
}
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With