У меня есть этот код PHP:
$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>"; } }
Это отображает мою структуру каталогов и вставляет каталоги и имена файлов в базу данных (удаление первых двух символов ..
).
Поскольку RecursiveDirectoryIterator
выполняет итерацию по всем файлам во всех каталогах, как я могу исключить целые каталоги, включая все файлы внутри них?
По сути, мой ответ не сильно отличается от ответа Томаса . Тем не менее, он не получает несколько правильных вещей:
RecursiveCallbackFilterIterator
требует, чтобы вы возвращали значение true
для рекурсии в подкаталоги. .
и ..
каталоги внутри каждого подкаталога in_array
не совсем делает то, что он ожидает Итак, я написал этот ответ. Это будет работать правильно, предполагая, что я понимаю, чего вы хотите:
Изменить: с тех пор он исправил 2 из этих трех вопросов; третья не может быть проблемой из-за того, как он написал свой условный чек, но я не совсем уверен.
<?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 }
Я предлагаю использовать 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) { //... }
Мое предложение – попробовать использовать библиотеку поиска Symfony, так как это намного облегчает и легко устанавливается через композитор, вот документы
http://symfony.com/doc/current/components/finder.html
и вот простой пример чего-то похожего на то, что, я думаю, вы просите
<?php use Symfony\Component\Finder\Finder; /** * @author Clark Tomlinson <fallen013@gmail.com> * @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>'; }
Этот пример вернет все каталоги, не пересекая их, чтобы изменить это изменение или удалить глубину.
Чтобы все файлы в этом каталоге делали что-то похожее на это
<?php use Symfony\Component\Finder\Finder; /** * @author Clark Tomlinson <fallen013@gmail.com> * @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>'; } }
Я бы сохранил это проще, с некоторыми базовыми функциями php, легко читаемыми (не тридцатью, не делегациями для других объектов), и этими несколькими строками.
Во-первых, вы создаете функцию, которая получает каталог, который вы хотите изучить, и необязательный массив или исключенные имена файлов
function getFiles($dir , $exclude=array()){ $acceptedfiles=array(); $handle=opendir($dir ); //reads the filenames, one by one while ($file = readdir($handle)) { if ($file!="." && $file!=".." && is_file($file) && !in_array($file, $exclude)) $acceptedfiles[]=$file; } closedir($handle); return $acceptedfiles; }
Теперь вам просто нужно вызвать функцию
$files= getFiles($rootpath) ;
или если вы хотите исключить некоторые файлы, если они существуют, вы можете позвонить
$files= getFiles($rootpath, array(".htaccess","otherfile", "etc")) ;
Вы можете использовать RecursiveFilterIterator для фильтрации dirs, а в петле fooreach вы только принимаете 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 }
Я бы сделал это так:
$excludes = array( 'files' => array('file1.ext','file2.ext','fileN.ext'), 'dirs' => array('dir1','dir2','dirN') ); foreach ($directories as $current_dir) { if (!in_array($current_dir,$excludes['dirs'])) { // directory method foreach ($files as $current_file) { if (!in_array($current_file,$excludes['files'])) { // files method } } } }
Если я правильно догадаюсь, вы просто хотите добавить базовый путь для файлов, а не для каталога.
Просто используйте для проверки функцию is_file
в вашем foreach
Например
foreach ($fileinfos as $pathname => $fileinfo) { if (!is_file($pathname)) { continue;// next step } $pathname2 = substr($pathname,2); ... }