diff options
Diffstat (limited to 'web/lib/Find.php')
-rw-r--r-- | web/lib/Find.php | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/web/lib/Find.php b/web/lib/Find.php new file mode 100644 index 00000000..62fc33ff --- /dev/null +++ b/web/lib/Find.php @@ -0,0 +1,485 @@ +<?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,v 1.27 2006/06/30 14:06:16 techtonik Exp $ +// + +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,v 1.27 2006/06/30 14:06:16 techtonik Exp $ +* @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; + } + + 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); + } + + $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); + } + + 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; + } + } + } + + 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: + */ + +?> |