[ Index ]
 

Code source de Symfony 1.0.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/util/ -> sfFinder.class.php (source)

   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  }


Généré le : Fri Mar 16 22:42:14 2007 par Balluche grâce à PHPXref 0.7