[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 namespace Symfony\Component\Finder; 13 14 use Symfony\Component\Finder\Comparator\DateComparator; 15 use Symfony\Component\Finder\Comparator\NumberComparator; 16 use Symfony\Component\Finder\Iterator\CustomFilterIterator; 17 use Symfony\Component\Finder\Iterator\DateRangeFilterIterator; 18 use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator; 19 use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator; 20 use Symfony\Component\Finder\Iterator\FilecontentFilterIterator; 21 use Symfony\Component\Finder\Iterator\FilenameFilterIterator; 22 use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator; 23 use Symfony\Component\Finder\Iterator\SortableIterator; 24 25 /** 26 * Finder allows to build rules to find files and directories. 27 * 28 * It is a thin wrapper around several specialized iterator classes. 29 * 30 * All rules may be invoked several times. 31 * 32 * All methods return the current Finder object to allow chaining: 33 * 34 * $finder = Finder::create()->files()->name('*.php')->in(__DIR__); 35 * 36 * @author Fabien Potencier <fabien@symfony.com> 37 */ 38 class Finder implements \IteratorAggregate, \Countable 39 { 40 const IGNORE_VCS_FILES = 1; 41 const IGNORE_DOT_FILES = 2; 42 43 private $mode = 0; 44 private $names = []; 45 private $notNames = []; 46 private $exclude = []; 47 private $filters = []; 48 private $depths = []; 49 private $sizes = []; 50 private $followLinks = false; 51 private $sort = false; 52 private $ignore = 0; 53 private $dirs = []; 54 private $dates = []; 55 private $iterators = []; 56 private $contains = []; 57 private $notContains = []; 58 private $paths = []; 59 private $notPaths = []; 60 private $ignoreUnreadableDirs = false; 61 62 private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg']; 63 64 public function __construct() 65 { 66 $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES; 67 } 68 69 /** 70 * Creates a new Finder. 71 * 72 * @return static 73 */ 74 public static function create() 75 { 76 return new static(); 77 } 78 79 /** 80 * Restricts the matching to directories only. 81 * 82 * @return $this 83 */ 84 public function directories() 85 { 86 $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES; 87 88 return $this; 89 } 90 91 /** 92 * Restricts the matching to files only. 93 * 94 * @return $this 95 */ 96 public function files() 97 { 98 $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES; 99 100 return $this; 101 } 102 103 /** 104 * Adds tests for the directory depth. 105 * 106 * Usage: 107 * 108 * $finder->depth('> 1') // the Finder will start matching at level 1. 109 * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point. 110 * 111 * @param string|int $level The depth level expression 112 * 113 * @return $this 114 * 115 * @see DepthRangeFilterIterator 116 * @see NumberComparator 117 */ 118 public function depth($level) 119 { 120 $this->depths[] = new Comparator\NumberComparator($level); 121 122 return $this; 123 } 124 125 /** 126 * Adds tests for file dates (last modified). 127 * 128 * The date must be something that strtotime() is able to parse: 129 * 130 * $finder->date('since yesterday'); 131 * $finder->date('until 2 days ago'); 132 * $finder->date('> now - 2 hours'); 133 * $finder->date('>= 2005-10-15'); 134 * 135 * @param string $date A date range string 136 * 137 * @return $this 138 * 139 * @see strtotime 140 * @see DateRangeFilterIterator 141 * @see DateComparator 142 */ 143 public function date($date) 144 { 145 $this->dates[] = new Comparator\DateComparator($date); 146 147 return $this; 148 } 149 150 /** 151 * Adds rules that files must match. 152 * 153 * You can use patterns (delimited with / sign), globs or simple strings. 154 * 155 * $finder->name('*.php') 156 * $finder->name('/\.php$/') // same as above 157 * $finder->name('test.php') 158 * 159 * @param string $pattern A pattern (a regexp, a glob, or a string) 160 * 161 * @return $this 162 * 163 * @see FilenameFilterIterator 164 */ 165 public function name($pattern) 166 { 167 $this->names[] = $pattern; 168 169 return $this; 170 } 171 172 /** 173 * Adds rules that files must not match. 174 * 175 * @param string $pattern A pattern (a regexp, a glob, or a string) 176 * 177 * @return $this 178 * 179 * @see FilenameFilterIterator 180 */ 181 public function notName($pattern) 182 { 183 $this->notNames[] = $pattern; 184 185 return $this; 186 } 187 188 /** 189 * Adds tests that file contents must match. 190 * 191 * Strings or PCRE patterns can be used: 192 * 193 * $finder->contains('Lorem ipsum') 194 * $finder->contains('/Lorem ipsum/i') 195 * 196 * @param string $pattern A pattern (string or regexp) 197 * 198 * @return $this 199 * 200 * @see FilecontentFilterIterator 201 */ 202 public function contains($pattern) 203 { 204 $this->contains[] = $pattern; 205 206 return $this; 207 } 208 209 /** 210 * Adds tests that file contents must not match. 211 * 212 * Strings or PCRE patterns can be used: 213 * 214 * $finder->notContains('Lorem ipsum') 215 * $finder->notContains('/Lorem ipsum/i') 216 * 217 * @param string $pattern A pattern (string or regexp) 218 * 219 * @return $this 220 * 221 * @see FilecontentFilterIterator 222 */ 223 public function notContains($pattern) 224 { 225 $this->notContains[] = $pattern; 226 227 return $this; 228 } 229 230 /** 231 * Adds rules that filenames must match. 232 * 233 * You can use patterns (delimited with / sign) or simple strings. 234 * 235 * $finder->path('some/special/dir') 236 * $finder->path('/some\/special\/dir/') // same as above 237 * 238 * Use only / as dirname separator. 239 * 240 * @param string $pattern A pattern (a regexp or a string) 241 * 242 * @return $this 243 * 244 * @see FilenameFilterIterator 245 */ 246 public function path($pattern) 247 { 248 $this->paths[] = $pattern; 249 250 return $this; 251 } 252 253 /** 254 * Adds rules that filenames must not match. 255 * 256 * You can use patterns (delimited with / sign) or simple strings. 257 * 258 * $finder->notPath('some/special/dir') 259 * $finder->notPath('/some\/special\/dir/') // same as above 260 * 261 * Use only / as dirname separator. 262 * 263 * @param string $pattern A pattern (a regexp or a string) 264 * 265 * @return $this 266 * 267 * @see FilenameFilterIterator 268 */ 269 public function notPath($pattern) 270 { 271 $this->notPaths[] = $pattern; 272 273 return $this; 274 } 275 276 /** 277 * Adds tests for file sizes. 278 * 279 * $finder->size('> 10K'); 280 * $finder->size('<= 1Ki'); 281 * $finder->size(4); 282 * 283 * @param string|int $size A size range string or an integer 284 * 285 * @return $this 286 * 287 * @see SizeRangeFilterIterator 288 * @see NumberComparator 289 */ 290 public function size($size) 291 { 292 $this->sizes[] = new Comparator\NumberComparator($size); 293 294 return $this; 295 } 296 297 /** 298 * Excludes directories. 299 * 300 * Directories passed as argument must be relative to the ones defined with the `in()` method. For example: 301 * 302 * $finder->in(__DIR__)->exclude('ruby'); 303 * 304 * @param string|array $dirs A directory path or an array of directories 305 * 306 * @return $this 307 * 308 * @see ExcludeDirectoryFilterIterator 309 */ 310 public function exclude($dirs) 311 { 312 $this->exclude = array_merge($this->exclude, (array) $dirs); 313 314 return $this; 315 } 316 317 /** 318 * Excludes "hidden" directories and files (starting with a dot). 319 * 320 * This option is enabled by default. 321 * 322 * @param bool $ignoreDotFiles Whether to exclude "hidden" files or not 323 * 324 * @return $this 325 * 326 * @see ExcludeDirectoryFilterIterator 327 */ 328 public function ignoreDotFiles($ignoreDotFiles) 329 { 330 if ($ignoreDotFiles) { 331 $this->ignore |= static::IGNORE_DOT_FILES; 332 } else { 333 $this->ignore &= ~static::IGNORE_DOT_FILES; 334 } 335 336 return $this; 337 } 338 339 /** 340 * Forces the finder to ignore version control directories. 341 * 342 * This option is enabled by default. 343 * 344 * @param bool $ignoreVCS Whether to exclude VCS files or not 345 * 346 * @return $this 347 * 348 * @see ExcludeDirectoryFilterIterator 349 */ 350 public function ignoreVCS($ignoreVCS) 351 { 352 if ($ignoreVCS) { 353 $this->ignore |= static::IGNORE_VCS_FILES; 354 } else { 355 $this->ignore &= ~static::IGNORE_VCS_FILES; 356 } 357 358 return $this; 359 } 360 361 /** 362 * Adds VCS patterns. 363 * 364 * @see ignoreVCS() 365 * 366 * @param string|string[] $pattern VCS patterns to ignore 367 */ 368 public static function addVCSPattern($pattern) 369 { 370 foreach ((array) $pattern as $p) { 371 self::$vcsPatterns[] = $p; 372 } 373 374 self::$vcsPatterns = array_unique(self::$vcsPatterns); 375 } 376 377 /** 378 * Sorts files and directories by an anonymous function. 379 * 380 * The anonymous function receives two \SplFileInfo instances to compare. 381 * 382 * This can be slow as all the matching files and directories must be retrieved for comparison. 383 * 384 * @return $this 385 * 386 * @see SortableIterator 387 */ 388 public function sort(\Closure $closure) 389 { 390 $this->sort = $closure; 391 392 return $this; 393 } 394 395 /** 396 * Sorts files and directories by name. 397 * 398 * This can be slow as all the matching files and directories must be retrieved for comparison. 399 * 400 * @return $this 401 * 402 * @see SortableIterator 403 */ 404 public function sortByName() 405 { 406 $this->sort = Iterator\SortableIterator::SORT_BY_NAME; 407 408 return $this; 409 } 410 411 /** 412 * Sorts files and directories by type (directories before files), then by name. 413 * 414 * This can be slow as all the matching files and directories must be retrieved for comparison. 415 * 416 * @return $this 417 * 418 * @see SortableIterator 419 */ 420 public function sortByType() 421 { 422 $this->sort = Iterator\SortableIterator::SORT_BY_TYPE; 423 424 return $this; 425 } 426 427 /** 428 * Sorts files and directories by the last accessed time. 429 * 430 * This is the time that the file was last accessed, read or written to. 431 * 432 * This can be slow as all the matching files and directories must be retrieved for comparison. 433 * 434 * @return $this 435 * 436 * @see SortableIterator 437 */ 438 public function sortByAccessedTime() 439 { 440 $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME; 441 442 return $this; 443 } 444 445 /** 446 * Sorts files and directories by the last inode changed time. 447 * 448 * This is the time that the inode information was last modified (permissions, owner, group or other metadata). 449 * 450 * On Windows, since inode is not available, changed time is actually the file creation time. 451 * 452 * This can be slow as all the matching files and directories must be retrieved for comparison. 453 * 454 * @return $this 455 * 456 * @see SortableIterator 457 */ 458 public function sortByChangedTime() 459 { 460 $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME; 461 462 return $this; 463 } 464 465 /** 466 * Sorts files and directories by the last modified time. 467 * 468 * This is the last time the actual contents of the file were last modified. 469 * 470 * This can be slow as all the matching files and directories must be retrieved for comparison. 471 * 472 * @return $this 473 * 474 * @see SortableIterator 475 */ 476 public function sortByModifiedTime() 477 { 478 $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME; 479 480 return $this; 481 } 482 483 /** 484 * Filters the iterator with an anonymous function. 485 * 486 * The anonymous function receives a \SplFileInfo and must return false 487 * to remove files. 488 * 489 * @return $this 490 * 491 * @see CustomFilterIterator 492 */ 493 public function filter(\Closure $closure) 494 { 495 $this->filters[] = $closure; 496 497 return $this; 498 } 499 500 /** 501 * Forces the following of symlinks. 502 * 503 * @return $this 504 */ 505 public function followLinks() 506 { 507 $this->followLinks = true; 508 509 return $this; 510 } 511 512 /** 513 * Tells finder to ignore unreadable directories. 514 * 515 * By default, scanning unreadable directories content throws an AccessDeniedException. 516 * 517 * @param bool $ignore 518 * 519 * @return $this 520 */ 521 public function ignoreUnreadableDirs($ignore = true) 522 { 523 $this->ignoreUnreadableDirs = (bool) $ignore; 524 525 return $this; 526 } 527 528 /** 529 * Searches files and directories which match defined rules. 530 * 531 * @param string|string[] $dirs A directory path or an array of directories 532 * 533 * @return $this 534 * 535 * @throws \InvalidArgumentException if one of the directories does not exist 536 */ 537 public function in($dirs) 538 { 539 $resolvedDirs = []; 540 541 foreach ((array) $dirs as $dir) { 542 if (is_dir($dir)) { 543 $resolvedDirs[] = $this->normalizeDir($dir); 544 } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0) | \GLOB_ONLYDIR | \GLOB_NOSORT)) { 545 sort($glob); 546 $resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob)); 547 } else { 548 throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir)); 549 } 550 } 551 552 $this->dirs = array_merge($this->dirs, $resolvedDirs); 553 554 return $this; 555 } 556 557 /** 558 * Returns an Iterator for the current Finder configuration. 559 * 560 * This method implements the IteratorAggregate interface. 561 * 562 * @return \Iterator|SplFileInfo[] An iterator 563 * 564 * @throws \LogicException if the in() method has not been called 565 */ 566 public function getIterator() 567 { 568 if (0 === \count($this->dirs) && 0 === \count($this->iterators)) { 569 throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.'); 570 } 571 572 if (1 === \count($this->dirs) && 0 === \count($this->iterators)) { 573 return $this->searchInDirectory($this->dirs[0]); 574 } 575 576 $iterator = new \AppendIterator(); 577 foreach ($this->dirs as $dir) { 578 $iterator->append($this->searchInDirectory($dir)); 579 } 580 581 foreach ($this->iterators as $it) { 582 $iterator->append($it); 583 } 584 585 return $iterator; 586 } 587 588 /** 589 * Appends an existing set of files/directories to the finder. 590 * 591 * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. 592 * 593 * @param iterable $iterator 594 * 595 * @return $this 596 * 597 * @throws \InvalidArgumentException when the given argument is not iterable 598 */ 599 public function append($iterator) 600 { 601 if ($iterator instanceof \IteratorAggregate) { 602 $this->iterators[] = $iterator->getIterator(); 603 } elseif ($iterator instanceof \Iterator) { 604 $this->iterators[] = $iterator; 605 } elseif ($iterator instanceof \Traversable || \is_array($iterator)) { 606 $it = new \ArrayIterator(); 607 foreach ($iterator as $file) { 608 $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file)); 609 } 610 $this->iterators[] = $it; 611 } else { 612 throw new \InvalidArgumentException('Finder::append() method wrong argument type.'); 613 } 614 615 return $this; 616 } 617 618 /** 619 * Check if any results were found. 620 * 621 * @return bool 622 */ 623 public function hasResults() 624 { 625 foreach ($this->getIterator() as $_) { 626 return true; 627 } 628 629 return false; 630 } 631 632 /** 633 * Counts all the results collected by the iterators. 634 * 635 * @return int 636 */ 637 public function count() 638 { 639 return iterator_count($this->getIterator()); 640 } 641 642 /** 643 * @param string $dir 644 * 645 * @return \Iterator 646 */ 647 private function searchInDirectory($dir) 648 { 649 $exclude = $this->exclude; 650 $notPaths = $this->notPaths; 651 652 if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) { 653 $exclude = array_merge($exclude, self::$vcsPatterns); 654 } 655 656 if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) { 657 $notPaths[] = '#(^|/)\..+(/|$)#'; 658 } 659 660 $minDepth = 0; 661 $maxDepth = \PHP_INT_MAX; 662 663 foreach ($this->depths as $comparator) { 664 switch ($comparator->getOperator()) { 665 case '>': 666 $minDepth = $comparator->getTarget() + 1; 667 break; 668 case '>=': 669 $minDepth = $comparator->getTarget(); 670 break; 671 case '<': 672 $maxDepth = $comparator->getTarget() - 1; 673 break; 674 case '<=': 675 $maxDepth = $comparator->getTarget(); 676 break; 677 default: 678 $minDepth = $maxDepth = $comparator->getTarget(); 679 } 680 } 681 682 $flags = \RecursiveDirectoryIterator::SKIP_DOTS; 683 684 if ($this->followLinks) { 685 $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS; 686 } 687 688 $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); 689 690 if ($exclude) { 691 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude); 692 } 693 694 $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); 695 696 if ($minDepth > 0 || $maxDepth < \PHP_INT_MAX) { 697 $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); 698 } 699 700 if ($this->mode) { 701 $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode); 702 } 703 704 if ($this->names || $this->notNames) { 705 $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames); 706 } 707 708 if ($this->contains || $this->notContains) { 709 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); 710 } 711 712 if ($this->sizes) { 713 $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes); 714 } 715 716 if ($this->dates) { 717 $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates); 718 } 719 720 if ($this->filters) { 721 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); 722 } 723 724 if ($this->paths || $notPaths) { 725 $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths); 726 } 727 728 if ($this->sort) { 729 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort); 730 $iterator = $iteratorAggregate->getIterator(); 731 } 732 733 return $iterator; 734 } 735 736 /** 737 * Normalizes given directory names by removing trailing slashes. 738 * 739 * Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper 740 * 741 * @param string $dir 742 * 743 * @return string 744 */ 745 private function normalizeDir($dir) 746 { 747 if ('/' === $dir) { 748 return $dir; 749 } 750 751 $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR); 752 753 if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) { 754 $dir .= '/'; 755 } 756 757 return $dir; 758 } 759 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |