Blame | Letzte Änderung | Log anzeigen | RSS feed
<?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: Find.php 304090 2010-10-05 14:07:34Z clockwerx $//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: Find.php 304090 2010-10-05 14:07:34Z clockwerx $* @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' patternif ($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;} else {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)) {$path = $directory . "/" . $val;if (!is_array($val) && 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 endif (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 *.* patternif (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 startif (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:*/?>