Viewing file: Find.php (14.88 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php // // +----------------------------------------------------------------------+ // | PHP Version 4 | // +----------------------------------------------------------------------+ // | Copyright (c) 1997-2005 The PHP Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.02 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/2_02.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Author: Sterling Hughes <sterling@php.net> | // +----------------------------------------------------------------------+ // // $Id$ //
require_once 'PEAR.php';
define('FILE_FIND_VERSION', '@package_version@');
// to debug uncomment this string // define('FILE_FIND_DEBUG', '');
/** * Commonly needed functions searching directory trees * * @access public * @version $Id$ * @package File * @author Sterling Hughes <sterling@php.net> */ class File_Find { /** * internal dir-list * @var array */ var $_dirs = array();
/** * directory separator * @var string */ var $dirsep = "/";
/** * found files * @var array */ var $files = array();
/** * found dirs * @var array */ var $directories = array();
/** * Search specified directory to find matches for specified pattern * * @param string $pattern a string containing the pattern to search * the directory for. * * @param string $dirpath a string containing the directory path * to search. * * @param string $pattern_type a string containing the type of * pattern matching functions to use (can either be 'php', * 'perl' or 'shell'). * * @return array containing all of the files and directories * matching the pattern or null if no matches * * @author Sterling Hughes <sterling@php.net> * @access public * @static */ function &glob($pattern, $dirpath, $pattern_type = 'php') { $dh = @opendir($dirpath);
if (!$dh) { $pe = PEAR::raiseError("Cannot open directory $dirpath"); return $pe; }
$match_function = File_Find::_determineRegex($pattern, $pattern_type); $matches = array();
// empty string cannot be specified for 'php' and 'perl' pattern if ($pattern || ($pattern_type != 'php' && $pattern_type != 'perl')) { while (false !== ($entry = @readdir($dh))) { if ($match_function($pattern, $entry) && $entry != '.' && $entry != '..') { $matches[] = $entry; } } }
@closedir($dh);
if (0 == count($matches)) { $matches = null; }
sort($matches);
return $matches ; }
/** * Map the directory tree given by the directory_path parameter. * * @param string $directory contains the directory path that you * want to map. * * @return array a two element array, the first element containing a list * of all the directories, the second element containing a list of all the * files. * * @author Sterling Hughes <sterling@php.net> * @access public */ function &maptree($directory) {
/* if called statically */ if (!isset($this) || !is_a($this, "File_Find")) { $obj = new File_Find(); return $obj->maptree($directory); } /* clear the results just in case */ $this->files = array(); $this->directories = array();
/* strip out trailing slashes */ $directory = preg_replace('![\\\\/]+$!', '', $directory);
$this->_dirs = array($directory);
while (count($this->_dirs)) { $dir = array_pop($this->_dirs); File_Find::_build($dir, $this->dirsep); array_push($this->directories, $dir); }
sort($this->directories); sort($this->files);
$retval = array($this->directories, $this->files); return $retval;
}
/** * Map the directory tree given by the directory parameter. * * @param string $directory contains the directory path that you * want to map. * @param integer $maxrecursion maximun number of folders to recursive * map * * @return array a multidimensional array containing all subdirectories * and their files. For example: * * Array * ( * [0] => file_1.php * [1] => file_2.php * [subdirname] => Array * ( * [0] => file_1.php * ) * ) * * @author Mika Tuupola <tuupola@appelsiini.net> * @access public * @static */ function &mapTreeMultiple($directory, $maxrecursion = 0, $count = 0) { $retval = array();
$count++;
/* strip trailing slashes */ $directory = preg_replace('![\\\\/]+$!', '', $directory); if (is_readable($directory)) { $dh = opendir($directory); while (false !== ($entry = @readdir($dh))) { if ($entry != '.' && $entry != '..') { array_push($retval, $entry); } } closedir($dh); }
sort($retval);
while (list($key, $val) = each($retval)) { if (!is_array($val)) { $path = $directory . "/" . $val; if (is_dir($path)) { unset($retval[$key]); if ($maxrecursion == 0 || $count < $maxrecursion) { $retval[$val] = &File_Find::mapTreeMultiple($path, $maxrecursion, $count); } } } }
return $retval; }
/** * Search the specified directory tree with the specified pattern. Return * an array containing all matching files (no directories included). * * @param string $pattern the pattern to match every file with. * * @param string $directory the directory tree to search in. * * @param string $type the type of regular expression support to use, either * 'php', 'perl' or 'shell'. * * @param bool $fullpath whether the regex should be matched against the * full path or only against the filename * * @param string $match can be either 'files', 'dirs' or 'both' to specify * the kind of list to return * * @return array a list of files matching the pattern parameter in the the * directory path specified by the directory parameter * * @author Sterling Hughes <sterling@php.net> * @access public * @static */ function &search($pattern, $directory, $type = 'php', $fullpath = true, $match = 'files') {
$matches = array(); list ($directories,$files) = File_Find::maptree($directory); switch($match) { case 'directories': $data = $directories; break; case 'both': $data = array_merge($directories, $files); break; case 'files': default: $data = $files; } unset($files, $directories);
$match_function = File_Find::_determineRegex($pattern, $type);
reset($data); // check if empty string given (ok for 'shell' method, but bad for others) if ($pattern || ($type != 'php' && $type != 'perl')) { while (list(,$entry) = each($data)) { if ($match_function($pattern, $fullpath ? $entry : basename($entry))) { $matches[] = $entry; } } }
sort($matches);
return $matches; }
/** * Determine whether or not a variable is a PEAR error * * @param object PEAR_Error $var the variable to test. * * @return boolean returns true if the variable is a PEAR error, otherwise * it returns false. * @access public */ function isError(&$var) { return PEAR::isError($var); }
/** * internal function to build singular directory trees, used by * File_Find::maptree() * * @param string $directory name of the directory to read * @param string $separator directory separator * @return void */ function _build($directory, $separator = "/") {
$dh = @opendir($directory);
if (!$dh) { $pe = PEAR::raiseError("Cannot open directory"); return $pe; }
while (false !== ($entry = @readdir($dh))) { if ($entry != '.' && $entry != '..') {
$entry = $directory.$separator.$entry;
if (is_dir($entry)) { array_push($this->_dirs, $entry); } else { array_push($this->files, $entry); } } }
@closedir($dh); }
/** * internal function to determine the type of regular expression to * use, implemented by File_Find::glob() and File_Find::search() * * @param string $type given RegExp type * @return string kind of function ( "eregi", "ereg" or "preg_match") ; * */ function _determineRegex($pattern, $type) { if (!strcasecmp($type, 'shell')) { $match_function = 'File_Find_match_shell'; } else if (!strcasecmp($type, 'perl')) { $match_function = 'preg_match'; } else if (!strcasecmp(substr($pattern, -2), '/i')) { $match_function = 'eregi'; } else { $match_function = 'ereg'; } return $match_function; }
}
/** * Package method to match via 'shell' pattern. Provided in global * scope, because it should be called like 'preg_match' and 'eregi' * and can be easily copied into other packages * * @author techtonik <techtonik@php.net> * @return mixed bool on success and PEAR_Error on failure */ function File_Find_match_shell($pattern, $filename) { // {{{ convert pattern to positive and negative regexps $positive = $pattern; $negation = substr_count($pattern, "|");
if ($negation > 1) { PEAR::raiseError("Mask string contains errors!"); return FALSE; } elseif ($negation) { list($positive, $negative) = explode("|", $pattern); if (strlen($negative) == 0) { PEAR::raiseError("File-mask string contains errors!"); return FALSE; } }
$positive = _File_Find_match_shell_get_pattern($positive); if ($negation) { $negative = _File_Find_match_shell_get_pattern($negative); } // }}} convert end
if (defined("FILE_FIND_DEBUG")) { print("Method: $type\nPattern: $pattern\n Converted pattern:"); print_r($positive); if (isset($negative)) print_r($negative); }
if (!preg_match($positive, $filename)) { return FALSE; } else { if (isset($negative) && preg_match($negative, $filename)) { return FALSE; } else { return TRUE; } } }
/** * function used by File_Find_match_shell to convert 'shell' mask * into pcre regexp. Some of the rules (see testcases for more): * escaping all special chars and replacing * . with \. * * with .* * ? with .{1} * also adding ^ and $ as the pattern matches whole filename * * @author techtonik <techtonik@php.net> * @return string pcre regexp for preg_match */ function _File_Find_match_shell_get_pattern($mask) { // get array of several masks (if any) delimited by comma // do not touch commas in char class $premasks = preg_split("|(\[[^\]]+\])|", $mask, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); if (defined("FILE_FIND_DEBUG")) { print("\nPremask: "); print_r($premasks); } $pi = 0; foreach($premasks as $pm) { if (!isset($masks[$pi])) $masks[$pi] = ""; if ($pm{0} == '[' && $pm{strlen($pm)-1} == ']') { // strip commas from character class $masks[$pi] .= str_replace(",", "", $pm); } else { $tarr = explode(",", $pm); if (sizeof($tarr) == 1) { $masks[$pi] .= $pm; } else { foreach ($tarr as $te) { $masks[$pi++] .= $te; $masks[$pi] = ""; } unset($masks[$pi--]); } } }
// if empty string given return *.* pattern if (strlen($mask) == 0) return "!^.*$!";
// convert to preg regexp $regexmask = implode("|", $masks); if (defined("FILE_FIND_DEBUG")) { print("regexMask step one(implode): $regexmask"); } $regexmask = addcslashes($regexmask, '^$}!{)(\/.+'); if (defined("FILE_FIND_DEBUG")) { print("\nregexMask step two(addcslashes): $regexmask"); } $regexmask = preg_replace("!(\*|\?)!", ".$1", $regexmask); if (defined("FILE_FIND_DEBUG")) { print("\nregexMask step three(* ? -> .* .?): $regexmask"); } // a special case '*.' at the end means that there is no extension $regexmask = preg_replace("!\.\*\\\.(\||$)!", "[^\.]*$1", $regexmask); // it is impossible to have dot at the end of filename $regexmask = preg_replace("!\\\.(\||$)!", "$1", $regexmask); // and .* at the end also means that there could be nothing at all // (i.e. no dot at the end also) $regexmask = preg_replace("!\\\.\.\*(\||$)!", "(\\\\..*)?$1", $regexmask); if (defined("FILE_FIND_DEBUG")) { print("\nregexMask step two and half(*.$ \\..*$ .$ -> [^.]*$ .?.* $): $regexmask"); } // if no extension supplied - add .* to match partially from filename start if (strpos($regexmask, "\\.") === FALSE) $regexmask .= ".*";
// file mask match whole name - adding restrictions $regexmask = preg_replace("!(\|)!", '^'."$1".'$', $regexmask); $regexmask = '^'.$regexmask.'$'; if (defined("FILE_FIND_DEBUG")) { print("\nregexMask step three(^ and $ to match whole name): $regexmask"); } // wrap regex into ! since all ! are already escaped $regexmask = "!$regexmask!i"; if (defined("FILE_FIND_DEBUG")) { print("\nWrapped regex: $regexmask\n"); } return $regexmask; }
/* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: */
?>
|