recursiveiterator — PHP RecursiveDirectoryIterator возвращает, но не просматривает соответствие каталогов & quot; x & quot;

Я пишу приложение каталога дисков на PHP. Мой скрипт зацикливается на каталогах, сохраняя все имена файлов и метаданные в базе данных. Есть определенные каталоги, по которым я не хочу путешествовать. Я хочу, чтобы итератор просто возвращал имена этих каталогов, как если бы они были файлами, а затем переходил к следующему брату. Я реализовал RecursiveCallbackFilterIterator, который позволяет пропускать каталоги на основе соответствующего шаблона имени файла:

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

У меня вопрос: как мне изменить этот код, чтобы каталоги, соответствующие шаблону, были включены в набор результатов, но не возвращались итератору для дальнейшего обхода?

До сих пор все примеры RecursiveCallbackFilterIterator, которые я обнаружил, показывают некоторые изменения в вышеприведенном (например, пропускают определенные файлы или каталоги). Я просто хочу вернуть имя каталога, если оно соответствует шаблону, а затем перейти к следующему брату.

Другими словами, мне нужно включить это:

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

В это:

File1.txt
File2.txt
Folder1/
Folder1/FileA.txt
Folder1/FileB.txt
MyThing.app
Portfolio.zip
Zee.txt

3

Решение

Я создал eval.in чтобы проверить это, хотя в этой среде я не могу создавать каталоги, поэтому я тестирую только с файлами, но также должен работать и с dir.

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

И вывод:

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
1

Другие решения

Благодаря ответу Эдвина я смог создать этот код, который отлично работает. Я думал, что поделюсь этим здесь в случае, если это будет полезно для кого-либо еще. Ключ был в том, что мне нужно было больше узнать о методах, доступных для splFileInfo, в частности Path. Проверяя путь, можно узнать, содержит ли подстановочный знак родитель, а не имя файла. Комбинируя это с fnmatch, мы можем догадаться, находится ли файл в нисходящем направлении от каталога «.app», и полностью пропустить эту ветвь, при этом все еще включая родительский. Спасибо Эдвин!

// Do not descend into matching directories
$wopt_nodescend = array("*.app", "*.sparsebundle");

// Ignore matching files and directories
$wopt_ignore = array(".DS_Store", "*.jdk");

$nodescended = 0;
$ignored = 0;
$files = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator(
$zpath,
RecursiveDirectoryIterator::SKIP_DOTS
),
function ($current, $key, $iterator) use ($wopt_ignore, $wopt_nodescend) {
global $nodescended, $ignored;
$clean = true;
if (is_array($wopt_ignore)) {
foreach ($wopt_ignore as $wildcard) {
if (fnmatch($wildcard, $current->getFilename())) {
$clean = false;
$ignored++;
echo "Skipping: ".$current->getFilename()."\n";
}
}
}
if (is_array($wopt_nodescend)) {
foreach ($wopt_nodescend as $wildcard) {
if (fnmatch($wildcard, $current->getPath())) {
$clean = false;
$nodescended++;
echo "Nodescending: ".$current->getFilename()."\n";
}
}
}
return $clean;
}
),
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
0

По вопросам рекламы [email protected]