| [ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 3 /* 4 * This file is part of the symfony package. 5 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com> 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11 /** 12 * 13 * @package symfony 14 * @subpackage util 15 * @author Fabien Potencier <fabien.potencier@symfony-project.com> 16 * @version SVN: $Id: sfFinder.class.php 3268 2007-01-13 20:19:33Z fabien $ 17 */ 18 19 /** 20 * 21 * Allow to build rules to find files and directories. 22 * 23 * All rules may be invoked several times, except for ->in() method. 24 * Some rules are cumulative (->name() for example) whereas others are destructive 25 * (most recent value is used, ->maxdepth() method for example). 26 * 27 * All methods return the current sfFinder object to allow easy chaining: 28 * 29 * $files = sfFinder::type('file')->name('*.php')->in(.); 30 * 31 * Interface loosely based on perl File::Find::Rule module. 32 * 33 * @package symfony 34 * @subpackage util 35 * @author Fabien Potencier <fabien.potencier@symfony-project.com> 36 * @version SVN: $Id: sfFinder.class.php 3268 2007-01-13 20:19:33Z fabien $ 37 */ 38 class sfFinder 39 { 40 protected $type = 'file'; 41 protected $names = array(); 42 protected $prunes = array(); 43 protected $discards = array(); 44 protected $execs = array(); 45 protected $mindepth = 0; 46 protected $sizes = array(); 47 protected $maxdepth = 1000000; 48 protected $relative = false; 49 protected $follow_link = false; 50 51 /** 52 * Sets maximum directory depth. 53 * 54 * Finder will descend at most $level levels of directories below the starting point. 55 * 56 * @param integer level 57 * @return object current sfFinder object 58 */ 59 public function maxdepth($level) 60 { 61 $this->maxdepth = $level; 62 63 return $this; 64 } 65 66 /** 67 * Sets minimum directory depth. 68 * 69 * Finder will start applying tests at level $level. 70 * 71 * @param integer level 72 * @return object current sfFinder object 73 */ 74 public function mindepth($level) 75 { 76 $this->mindepth = $level; 77 78 return $this; 79 } 80 81 public function get_type() 82 { 83 return $this->type; 84 } 85 86 /** 87 * Sets the type of elements to returns. 88 * 89 * @param string directory or file or any (for both file and directory) 90 * @return object new sfFinder object 91 */ 92 public static function type($name) 93 { 94 $finder = new sfFinder(); 95 96 if (strtolower(substr($name, 0, 3)) == 'dir') 97 { 98 $finder->type = 'directory'; 99 } 100 else if (strtolower($name) == 'any') 101 { 102 $finder->type = 'any'; 103 } 104 else 105 { 106 $finder->type = 'file'; 107 } 108 109 return $finder; 110 } 111 112 /* 113 * glob, patterns (must be //) or strings 114 */ 115 protected function to_regex($str) 116 { 117 if ($str{0} == '/' && $str{strlen($str) - 1} == '/') 118 { 119 return $str; 120 } 121 else 122 { 123 return sfGlobToRegex::glob_to_regex($str); 124 } 125 } 126 127 protected function args_to_array($arg_list, $not = false) 128 { 129 $list = array(); 130 131 for ($i = 0; $i < count($arg_list); $i++) 132 { 133 if (is_array($arg_list[$i])) 134 { 135 foreach ($arg_list[$i] as $arg) 136 { 137 $list[] = array($not, $this->to_regex($arg)); 138 } 139 } 140 else 141 { 142 $list[] = array($not, $this->to_regex($arg_list[$i])); 143 } 144 } 145 146 return $list; 147 } 148 149 /** 150 * Adds rules that files must match. 151 * 152 * You can use patterns (delimited with / sign), globs or simple strings. 153 * 154 * $finder->name('*.php') 155 * $finder->name('/\.php$/') // same as above 156 * $finder->name('test.php') 157 * 158 * @param list a list of patterns, globs or strings 159 * @return object current sfFinder object 160 */ 161 public function name() 162 { 163 $args = func_get_args(); 164 $this->names = array_merge($this->names, $this->args_to_array($args)); 165 166 return $this; 167 } 168 169 /** 170 * Adds rules that files must not match. 171 * 172 * @see ->name() 173 * @param list a list of patterns, globs or strings 174 * @return object current sfFinder object 175 */ 176 public function not_name() 177 { 178 $args = func_get_args(); 179 $this->names = array_merge($this->names, $this->args_to_array($args, true)); 180 181 return $this; 182 } 183 184 /** 185 * Adds tests for file sizes. 186 * 187 * $finder->size('> 10K'); 188 * $finder->size('<= 1Ki'); 189 * $finder->size(4); 190 * 191 * @param list a list of comparison strings 192 * @return object current sfFinder object 193 */ 194 public function size() 195 { 196 $args = func_get_args(); 197 for ($i = 0; $i < count($args); $i++) 198 { 199 $this->sizes[] = new sfNumberCompare($args[$i]); 200 } 201 202 return $this; 203 } 204 205 /** 206 * Traverses no further. 207 * 208 * @param list a list of patterns, globs to match 209 * @return object current sfFinder object 210 */ 211 public function prune() 212 { 213 $args = func_get_args(); 214 $this->prunes = array_merge($this->prunes, $this->args_to_array($args)); 215 216 return $this; 217 } 218 219 /** 220 * Discards elements that matches. 221 * 222 * @param list a list of patterns, globs to match 223 * @return object current sfFinder object 224 */ 225 public function discard() 226 { 227 $args = func_get_args(); 228 $this->discards = array_merge($this->discards, $this->args_to_array($args)); 229 230 return $this; 231 } 232 233 /** 234 * Ignores version control directories. 235 * 236 * Currently supports subversion, CVS, DARCS, Gnu Arch, Monotone, Bazaar-NG 237 * 238 * @return object current pakeFinder object 239 */ 240 public function ignore_version_control() 241 { 242 $ignores = array('.svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr'); 243 244 return $this->discard($ignores)->prune($ignores); 245 } 246 247 /** 248 * Executes function or method for each element. 249 * 250 * Element match if functino or method returns true. 251 * 252 * $finder->exec('myfunction'); 253 * $finder->exec(array($object, 'mymethod')); 254 * 255 * @param mixed function or method to call 256 * @return object current sfFinder object 257 */ 258 public function exec() 259 { 260 $args = func_get_args(); 261 for ($i = 0; $i < count($args); $i++) 262 { 263 if (is_array($args[$i]) && !method_exists($args[$i][0], $args[$i][1])) 264 { 265 throw new sfException("method {$args[$i][1]} does not exist for object {$args[$i][0]}"); 266 } 267 else if (!is_array($args[$i]) && !function_exists($args[$i])) 268 { 269 throw new sfException("function {$args[$i]} does not exist"); 270 } 271 272 $this->execs[] = $args[$i]; 273 } 274 275 return $this; 276 } 277 278 /** 279 * Returns relative paths for all files and directories. 280 * 281 * @return object current sfFinder object 282 */ 283 public function relative() 284 { 285 $this->relative = true; 286 287 return $this; 288 } 289 290 /** 291 * Symlink following. 292 * 293 * @return object current sfFinder object 294 */ 295 public function follow_link() 296 { 297 $this->follow_link = true; 298 299 return $this; 300 } 301 302 /** 303 * Searches files and directories which match defined rules. 304 * 305 * @return array list of files and directories 306 */ 307 public function in() 308 { 309 $files = array(); 310 $here_dir = getcwd(); 311 $numargs = func_num_args(); 312 $arg_list = func_get_args(); 313 314 // first argument is an array? 315 if ($numargs == 1 && is_array($arg_list[0])) 316 { 317 $arg_list = $arg_list[0]; 318 $numargs = count($arg_list); 319 } 320 321 for ($i = 0; $i < $numargs; $i++) 322 { 323 $real_dir = realpath($arg_list[$i]); 324 325 // absolute path? 326 if (!self::isPathAbsolute($real_dir)) 327 { 328 $dir = $here_dir.DIRECTORY_SEPARATOR.$real_dir; 329 } 330 else 331 { 332 $dir = $real_dir; 333 } 334 335 if (!is_dir($real_dir)) 336 { 337 continue; 338 } 339 340 if ($this->relative) 341 { 342 $files = array_merge($files, str_replace($dir.DIRECTORY_SEPARATOR, '', $this->search_in($dir))); 343 } 344 else 345 { 346 $files = array_merge($files, $this->search_in($dir)); 347 } 348 } 349 350 return array_unique($files); 351 } 352 353 protected function search_in($dir, $depth = 0) 354 { 355 if ($depth > $this->maxdepth) 356 { 357 return array(); 358 } 359 360 if (is_link($dir) && !$this->follow_link) 361 { 362 return array(); 363 } 364 365 $files = array(); 366 367 if (is_dir($dir)) 368 { 369 $current_dir = opendir($dir); 370 while (false !== $entryname = readdir($current_dir)) 371 { 372 if ($entryname == '.' || $entryname == '..') continue; 373 374 $current_entry = $dir.DIRECTORY_SEPARATOR.$entryname; 375 if (is_link($current_entry) && !$this->follow_link) 376 { 377 continue; 378 } 379 380 if (is_dir($current_entry)) 381 { 382 if (($this->type == 'directory' || $this->type == 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->exec_ok($dir, $entryname)) 383 { 384 $files[] = realpath($current_entry); 385 } 386 387 if (!$this->is_pruned($dir, $entryname)) 388 { 389 $files = array_merge($files, $this->search_in($current_entry, $depth + 1)); 390 } 391 } 392 else 393 { 394 if (($this->type != 'directory' || $this->type == 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->size_ok($dir, $entryname) && $this->exec_ok($dir, $entryname)) 395 { 396 $files[] = realpath($current_entry); 397 } 398 } 399 } 400 closedir($current_dir); 401 } 402 403 return $files; 404 } 405 406 protected function match_names($dir, $entry) 407 { 408 if (!count($this->names)) return true; 409 410 // we must match one "not_name" rules to be ko 411 $one_not_name_rule = false; 412 foreach ($this->names as $args) 413 { 414 list($not, $regex) = $args; 415 if ($not) 416 { 417 $one_not_name_rule = true; 418 if (preg_match($regex, $entry)) 419 { 420 return false; 421 } 422 } 423 } 424 425 $one_name_rule = false; 426 // we must match one "name" rules to be ok 427 foreach ($this->names as $args) 428 { 429 list($not, $regex) = $args; 430 if (!$not) 431 { 432 $one_name_rule = true; 433 if (preg_match($regex, $entry)) 434 { 435 return true; 436 } 437 } 438 } 439 440 if ($one_not_name_rule && $one_name_rule) 441 { 442 return false; 443 } 444 else if ($one_not_name_rule) 445 { 446 return true; 447 } 448 else if ($one_name_rule) 449 { 450 return false; 451 } 452 else 453 { 454 return true; 455 } 456 } 457 458 protected function size_ok($dir, $entry) 459 { 460 if (!count($this->sizes)) return true; 461 462 if (!is_file($dir.DIRECTORY_SEPARATOR.$entry)) return true; 463 464 $filesize = filesize($dir.DIRECTORY_SEPARATOR.$entry); 465 foreach ($this->sizes as $number_compare) 466 { 467 if (!$number_compare->test($filesize)) return false; 468 } 469 470 return true; 471 } 472 473 protected function is_pruned($dir, $entry) 474 { 475 if (!count($this->prunes)) return false; 476 477 foreach ($this->prunes as $args) 478 { 479 $regex = $args[1]; 480 if (preg_match($regex, $entry)) return true; 481 } 482 483 return false; 484 } 485 486 protected function is_discarded($dir, $entry) 487 { 488 if (!count($this->discards)) return false; 489 490 foreach ($this->discards as $args) 491 { 492 $regex = $args[1]; 493 if (preg_match($regex, $entry)) return true; 494 } 495 496 return false; 497 } 498 499 protected function exec_ok($dir, $entry) 500 { 501 if (!count($this->execs)) return true; 502 503 foreach ($this->execs as $exec) 504 { 505 if (!call_user_func_array($exec, array($dir, $entry))) return false; 506 } 507 508 return true; 509 } 510 511 public static function isPathAbsolute($path) 512 { 513 if ($path{0} == '/' || $path{0} == '\\' || 514 (strlen($path) > 3 && ctype_alpha($path{0}) && 515 $path{1} == ':' && 516 ($path{2} == '\\' || $path{2} == '/') 517 ) 518 ) 519 { 520 return true; 521 } 522 523 return false; 524 } 525 } 526 527 /** 528 * Match globbing patterns against text. 529 * 530 * if match_glob("foo.*", "foo.bar") echo "matched\n"; 531 * 532 * // prints foo.bar and foo.baz 533 * $regex = glob_to_regex("foo.*"); 534 * for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t) 535 * { 536 * if (/$regex/) echo "matched: $car\n"; 537 * } 538 * 539 * sfGlobToRegex implements glob(3) style matching that can be used to match 540 * against text, rather than fetching names from a filesystem. 541 * 542 * based on perl Text::Glob module. 543 * 544 * @package symfony 545 * @subpackage util 546 * @author Fabien Potencier <fabien.potencier@gmail.com> php port 547 * @author Richard Clamp <richardc@unixbeard.net> perl version 548 * @copyright 2004-2005 Fabien Potencier <fabien.potencier@gmail.com> 549 * @copyright 2002 Richard Clamp <richardc@unixbeard.net> 550 * @version SVN: $Id: sfFinder.class.php 3268 2007-01-13 20:19:33Z fabien $ 551 */ 552 class sfGlobToRegex 553 { 554 protected static $strict_leading_dot = true; 555 protected static $strict_wildcard_slash = true; 556 557 public static function setStrictLeadingDot($boolean) 558 { 559 self::$strict_leading_dot = $boolean; 560 } 561 562 public static function setStrictWildcardSlash($boolean) 563 { 564 self::$strict_wildcard_slash = $boolean; 565 } 566 567 /** 568 * Returns a compiled regex which is the equiavlent of the globbing pattern. 569 * 570 * @param string glob pattern 571 * @return string regex 572 */ 573 public static function glob_to_regex($glob) 574 { 575 $first_byte = true; 576 $escaping = false; 577 $in_curlies = 0; 578 $regex = ''; 579 for ($i = 0; $i < strlen($glob); $i++) 580 { 581 $car = $glob[$i]; 582 if ($first_byte) 583 { 584 if (self::$strict_leading_dot && $car != '.') 585 { 586 $regex .= '(?=[^\.])'; 587 } 588 589 $first_byte = false; 590 } 591 592 if ($car == '/') 593 { 594 $first_byte = true; 595 } 596 597 if ($car == '.' || $car == '(' || $car == ')' || $car == '|' || $car == '+' || $car == '^' || $car == '$') 598 { 599 $regex .= "\\$car"; 600 } 601 else if ($car == '*') 602 { 603 $regex .= ($escaping ? "\\*" : (self::$strict_wildcard_slash ? "[^/]*" : ".*")); 604 } 605 else if ($car == '?') 606 { 607 $regex .= ($escaping ? "\\?" : (self::$strict_wildcard_slash ? "[^/]" : ".")); 608 } 609 else if ($car == '{') 610 { 611 $regex .= ($escaping ? "\\{" : "("); 612 if (!$escaping) ++$in_curlies; 613 } 614 else if ($car == '}' && $in_curlies) 615 { 616 $regex .= ($escaping ? "}" : ")"); 617 if (!$escaping) --$in_curlies; 618 } 619 else if ($car == ',' && $in_curlies) 620 { 621 $regex .= ($escaping ? "," : "|"); 622 } 623 else if ($car == "\\") 624 { 625 if ($escaping) 626 { 627 $regex .= "\\\\"; 628 $escaping = false; 629 } 630 else 631 { 632 $escaping = true; 633 } 634 635 continue; 636 } 637 else 638 { 639 $regex .= $car; 640 $escaping = false; 641 } 642 $escaping = false; 643 } 644 645 return "#^$regex$#"; 646 } 647 } 648 649 /** 650 * Numeric comparisons. 651 * 652 * sfNumberCompare compiles a simple comparison to an anonymous 653 * subroutine, which you can call with a value to be tested again. 654 655 * Now this would be very pointless, if sfNumberCompare didn't understand 656 * magnitudes. 657 658 * The target value may use magnitudes of kilobytes (k, ki), 659 * megabytes (m, mi), or gigabytes (g, gi). Those suffixed 660 * with an i use the appropriate 2**n version in accordance with the 661 * IEC standard: http://physics.nist.gov/cuu/Units/binary.html 662 * 663 * based on perl Number::Compare module. 664 * 665 * @package symfony 666 * @subpackage util 667 * @author Fabien Potencier <fabien.potencier@gmail.com> php port 668 * @author Richard Clamp <richardc@unixbeard.net> perl version 669 * @copyright 2004-2005 Fabien Potencier <fabien.potencier@gmail.com> 670 * @copyright 2002 Richard Clamp <richardc@unixbeard.net> 671 * @see http://physics.nist.gov/cuu/Units/binary.html 672 * @version SVN: $Id: sfFinder.class.php 3268 2007-01-13 20:19:33Z fabien $ 673 */ 674 class sfNumberCompare 675 { 676 protected $test = ''; 677 678 public function __construct($test) 679 { 680 $this->test = $test; 681 } 682 683 public function test($number) 684 { 685 if (!preg_match('{^([<>]=?)?(.*?)([kmg]i?)?$}i', $this->test, $matches)) 686 { 687 throw new sfException('don\'t understand "'.$this->test.'" as a test'); 688 } 689 690 $target = array_key_exists(2, $matches) ? $matches[2] : ''; 691 $magnitude = array_key_exists(3, $matches) ? $matches[3] : ''; 692 if (strtolower($magnitude) == 'k') $target *= 1000; 693 if (strtolower($magnitude) == 'ki') $target *= 1024; 694 if (strtolower($magnitude) == 'm') $target *= 1000000; 695 if (strtolower($magnitude) == 'mi') $target *= 1024*1024; 696 if (strtolower($magnitude) == 'g') $target *= 1000000000; 697 if (strtolower($magnitude) == 'gi') $target *= 1024*1024*1024; 698 699 $comparison = array_key_exists(1, $matches) ? $matches[1] : '=='; 700 if ($comparison == '==' || $comparison == '') 701 { 702 return ($number == $target); 703 } 704 else if ($comparison == '>') 705 { 706 return ($number > $target); 707 } 708 else if ($comparison == '>=') 709 { 710 return ($number >= $target); 711 } 712 else if ($comparison == '<') 713 { 714 return ($number < $target); 715 } 716 else if ($comparison == '<=') 717 { 718 return ($number <= $target); 719 } 720 721 return false; 722 } 723 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |