Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
76.19% |
16 / 21 |
CRAP | |
92.47% |
172 / 186 |
finder | |
0.00% |
0 / 1 |
|
76.19% |
16 / 21 |
61.54 | |
92.47% |
172 / 186 |
__construct | |
100.00% |
1 / 1 |
2 | |
100.00% |
16 / 16 |
|||
set_extensions | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
core_path | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
suffix | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
extension_suffix | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
core_suffix | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
prefix | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
extension_prefix | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
core_prefix | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
directory | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
extension_directory | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
core_directory | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
sanitise_directory | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
get_classes | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
get_classes_from_files | |
100.00% |
1 / 1 |
4 | |
100.00% |
12 / 12 |
|||
get_directories | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
get_files | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
find_with_root_path | |
0.00% |
0 / 1 |
3.10 | |
77.78% |
7 / 9 |
|||
find | |
100.00% |
1 / 1 |
3 | |
100.00% |
11 / 11 |
|||
find_from_extension | |
100.00% |
1 / 1 |
2 | |
100.00% |
8 / 8 |
|||
find_from_paths | |
0.00% |
0 / 1 |
27.24 | |
93.10% |
81 / 87 |
<?php | |
/** | |
* | |
* This file is part of the phpBB Forum Software package. | |
* | |
* @copyright (c) phpBB Limited <https://www.phpbb.com> | |
* @license GNU General Public License, version 2 (GPL-2.0) | |
* | |
* For full copyright and license information, please see | |
* the docs/CREDITS.txt file. | |
* | |
*/ | |
namespace phpbb; | |
/** | |
* The finder provides a simple way to locate files in the core and a set of extensions | |
*/ | |
class finder | |
{ | |
protected $extensions; | |
protected $filesystem; | |
protected $phpbb_root_path; | |
protected $cache; | |
protected $php_ext; | |
/** | |
* The cache variable name used to store $this->cached_queries in $this->cache. | |
* | |
* Allows the use of multiple differently configured finders with the same cache. | |
* @var string | |
*/ | |
protected $cache_name; | |
/** | |
* An associative array, containing all search parameters set in methods. | |
* @var array | |
*/ | |
protected $query; | |
/** | |
* A map from md5 hashes of serialized queries to their previously retrieved | |
* results. | |
* @var array | |
*/ | |
protected $cached_queries; | |
/** | |
* Creates a new finder instance with its dependencies | |
* | |
* @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem instance | |
* @param string $phpbb_root_path Path to the phpbb root directory | |
* @param \phpbb\cache\service $cache A cache instance or null | |
* @param string $php_ext php file extension | |
* @param string $cache_name The name of the cache variable, defaults to | |
* _ext_finder | |
*/ | |
public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path = '', \phpbb\cache\service $cache = null, $php_ext = 'php', $cache_name = '_ext_finder') | |
{ | |
$this->filesystem = $filesystem; | |
$this->phpbb_root_path = $phpbb_root_path; | |
$this->cache = $cache; | |
$this->php_ext = $php_ext; | |
$this->cache_name = $cache_name; | |
$this->query = array( | |
'core_path' => false, | |
'core_suffix' => false, | |
'core_prefix' => false, | |
'core_directory' => false, | |
'extension_suffix' => false, | |
'extension_prefix' => false, | |
'extension_directory' => false, | |
); | |
$this->extensions = array(); | |
$this->cached_queries = ($this->cache) ? $this->cache->get($this->cache_name) : false; | |
} | |
/** | |
* Set the array of extensions | |
* | |
* @param array $extensions A list of extensions that should be searched aswell | |
* @param bool $replace_list Should the list be emptied before adding the extensions | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function set_extensions(array $extensions, $replace_list = true) | |
{ | |
if ($replace_list) | |
{ | |
$this->extensions = array(); | |
} | |
foreach ($extensions as $ext_name) | |
{ | |
$this->extensions[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; | |
} | |
return $this; | |
} | |
/** | |
* Sets a core path to be searched in addition to extensions | |
* | |
* @param string $core_path The path relative to phpbb_root_path | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function core_path($core_path) | |
{ | |
$this->query['core_path'] = $core_path; | |
return $this; | |
} | |
/** | |
* Sets the suffix all files found in extensions and core must match. | |
* | |
* There is no default file extension, so to find PHP files only, you will | |
* have to specify .php as a suffix. However when using get_classes, the .php | |
* file extension is automatically added to suffixes. | |
* | |
* @param string $suffix A filename suffix | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function suffix($suffix) | |
{ | |
$this->core_suffix($suffix); | |
$this->extension_suffix($suffix); | |
return $this; | |
} | |
/** | |
* Sets a suffix all files found in extensions must match | |
* | |
* There is no default file extension, so to find PHP files only, you will | |
* have to specify .php as a suffix. However when using get_classes, the .php | |
* file extension is automatically added to suffixes. | |
* | |
* @param string $extension_suffix A filename suffix | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function extension_suffix($extension_suffix) | |
{ | |
$this->query['extension_suffix'] = $extension_suffix; | |
return $this; | |
} | |
/** | |
* Sets a suffix all files found in the core path must match | |
* | |
* There is no default file extension, so to find PHP files only, you will | |
* have to specify .php as a suffix. However when using get_classes, the .php | |
* file extension is automatically added to suffixes. | |
* | |
* @param string $core_suffix A filename suffix | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function core_suffix($core_suffix) | |
{ | |
$this->query['core_suffix'] = $core_suffix; | |
return $this; | |
} | |
/** | |
* Sets the prefix all files found in extensions and core must match | |
* | |
* @param string $prefix A filename prefix | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function prefix($prefix) | |
{ | |
$this->core_prefix($prefix); | |
$this->extension_prefix($prefix); | |
return $this; | |
} | |
/** | |
* Sets a prefix all files found in extensions must match | |
* | |
* @param string $extension_prefix A filename prefix | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function extension_prefix($extension_prefix) | |
{ | |
$this->query['extension_prefix'] = $extension_prefix; | |
return $this; | |
} | |
/** | |
* Sets a prefix all files found in the core path must match | |
* | |
* @param string $core_prefix A filename prefix | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function core_prefix($core_prefix) | |
{ | |
$this->query['core_prefix'] = $core_prefix; | |
return $this; | |
} | |
/** | |
* Sets a directory all files found in extensions and core must be contained in | |
* | |
* Automatically sets the core_directory if its value does not differ from | |
* the current directory. | |
* | |
* @param string $directory | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function directory($directory) | |
{ | |
$this->core_directory($directory); | |
$this->extension_directory($directory); | |
return $this; | |
} | |
/** | |
* Sets a directory all files found in extensions must be contained in | |
* | |
* @param string $extension_directory | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function extension_directory($extension_directory) | |
{ | |
$this->query['extension_directory'] = $this->sanitise_directory($extension_directory); | |
return $this; | |
} | |
/** | |
* Sets a directory all files found in the core path must be contained in | |
* | |
* @param string $core_directory | |
* @return \phpbb\finder This object for chaining calls | |
*/ | |
public function core_directory($core_directory) | |
{ | |
$this->query['core_directory'] = $this->sanitise_directory($core_directory); | |
return $this; | |
} | |
/** | |
* Removes occurances of /./ and makes sure path ends without trailing slash | |
* | |
* @param string $directory A directory pattern | |
* @return string A cleaned up directory pattern | |
*/ | |
protected function sanitise_directory($directory) | |
{ | |
$directory = $this->filesystem->clean_path($directory); | |
$dir_len = strlen($directory); | |
if ($dir_len > 1 && $directory[$dir_len - 1] === '/') | |
{ | |
$directory = substr($directory, 0, -1); | |
} | |
return $directory; | |
} | |
/** | |
* Finds classes matching the configured options if they follow phpBB naming rules. | |
* | |
* The php file extension is automatically added to suffixes. | |
* | |
* Note: If a file is matched but contains a class name not following the | |
* phpBB naming rules an incorrect class name will be returned. | |
* | |
* @param bool $cache Whether the result should be cached | |
* @return array An array of found class names | |
*/ | |
public function get_classes($cache = true) | |
{ | |
$this->query['extension_suffix'] .= '.' . $this->php_ext; | |
$this->query['core_suffix'] .= '.' . $this->php_ext; | |
$files = $this->find($cache, false); | |
return $this->get_classes_from_files($files); | |
} | |
/** | |
* Get class names from a list of files | |
* | |
* @param array $files Array of files (from find()) | |
* @return array Array of class names | |
*/ | |
public function get_classes_from_files($files) | |
{ | |
$classes = array(); | |
foreach ($files as $file => $ext_name) | |
{ | |
$class = substr($file, 0, -strlen('.' . $this->php_ext)); | |
if ($ext_name === '/' && preg_match('#^includes/#', $file)) | |
{ | |
$class = preg_replace('#^includes/#', '', $class); | |
$classes[] = 'phpbb_' . str_replace('/', '_', $class); | |
} | |
else | |
{ | |
$class = preg_replace('#^ext/#', '', $class); | |
$classes[] = '\\' . str_replace('/', '\\', $class); | |
} | |
} | |
return $classes; | |
} | |
/** | |
* Finds all directories matching the configured options | |
* | |
* @param bool $cache Whether the result should be cached | |
* @param bool $extension_keys Whether the result should have extension name as array key | |
* @return array An array of paths to found directories | |
*/ | |
public function get_directories($cache = true, $extension_keys = false) | |
{ | |
return $this->find_with_root_path($cache, true, $extension_keys); | |
} | |
/** | |
* Finds all files matching the configured options. | |
* | |
* @param bool $cache Whether the result should be cached | |
* @return array An array of paths to found files | |
*/ | |
public function get_files($cache = true) | |
{ | |
return $this->find_with_root_path($cache, false); | |
} | |
/** | |
* A wrapper around the general find which prepends a root path to results | |
* | |
* @param bool $cache Whether the result should be cached | |
* @param bool $is_dir Directories will be returned when true, only files | |
* otherwise | |
* @param bool $extension_keys If true, result will be associative array | |
* with extension name as key | |
* @return array An array of paths to found items | |
*/ | |
protected function find_with_root_path($cache = true, $is_dir = false, $extension_keys = false) | |
{ | |
$items = $this->find($cache, $is_dir); | |
$result = array(); | |
foreach ($items as $item => $ext_name) | |
{ | |
if ($extension_keys) | |
{ | |
$result[$ext_name] = $this->phpbb_root_path . $item; | |
} | |
else | |
{ | |
$result[] = $this->phpbb_root_path . $item; | |
} | |
} | |
return $result; | |
} | |
/** | |
* Finds all file system entries matching the configured options | |
* | |
* @param bool $cache Whether the result should be cached | |
* @param bool $is_dir Directories will be returned when true, only files | |
* otherwise | |
* @return array An array of paths to found items | |
*/ | |
public function find($cache = true, $is_dir = false) | |
{ | |
$extensions = $this->extensions; | |
if ($this->query['core_path']) | |
{ | |
$extensions['/'] = $this->phpbb_root_path . $this->query['core_path']; | |
} | |
$files = array(); | |
$file_list = $this->find_from_paths($extensions, $cache, $is_dir); | |
foreach ($file_list as $file) | |
{ | |
$files[$file['named_path']] = $file['ext_name']; | |
} | |
return $files; | |
} | |
/** | |
* Finds all file system entries matching the configured options for one | |
* specific extension | |
* | |
* @param string $extension_name Name of the extension | |
* @param string $extension_path Relative path to the extension root directory | |
* @param bool $cache Whether the result should be cached | |
* @param bool $is_dir Directories will be returned when true, only files | |
* otherwise | |
* @return array An array of paths to found items | |
*/ | |
public function find_from_extension($extension_name, $extension_path, $cache = true, $is_dir = false) | |
{ | |
$extensions = array( | |
$extension_name => $extension_path, | |
); | |
$files = array(); | |
$file_list = $this->find_from_paths($extensions, $cache, $is_dir); | |
foreach ($file_list as $file) | |
{ | |
$files[$file['named_path']] = $file['ext_name']; | |
} | |
return $files; | |
} | |
/** | |
* Finds all file system entries matching the configured options from | |
* an array of paths | |
* | |
* @param array $extensions Array of extensions (name => full relative path) | |
* @param bool $cache Whether the result should be cached | |
* @param bool $is_dir Directories will be returned when true, only files | |
* otherwise | |
* @return array An array of paths to found items | |
*/ | |
public function find_from_paths($extensions, $cache = true, $is_dir = false) | |
{ | |
$this->query['is_dir'] = $is_dir; | |
$query = md5(serialize($this->query) . serialize($extensions)); | |
if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query])) | |
{ | |
return $this->cached_queries[$query]; | |
} | |
$files = array(); | |
foreach ($extensions as $name => $path) | |
{ | |
$ext_name = $name; | |
if (!file_exists($path)) | |
{ | |
continue; | |
} | |
if ($name === '/') | |
{ | |
$location = $this->query['core_path']; | |
$name = ''; | |
$suffix = $this->query['core_suffix']; | |
$prefix = $this->query['core_prefix']; | |
$directory = $this->query['core_directory']; | |
} | |
else | |
{ | |
$location = 'ext/'; | |
$name .= '/'; | |
$suffix = $this->query['extension_suffix']; | |
$prefix = $this->query['extension_prefix']; | |
$directory = $this->query['extension_directory']; | |
} | |
// match only first directory if leading slash is given | |
if ($directory === '/') | |
{ | |
$directory_pattern = '^' . preg_quote(DIRECTORY_SEPARATOR, '#'); | |
} | |
else if ($directory && $directory[0] === '/') | |
{ | |
if (!$is_dir) | |
{ | |
$path .= substr($directory, 1); | |
} | |
$directory_pattern = '^' . preg_quote(str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); | |
} | |
else | |
{ | |
$directory_pattern = preg_quote(DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); | |
} | |
if ($is_dir) | |
{ | |
$directory_pattern .= '$'; | |
} | |
$directory_pattern = '#' . $directory_pattern . '#'; | |
if (is_dir($path)) | |
{ | |
$iterator = new \RecursiveIteratorIterator( | |
new \phpbb\recursive_dot_prefix_filter_iterator( | |
new \RecursiveDirectoryIterator( | |
$path, | |
\FilesystemIterator::SKIP_DOTS | |
) | |
), | |
\RecursiveIteratorIterator::SELF_FIRST | |
); | |
foreach ($iterator as $file_info) | |
{ | |
$filename = $file_info->getFilename(); | |
if ($file_info->isDir() == $is_dir) | |
{ | |
if ($is_dir) | |
{ | |
$relative_path = $iterator->getInnerIterator()->getSubPath() . DIRECTORY_SEPARATOR . basename($filename) . DIRECTORY_SEPARATOR; | |
if ($relative_path[0] !== DIRECTORY_SEPARATOR) | |
{ | |
$relative_path = DIRECTORY_SEPARATOR . $relative_path; | |
} | |
} | |
else | |
{ | |
$relative_path = $iterator->getInnerIterator()->getSubPathname(); | |
if ($directory && $directory[0] === '/') | |
{ | |
$relative_path = str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR . $relative_path; | |
} | |
else | |
{ | |
$relative_path = DIRECTORY_SEPARATOR . $relative_path; | |
} | |
} | |
if ((!$suffix || substr($relative_path, -strlen($suffix)) === $suffix) && | |
(!$prefix || substr($filename, 0, strlen($prefix)) === $prefix) && | |
(!$directory || preg_match($directory_pattern, $relative_path))) | |
{ | |
$files[] = array( | |
'named_path' => str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1)), | |
'ext_name' => $ext_name, | |
'path' => str_replace(array(DIRECTORY_SEPARATOR, $this->phpbb_root_path), array('/', ''), $file_info->getPath()) . '/', | |
'filename' => $filename, | |
); | |
} | |
} | |
} | |
} | |
} | |
if ($cache && $this->cache) | |
{ | |
$this->cached_queries[$query] = $files; | |
$this->cache->put($this->cache_name, $this->cached_queries); | |
} | |
return $files; | |
} | |
} |