I am writing a disk catalogue application in PHP. My script loops over directories, storing all filenames and metadata in a database. There are certain directories I do not want to travel down. I want the iterator to simply return the names of those directories as though they are files, then move onto the next sibling. I have implemented a RecursiveCallbackFilterIterator that allows omitting directories based on a matching filename pattern:
$filter = array(".app");
$files = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator(
$zpath,
RecursiveDirectoryIterator::SKIP_DOTS
),
function ($current, $key, $iterator) use ($filter) {
$match = 0;
foreach ($filter as $skip) {
if (substr($current->getBaseName(), -4, 4) == $skip) {
$match = 1;
}
}
if ($match) {
return false;
} else {
return true;
}
}
),
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
foreach ($files as $splFileInfo) {
$path = $splFileInfo->getRealPath();
echo $path."\n";
}
My question is, how do I modify this code so that directories matching the pattern are included in the result set, but not returned to the iterator for further traversal?
So far, all examples of RecursiveCallbackFilterIterator I've found show some variation on the above (eg, omit certain files or directories). I simply want to return the directory name if it matches the pattern, then move on to the next sibling.
In other words, I need to turn this:
File1.txt
File2.txt
Folder1/
Folder1/FileA.txt
Folder1/FileB.txt
MyThing.app/
MyThing.app/Contents/
Mything.app/Contents/Manifest.plist
Mything.app/Menu.nib
Portfolio.zip
Zee.txt
Into this:
File1.txt
File2.txt
Folder1/
Folder1/FileA.txt
Folder1/FileB.txt
MyThing.app
Portfolio.zip
Zee.txt
I've created an eval.in to test this, though on this env I cannot create Directories, so I've testet only with files, but should work the same with dir too.
file_put_contents("./file2.txt", "test");
file_put_contents("./Zee.txt", "test");
file_put_contents("./fileA.txt", "test");
file_put_contents("./fileB.txt", "test");
file_put_contents("./manifest.plist", "test");
file_put_contents("./manifest.app", "test");
file_put_contents("./MyApp.app", "test");
file_put_contents("./Menu.nib", "test");
$zpath=realpath("./");
$filter = array(".app");
$appFolders =array();
$files = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator(
$zpath,
RecursiveDirectoryIterator::SKIP_DOTS
),
function ($current, $key, $iterator) use ($filter) {
foreach ($filter as $skip) {
preg_match_all("(".$skip.")", $current->getRealPath(), $result);
if (!empty($result[0])) {
$GLOBALS["appFolders"][] =$current->getRealPath();
return false;
}
}
return true;
}
),
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
echo "\nFiles:\n";
foreach ($files as $splFileInfo) {
$path = $splFileInfo->getRealPath();
echo $path."\n";
}
echo "\nAppFolders:\n";
foreach ($appFolders as $app){
echo $app."\n";
}
And the output is:
Files:
/tmp/execpad-4917ea112c86/file2.txt
/tmp/execpad-4917ea112c86/input-4917ea112c86
/tmp/execpad-4917ea112c86/manifest.plist
/tmp/execpad-4917ea112c86/Menu.nib
/tmp/execpad-4917ea112c86/output-4917ea112c86
/tmp/execpad-4917ea112c86/fileA.txt
/tmp/execpad-4917ea112c86/fileB.txt
/tmp/execpad-4917ea112c86/Zee.txt
/tmp/execpad-4917ea112c86/source-4917ea112c86
AppFolders:
/tmp/execpad-4917ea112c86/MyApp.app
/tmp/execpad-4917ea112c86/manifest.app