Мне еще предстоит найти хороший пример того, как использовать php RegexIterator для рекурсивного прохождения каталога.
Конечным результатом будет то, что я хочу указать каталог и найти все файлы в нем с некоторыми заданными расширениями. Скажем, например, только расширения html / php. Кроме того, я хочу отфильтровать папки такого типа .Trash-0, .Trash-500 и т. Д.
<?php $Directory = new RecursiveDirectoryIterator("/var/www/dev/"); $It = new RecursiveIteratorIterator($Directory); $Regex = new RegexIterator($It,'/^.+\.php$/i',RecursiveRegexIterator::GET_MATCH); foreach($Regex as $v){ echo $value."<br/>"; } ?>
Это то, что у меня есть до сих пор, но приводит к: Неустранимая ошибка: исключить исключение «UnexpectedValueException» с сообщением «RecursiveDirectoryIterator :: __ construct (/media/hdmovies1/.Trash-0)
Какие-либо предложения?
Есть несколько разных способов сделать что-то вроде этого, я дам вам два быстрых подхода: быстро и грязно, по сравнению с более длинными и менее грязными (хотя это пятница, так что нам разрешено идти немного сумасшедший).
1. Быстрый (и грязный)
Это включает в себя просто запись регулярного выражения (может быть разделено на несколько) для использования для фильтрации коллекции файлов одним быстрым махом.
(Только две прокомментированные строки действительно важны для этой концепции.)
$directory = new RecursiveDirectoryIterator(__DIR__); $flattened = new RecursiveIteratorIterator($directory); // Make sure the path does not contain "/.Trash*" folders and ends eith a .php or .html file $files = new RegexIterator($flattened, '#^(?:[AZ]:)?(?:/(?!\.Trash)[^/]+)+/[^/]+\.(?:php|html)$#Di'); foreach($files as $file) { echo $file . PHP_EOL; }
Этот подход имеет ряд проблем, хотя быстро реализовать его можно всего лишь одним слоем (хотя регулярное выражение может быть болью для расшифровки).
2. Менее быстрые (и менее грязные)
Более подходящий подход заключается в создании нескольких фильтров на заказ (с использованием регулярных выражений или любого другого, что вам нравится!), Чтобы уничтожить список доступных элементов в исходном RecursiveDirectoryIterator
вплоть до тех, которые вы хотите. Ниже приведен только один пример, быстро написанный для вас, о расширении RecursiveRegexIterator
.
Мы начинаем с базового класса, основной задачей которого является сохранение регулярного выражения, с которым мы хотим отфильтровать, все остальное откладывается обратно к RecursiveRegexIterator
. Обратите внимание, что класс является abstract
поскольку он фактически не делает ничего полезного: фактическая фильтрация должна выполняться двумя классами, которые будут расширять этот. Кроме того, он может быть назван FilesystemRegexFilter
но нет ничего, что вынуждало бы (на этом уровне) фильтровать связанные с файловой системой классы (я бы выбрал лучшее имя, если бы я не был настолько сонным).
abstract class FilesystemRegexFilter extends RecursiveRegexIterator { protected $regex; public function __construct(RecursiveIterator $it, $regex) { $this->regex = $regex; parent::__construct($it, $regex); } }
Эти два класса – это очень простые фильтры, действующие соответственно на имя файла и имя каталога.
class FilenameFilter extends FilesystemRegexFilter { // Filter files against the regex public function accept() { return ( ! $this->isFile() || preg_match($this->regex, $this->getFilename())); } } class DirnameFilter extends FilesystemRegexFilter { // Filter directories against the regex public function accept() { return ( ! $this->isDir() || preg_match($this->regex, $this->getFilename())); } }
Чтобы применить их на практике, следующие повторяются по содержимому каталога, в котором находится скрипт (не стесняйтесь редактировать это!) И отфильтровываете папки .Trash
(чтобы убедиться, что имена папок соответствуют специально созданному регулярному выражению) , и принимает только файлы PHP и HTML.
$directory = new RecursiveDirectoryIterator(__DIR__); // Filter out ".Trash*" folders $filter = new DirnameFilter($directory, '/^(?!\.Trash)/'); // Filter PHP/HTML files $filter = new FilenameFilter($filter, '/\.(?:php|html)$/'); foreach(new RecursiveIteratorIterator($filter) as $file) { echo $file . PHP_EOL; }
Особо следует отметить, что, поскольку наши фильтры рекурсивные, мы можем поиграть с тем, как их перебирать. Например, мы можем легко ограничиться только сканированием до двух уровней (включая начальную папку), выполнив:
$files = new RecursiveIteratorIterator($filter); $files->setMaxDepth(1); // Two levels, the parameter is zero-based. foreach($files as $file) { echo $file . PHP_EOL; }
Кроме того, очень легко добавлять еще больше фильтров (путем создания дополнительных классов фильтрации с различными регулярными выражениями или путем создания новых классов фильтрации) для более специализированных задач фильтрации (например, размер файла, длина полного пути и т. Д.).
PS Хмм, этот ответ немного болтает; Я старался держать его как можно более кратким (даже удаляя огромные кусочки супер-лепет). Извиняюсь, если чистый результат оставляет ответ некогерентным.
Документы действительно не очень полезны. Существует проблема с использованием регулярного выражения для «не соответствует» здесь, но сначала проиллюстрируем рабочий пример:
<?php //we want to iterate a directory $Directory = new RecursiveDirectoryIterator("/var/dir"); //we need to iterate recursively $It = new RecursiveIteratorIterator($Directory); //We want to stop decending in directories named '.Trash[0-9]+' $Regex1 = new RecursiveRegexIterator($It,'%([^0-9]|^)(?<!/.Trash-)[0-9]*$%'); //But, still continue on doing it **recursively** $It2 = new RecursiveIteratorIterator($Regex1); //Now, match files $Regex2 = new RegexIterator($It2,'/\.php$/i'); foreach($Regex2 as $v){ echo $v."\n"; } ?>
Проблема в том, что она не соответствует .Trash[0-9]{3}
part: Единственный способ, которым я знаю, как отрицательно соответствовать каталогу, соответствует концу строки $
, а затем утверждать с помощью lookbehind (?<!/foo)
', если ему не предшествует' / foo '.
Однако, поскольку .Trash[0-9]{1,3}
не является фиксированной длиной, мы не можем использовать его как утверждение lookbehind. К сожалению, нет никакого инвертированного соответствия для RegexIterator. Но, возможно, есть больше людей, которые хорошо разбираются в регулярных выражениях, тогда я знаю, как сопоставить «любую строку, не заканчивающуюся на .Trash[0-9]+
edit : получил это '%([^0-9]|^)(?<!/.Trash-)[0-9]*$%'
поскольку регулярное выражение сделало бы трюк.
Улучшение salathe, было бы забыть о пользовательском абстрактном классе. Просто используйте хороший ООП в PHP и вместо этого прямо создайте рекурсивныйRegexIterator:
Вот фильтр файлов
class FilenameFilter extends RecursiveRegexIterator { // Filter files against the regex public function accept() { return ! $this->isFile() || parent::accept(); } }
И фильтр Directory
class DirnameFilter extends RecursiveRegexIterator { // Filter directories against the regex public function accept() { return ! $this->isDir() || parent::accept(); } }