File
[ class tree: File ] [ index: File ] [ all elements ]

Source for file Find.php

Documentation is available at Find.php

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

Documentation generated on Mon, 11 Mar 2019 14:36:00 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.