home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / File / Find.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  14.8 KB  |  486 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2005 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Sterling Hughes <sterling@php.net>                           |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Find.php,v 1.27 2006/06/30 14:06:16 techtonik Exp $
  20. //
  21.  
  22. require_once 'PEAR.php';
  23.  
  24. define('FILE_FIND_VERSION', '@package_version@');
  25.  
  26. // to debug uncomment this string
  27. // define('FILE_FIND_DEBUG', '');
  28.  
  29. /**
  30. *  Commonly needed functions searching directory trees
  31. *
  32. * @access public
  33. * @version $Id: Find.php,v 1.27 2006/06/30 14:06:16 techtonik Exp $
  34. * @package File
  35. * @author Sterling Hughes <sterling@php.net>
  36. */
  37. class File_Find
  38. {
  39.     /**
  40.      * internal dir-list
  41.      * @var array
  42.      */
  43.     var $_dirs = array();
  44.  
  45.     /**
  46.      * directory separator
  47.      * @var string
  48.      */
  49.     var $dirsep = "/";
  50.  
  51.     /**
  52.      * found files
  53.      * @var array
  54.      */
  55.     var $files = array();
  56.  
  57.     /**
  58.      * found dirs
  59.      * @var array
  60.      */
  61.     var $directories = array();
  62.  
  63.     /**
  64.      * Search specified directory to find matches for specified pattern
  65.      *
  66.      * @param string $pattern a string containing the pattern to search
  67.      * the directory for.
  68.      *
  69.      * @param string $dirpath a string containing the directory path
  70.      * to search.
  71.      *
  72.      * @param string $pattern_type a string containing the type of
  73.      * pattern matching functions to use (can either be 'php',
  74.      * 'perl' or 'shell').
  75.      *
  76.      * @return array containing all of the files and directories
  77.      * matching the pattern or null if no matches
  78.      *
  79.      * @author Sterling Hughes <sterling@php.net>
  80.      * @access public
  81.      * @static
  82.      */
  83.     function &glob($pattern, $dirpath, $pattern_type = 'php')
  84.     {
  85.         $dh = @opendir($dirpath);
  86.  
  87.         if (!$dh) {
  88.             $pe = PEAR::raiseError("Cannot open directory $dirpath");
  89.             return $pe;
  90.         }
  91.  
  92.         $match_function = File_Find::_determineRegex($pattern, $pattern_type);
  93.         $matches = array();
  94.  
  95.         // empty string cannot be specified for 'php' and 'perl' pattern
  96.         if ($pattern || ($pattern_type != 'php' && $pattern_type != 'perl')) {
  97.             while (false !== ($entry = @readdir($dh))) {
  98.                 if ($match_function($pattern, $entry) &&
  99.                     $entry != '.' && $entry != '..') {
  100.                     $matches[] = $entry;
  101.                 }
  102.             }
  103.         }
  104.  
  105.         @closedir($dh);
  106.  
  107.         if (0 == count($matches)) {
  108.             $matches = null;
  109.         }
  110.  
  111.         return $matches ;
  112.     }
  113.  
  114.     /**
  115.      * Map the directory tree given by the directory_path parameter.
  116.      *
  117.      * @param string $directory contains the directory path that you
  118.      * want to map.
  119.      *
  120.      * @return array a two element array, the first element containing a list
  121.      * of all the directories, the second element containing a list of all the
  122.      * files.
  123.      *
  124.      * @author Sterling Hughes <sterling@php.net>
  125.      * @access public
  126.      */
  127.     function &maptree($directory)
  128.     {
  129.  
  130.         /* if called statically */
  131.         if (!isset($this)  || !is_a($this, "File_Find")) {
  132.             $obj = &new File_Find();
  133.             return $obj->maptree($directory);
  134.         }
  135.       
  136.         /* clear the results just in case */
  137.         $this->files       = array();
  138.         $this->directories = array();
  139.  
  140.         /* strip out trailing slashes */
  141.         $directory = preg_replace('![\\\\/]+$!', '', $directory);
  142.  
  143.         $this->_dirs = array($directory);
  144.  
  145.         while (count($this->_dirs)) {
  146.             $dir = array_pop($this->_dirs);
  147.             File_Find::_build($dir, $this->dirsep);
  148.             array_push($this->directories, $dir);
  149.         }
  150.  
  151.         $retval = array($this->directories, $this->files);
  152.         return $retval;
  153.  
  154.     }
  155.  
  156.     /**
  157.      * Map the directory tree given by the directory parameter.
  158.      *
  159.      * @param string $directory contains the directory path that you
  160.      * want to map.
  161.      * @param integer $maxrecursion maximun number of folders to recursive 
  162.      * map
  163.      *
  164.      * @return array a multidimensional array containing all subdirectories
  165.      * and their files. For example:
  166.      *
  167.      * Array
  168.      * (
  169.      *    [0] => file_1.php
  170.      *    [1] => file_2.php
  171.      *    [subdirname] => Array
  172.      *       (
  173.      *          [0] => file_1.php
  174.      *       )
  175.      * )
  176.      *
  177.      * @author Mika Tuupola <tuupola@appelsiini.net>
  178.      * @access public
  179.      * @static
  180.      */
  181.     function &mapTreeMultiple($directory, $maxrecursion = 0, $count = 0)
  182.     {   
  183.         $retval = array();
  184.  
  185.         $count++;
  186.  
  187.         /* strip trailing slashes */
  188.         $directory = preg_replace('![\\\\/]+$!', '', $directory);
  189.         
  190.         if (is_readable($directory)) {
  191.             $dh = opendir($directory);
  192.             while (false !== ($entry = @readdir($dh))) {
  193.                 if ($entry != '.' && $entry != '..') {
  194.                      array_push($retval, $entry);
  195.                 }
  196.             }
  197.             closedir($dh);
  198.         }
  199.      
  200.         while (list($key, $val) = each($retval)) {
  201.             $path = $directory . "/" . $val;
  202.       
  203.             if (!is_array($val) && is_dir($path)) {
  204.                 unset($retval[$key]);
  205.                 if ($maxrecursion == 0 || $count < $maxrecursion) {
  206.                     $retval[$val] = &File_Find::mapTreeMultiple($path, 
  207.                                     $maxrecursion, $count);
  208.                 }
  209.             }
  210.         }
  211.  
  212.         return $retval;
  213.     }
  214.  
  215.     /**
  216.      * Search the specified directory tree with the specified pattern.  Return
  217.      * an array containing all matching files (no directories included).
  218.      *
  219.      * @param string $pattern the pattern to match every file with.
  220.      *
  221.      * @param string $directory the directory tree to search in.
  222.      *
  223.      * @param string $type the type of regular expression support to use, either
  224.      * 'php', 'perl' or 'shell'.
  225.      *
  226.      * @param bool $fullpath whether the regex should be matched against the
  227.      * full path or only against the filename
  228.      *
  229.      * @param string $match can be either 'files', 'dirs' or 'both' to specify
  230.      * the kind of list to return
  231.      *
  232.      * @return array a list of files matching the pattern parameter in the the
  233.      * directory path specified by the directory parameter
  234.      *
  235.      * @author Sterling Hughes <sterling@php.net>
  236.      * @access public
  237.      * @static
  238.      */
  239.     function &search($pattern, $directory, $type = 'php', $fullpath = true, $match = 'files')
  240.     {
  241.  
  242.         $matches = array();
  243.         list ($directories,$files)  = File_Find::maptree($directory);
  244.         switch($match) {
  245.             case 'directories': 
  246.                 $data = $directories; 
  247.                 break;
  248.             case 'both': 
  249.                 $data = array_merge($directories, $files); 
  250.                 break;
  251.             case 'files':
  252.             default:
  253.                 $data = $files;
  254.         }
  255.         unset($files, $directories);
  256.  
  257.         $match_function = File_Find::_determineRegex($pattern, $type);
  258.  
  259.         reset($data);
  260.         // check if empty string given (ok for 'shell' method, but bad for others)
  261.         if ($pattern || ($type != 'php' && $type != 'perl')) {
  262.             while (list(,$entry) = each($data)) {
  263.                 if ($match_function($pattern, 
  264.                                     $fullpath ? $entry : basename($entry))) {
  265.                     $matches[] = $entry;
  266.                 } 
  267.             }
  268.         }
  269.  
  270.         return $matches;
  271.     }
  272.  
  273.     /**
  274.      * Determine whether or not a variable is a PEAR error
  275.      *
  276.      * @param object PEAR_Error $var the variable to test.
  277.      *
  278.      * @return boolean returns true if the variable is a PEAR error, otherwise
  279.      * it returns false.
  280.      * @access public
  281.      */
  282.     function isError(&$var)
  283.     {
  284.         return PEAR::isError($var);
  285.     }
  286.  
  287.     /**
  288.      * internal function to build singular directory trees, used by
  289.      * File_Find::maptree()
  290.      *
  291.      * @param string $directory name of the directory to read
  292.      * @param string $separator directory separator
  293.      * @return void
  294.      */
  295.     function _build($directory, $separator = "/")
  296.     {
  297.  
  298.         $dh = @opendir($directory);
  299.  
  300.         if (!$dh) {
  301.             $pe = PEAR::raiseError("Cannot open directory");
  302.             return $pe;
  303.         }
  304.  
  305.         while (false !== ($entry = @readdir($dh))) {
  306.             if ($entry != '.' && $entry != '..') {
  307.  
  308.                 $entry = $directory.$separator.$entry;
  309.  
  310.                 if (is_dir($entry)) {
  311.                     array_push($this->_dirs, $entry);
  312.                 } else {
  313.                     array_push($this->files, $entry);
  314.                 }
  315.             }
  316.         }
  317.  
  318.         @closedir($dh);
  319.     }
  320.  
  321.     /**
  322.      * internal function to determine the type of regular expression to
  323.      * use, implemented by File_Find::glob() and File_Find::search()
  324.      *
  325.      * @param string $type given RegExp type
  326.      * @return string kind of function ( "eregi", "ereg" or "preg_match") ;
  327.      *
  328.      */
  329.     function _determineRegex($pattern, $type)
  330.     {
  331.         if (!strcasecmp($type, 'shell')) {
  332.             $match_function = 'File_Find_match_shell';
  333.         } else if (!strcasecmp($type, 'perl')) {
  334.             $match_function = 'preg_match';
  335.         } else if (!strcasecmp(substr($pattern, -2), '/i')) {
  336.             $match_function = 'eregi';
  337.         } else {
  338.             $match_function = 'ereg';
  339.         }
  340.         return $match_function;
  341.     }
  342.  
  343. }
  344.  
  345. /**
  346. * Package method to match via 'shell' pattern. Provided in global
  347. * scope, because it should be called like 'preg_match' and 'eregi'
  348. * and can be easily copied into other packages
  349. *
  350. * @author techtonik <techtonik@php.net>
  351. * @return mixed bool on success and PEAR_Error on failure
  352. */ 
  353. function File_Find_match_shell($pattern, $filename)
  354. {
  355.     // {{{ convert pattern to positive and negative regexps
  356.         $positive = $pattern;
  357.         $negation = substr_count($pattern, "|");
  358.  
  359.         if ($negation > 1) {
  360.             PEAR::raiseError("Mask string contains errors!");
  361.             return FALSE;
  362.         } elseif ($negation) {
  363.             list($positive, $negative) = explode("|", $pattern);
  364.             if (strlen($negative) == 0) {
  365.                 PEAR::raiseError("File-mask string contains errors!");
  366.                 return FALSE;
  367.             }
  368.         }
  369.  
  370.        $positive = _File_Find_match_shell_get_pattern($positive);
  371.        if ($negation) {
  372.            $negative = _File_Find_match_shell_get_pattern($negative);
  373.        }
  374.     // }}} convert end 
  375.  
  376.  
  377.     if (defined("FILE_FIND_DEBUG")) {
  378.         print("Method: $type\nPattern: $pattern\n Converted pattern:");
  379.         print_r($positive);
  380.         if (isset($negative)) print_r($negative);
  381.     }
  382.  
  383.     if (!preg_match($positive, $filename)) {
  384.         return FALSE;
  385.     } else {
  386.         if (isset($negative) 
  387.               && preg_match($negative, $filename)) {
  388.             return FALSE;
  389.         } else {
  390.             return TRUE;
  391.         }
  392.     }
  393. }
  394.  
  395. /**
  396. * function used by File_Find_match_shell to convert 'shell' mask
  397. * into pcre regexp. Some of the rules (see testcases for more): 
  398. *  escaping all special chars and replacing 
  399. *    . with \.
  400. *    * with .*
  401. *    ? with .{1}
  402. *    also adding ^ and $ as the pattern matches whole filename
  403. *
  404. * @author techtonik <techtonik@php.net>
  405. * @return string pcre regexp for preg_match
  406. */ 
  407. function _File_Find_match_shell_get_pattern($mask) {
  408.     // get array of several masks (if any) delimited by comma
  409.     // do not touch commas in char class
  410.     $premasks = preg_split("|(\[[^\]]+\])|", $mask, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
  411.     if (defined("FILE_FIND_DEBUG")) {
  412.         print("\nPremask: ");
  413.         print_r($premasks);
  414.     }
  415.     $pi = 0;
  416.     foreach($premasks as $pm) {
  417.         if (!isset($masks[$pi])) $masks[$pi] = "";
  418.         if ($pm{0} == '[' && $pm{strlen($pm)-1} == ']') {
  419.             // strip commas from character class
  420.             $masks[$pi] .= str_replace(",", "", $pm);
  421.         } else {
  422.             $tarr = explode(",", $pm);
  423.             if (sizeof($tarr) == 1) {
  424.                 $masks[$pi] .= $pm;
  425.             } else {
  426.                 foreach ($tarr as $te) {
  427.                     $masks[$pi++] .= $te;
  428.                     $masks[$pi] = "";
  429.                 }
  430.                 unset($masks[$pi--]);
  431.             }
  432.         }
  433.     }
  434.  
  435.     // if empty string given return *.* pattern
  436.     if (strlen($mask) == 0) return "!^.*$!";
  437.  
  438.     // convert to preg regexp
  439.     $regexmask = implode("|", $masks);
  440.     if (defined("FILE_FIND_DEBUG")) {
  441.         print("regexMask step one(implode): $regexmask");
  442.     }
  443.     $regexmask = addcslashes($regexmask, '^$}!{)(\/.+');
  444.     if (defined("FILE_FIND_DEBUG")) {
  445.         print("\nregexMask step two(addcslashes): $regexmask");
  446.     }
  447.     $regexmask = preg_replace("!(\*|\?)!", ".$1", $regexmask);
  448.     if (defined("FILE_FIND_DEBUG")) {
  449.         print("\nregexMask step three(* ? -> .* .?): $regexmask");
  450.     }
  451.     // a special case '*.' at the end means that there is no extension
  452.     $regexmask = preg_replace("!\.\*\\\.(\||$)!", "[^\.]*$1", $regexmask);
  453.     // it is impossible to have dot at the end of filename
  454.     $regexmask = preg_replace("!\\\.(\||$)!", "$1", $regexmask);
  455.     // and .* at the end also means that there could be nothing at all
  456.     //   (i.e. no dot at the end also)
  457.     $regexmask = preg_replace("!\\\.\.\*(\||$)!", "(\\\\..*)?$1", $regexmask);
  458.     if (defined("FILE_FIND_DEBUG")) {
  459.         print("\nregexMask step two and half(*.$ \\..*$ .$ -> [^.]*$ .?.* $): $regexmask");
  460.     }
  461.     // if no extension supplied - add .* to match partially from filename start
  462.     if (strpos($regexmask, "\\.") === FALSE) $regexmask .= ".*";
  463.  
  464.     // file mask match whole name - adding restrictions
  465.     $regexmask = preg_replace("!(\|)!", '^'."$1".'$', $regexmask);
  466.     $regexmask = '^'.$regexmask.'$';
  467.     if (defined("FILE_FIND_DEBUG")) {
  468.         print("\nregexMask step three(^ and $ to match whole name): $regexmask");
  469.     }
  470.     // wrap regex into ! since all ! are already escaped
  471.     $regexmask = "!$regexmask!i";
  472.     if (defined("FILE_FIND_DEBUG")) {
  473.         print("\nWrapped regex: $regexmask\n");
  474.     }
  475.     return $regexmask;
  476. }
  477.  
  478. /*
  479.  * Local variables:
  480.  * tab-width: 4
  481.  * c-basic-offset: 4
  482.  * End:
  483.  */
  484.  
  485. ?>
  486.