Commit 86b4c4ee by John Was

improved comments, method visiblity and exceptions

parent 49e2c493
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
namespace yii\helpers; namespace yii\helpers;
use Yii; use Yii;
use yii\base\InvalidParamException;
/** /**
* BaseFileHelper provides concrete implementation for [[FileHelper]]. * BaseFileHelper provides concrete implementation for [[FileHelper]].
...@@ -251,17 +252,27 @@ class BaseFileHelper ...@@ -251,17 +252,27 @@ class BaseFileHelper
* both '/' and '\' in the paths. * both '/' and '\' in the paths.
* - recursive: boolean, whether the files under the subdirectories should also be looked for. Defaults to true. * - recursive: boolean, whether the files under the subdirectories should also be looked for. Defaults to true.
* @return array files found under the directory. The file list is sorted. * @return array files found under the directory. The file list is sorted.
* @throws InvalidParamException if the dir is invalid.
*/ */
public static function findFiles($dir, $options = []) public static function findFiles($dir, $options = [])
{ {
if (!is_dir($dir)) {
throw new InvalidParamException('The dir argument must be a directory.');
}
if (!isset($options['basePath'])) { if (!isset($options['basePath'])) {
$options['basePath'] = realpath($dir); $options['basePath'] = realpath($dir);
// this should also be done only once // this should also be done only once
if (isset($options['except'])) { if (isset($options['except'])) {
$options['except'] = array_map(array(__CLASS__, 'parseExcludePattern'), $options['except']); foreach($options['except'] as $key=>$value) {
if (is_string($value))
$options['except'][$key] = static::parseExcludePattern($value);
}
} }
if (isset($options['only'])) { if (isset($options['only'])) {
$options['only'] = array_map(array(__CLASS__, 'parseExcludePattern'), $options['only']); foreach($options['only'] as $key=>$value) {
if (is_string($value))
$options['only'][$key] = static::parseExcludePattern($value);
}
} }
} }
$list = []; $list = [];
...@@ -304,9 +315,6 @@ class BaseFileHelper ...@@ -304,9 +315,6 @@ class BaseFileHelper
} }
$path = str_replace('\\', '/', $path); $path = str_replace('\\', '/', $path);
/*if ($isDir = is_dir($path)) {
$path .= '/';
}*/
if (!empty($options['except'])) { if (!empty($options['except'])) {
if (($except=self::lastExcludeMatchingFromList($options['basePath'], $path, $options['except'])) !== null) { if (($except=self::lastExcludeMatchingFromList($options['basePath'], $path, $options['except'])) !== null) {
...@@ -350,9 +358,20 @@ class BaseFileHelper ...@@ -350,9 +358,20 @@ class BaseFileHelper
return $result; return $result;
} }
public static function matchBasename($baseName, $pattern, $hasWildcard, $flags) /**
* Performs a simple comparison of file or directory names.
*
* Based on match_basename() from dir.c of git 1.8.5.3 sources.
*
* @param string $baseName file or directory name to compare with the pattern
* @param string $pattern the pattern that $baseName will be compared against
* @param integer|boolean $firstWildcard location of first wildcard character in the $pattern
* @param integer $flags pattern flags
* @return boolean wheter the name matches against pattern
*/
private static function matchBasename($baseName, $pattern, $firstWildcard, $flags)
{ {
if ($hasWildcard === false) { if ($firstWildcard === false) {
if ($pattern === $baseName) { if ($pattern === $baseName) {
return true; return true;
} }
...@@ -366,33 +385,45 @@ class BaseFileHelper ...@@ -366,33 +385,45 @@ class BaseFileHelper
return fnmatch($pattern, $baseName, 0); return fnmatch($pattern, $baseName, 0);
} }
public static function matchPathname($path, $basePath, $pattern, $prefix, $flags) /**
* Compares a path part against a pattern with optional wildcards.
*
* Based on match_pathname() from dir.c of git 1.8.5.3 sources.
*
* @param string $path full path to compare
* @param string $basePath base of path that will not be compared
* @param string $pattern the pattern that path part will be compared against
* @param integer|boolean $firstWildcard location of first wildcard character in the $pattern
* @param integer $flags pattern flags
* @return boolean wheter the path part matches against pattern
*/
private static function matchPathname($path, $basePath, $pattern, $firstWildcard, $flags)
{ {
// match with FNM_PATHNAME; the pattern has base implicitly in front of it. // match with FNM_PATHNAME; the pattern has base implicitly in front of it.
if (isset($pattern[0]) && $pattern[0] == '/') { if (isset($pattern[0]) && $pattern[0] == '/') {
$pattern = StringHelper::byteSubstr($pattern, 1, StringHelper::byteLength($pattern)); $pattern = StringHelper::byteSubstr($pattern, 1, StringHelper::byteLength($pattern));
if ($prefix !== 0) { if ($firstWildcard !== false && $firstWildcard !== 0) {
$prefix--; $firstWildcard--;
} }
} }
$namelen = StringHelper::byteLength($path) - (empty($basePath) ? 0 : StringHelper::byteLength($basePath) + 1); $namelen = StringHelper::byteLength($path) - (empty($basePath) ? 0 : StringHelper::byteLength($basePath) + 1);
$name = StringHelper::byteSubstr($path, -$namelen, $namelen); $name = StringHelper::byteSubstr($path, -$namelen, $namelen);
if ($prefix !== 0) { if ($firstWildcard !== 0) {
if ($prefix === false) { if ($firstWildcard === false) {
$prefix = StringHelper::byteLength($pattern); $firstWildcard = StringHelper::byteLength($pattern);
} }
// if the non-wildcard part is longer than the remaining pathname, surely it cannot match. // if the non-wildcard part is longer than the remaining pathname, surely it cannot match.
if ($prefix > $namelen) { if ($firstWildcard > $namelen) {
return false; return false;
} }
if (strncmp($pattern, $name, $prefix)) { if (strncmp($pattern, $name, $firstWildcard)) {
return false; return false;
} }
$pattern = StringHelper::byteSubstr($pattern, $prefix, StringHelper::byteLength($pattern)); $pattern = StringHelper::byteSubstr($pattern, $firstWildcard, StringHelper::byteLength($pattern));
$name = StringHelper::byteSubstr($name, $prefix, $namelen); $name = StringHelper::byteSubstr($name, $firstWildcard, $namelen);
// If the whole pattern did not have a wildcard, then our prefix match is all we need; we do not need to call fnmatch at all. // If the whole pattern did not have a wildcard, then our prefix match is all we need; we do not need to call fnmatch at all.
if (empty($pattern) && empty($name)) { if (empty($pattern) && empty($name)) {
...@@ -415,40 +446,50 @@ class BaseFileHelper ...@@ -415,40 +446,50 @@ class BaseFileHelper
* @param string $path * @param string $path
* @param array $excludes list of patterns to match $path against * @param array $excludes list of patterns to match $path against
* @return string null or one of $excludes item as an array with keys: 'pattern', 'flags' * @return string null or one of $excludes item as an array with keys: 'pattern', 'flags'
* @throws InvalidParamException if any of the exclude patterns is not a string or an array with keys: pattern, flags, firstWildcard.
*/ */
public static function lastExcludeMatchingFromList($basePath, $path, $excludes) private static function lastExcludeMatchingFromList($basePath, $path, $excludes)
{ {
foreach(array_reverse($excludes) as $exclude) { foreach(array_reverse($excludes) as $exclude) {
if (is_string($exclude)) { if (is_string($exclude)) {
$exclude = self::parseExcludePattern($exclude); $exclude = self::parseExcludePattern($exclude);
} }
if (!isset($exclude['pattern']) || !isset($exclude['flags']) || !isset($exclude['firstWildcard'])) {
throw new InvalidParamException('If exclude/include pattern is an array it must contain the pattern, flags and firstWildcard keys.');
}
if ($exclude['flags'] & self::EXC_FLAG_MUSTBEDIR && !is_dir($path)) { if ($exclude['flags'] & self::EXC_FLAG_MUSTBEDIR && !is_dir($path)) {
continue; continue;
} }
if ($exclude['flags'] & self::EXC_FLAG_NODIR) { if ($exclude['flags'] & self::EXC_FLAG_NODIR) {
if (self::matchBasename(basename($path), $exclude['pattern'], $exclude['hasWildcard'], $exclude['flags'])) { if (self::matchBasename(basename($path), $exclude['pattern'], $exclude['firstWildcard'], $exclude['flags'])) {
return $exclude; return $exclude;
} }
continue; continue;
} }
if (self::matchPathname($path, $basePath, $exclude['pattern'], $exclude['hasWildcard'], $exclude['flags'])) { if (self::matchPathname($path, $basePath, $exclude['pattern'], $exclude['firstWildcard'], $exclude['flags'])) {
return $exclude; return $exclude;
} }
} }
return null; return null;
} }
public static function parseExcludePattern($pattern) /**
* Processes the pattern, stripping special characters like / and ! from the beginning and settings flags instead.
* @param string $pattern
* @return array with keys: (string)pattern, (int)flags, (int|boolean)firstWildcard
* @throws InvalidParamException if the pattern is not a string.
*/
private static function parseExcludePattern($pattern)
{ {
if (!is_string($pattern)) { if (!is_string($pattern)) {
throw new \yii\base\Exception('Exclude/include pattern must be a string.'); throw new InvalidParamException('Exclude/include pattern must be a string.');
} }
$result = array( $result = array(
'pattern' => $pattern, 'pattern' => $pattern,
'flags' => 0, 'flags' => 0,
'hasWildcard' => false, 'firstWildcard' => false,
); );
if (!isset($pattern[0])) if (!isset($pattern[0]))
return $result; return $result;
...@@ -465,14 +506,19 @@ class BaseFileHelper ...@@ -465,14 +506,19 @@ class BaseFileHelper
} }
if (strpos($pattern, '/') === false) if (strpos($pattern, '/') === false)
$result['flags'] |= self::EXC_FLAG_NODIR; $result['flags'] |= self::EXC_FLAG_NODIR;
$result['hasWildcard'] = self::firstWildcardInPattern($pattern); $result['firstWildcard'] = self::firstWildcardInPattern($pattern);
if ($pattern[0] == '*' && self::firstWildcardInPattern(StringHelper::byteSubstr($pattern, 1, StringHelper::byteLength($pattern))) === false) if ($pattern[0] == '*' && self::firstWildcardInPattern(StringHelper::byteSubstr($pattern, 1, StringHelper::byteLength($pattern))) === false)
$result['flags'] |= self::EXC_FLAG_ENDSWITH; $result['flags'] |= self::EXC_FLAG_ENDSWITH;
$result['pattern'] = $pattern; $result['pattern'] = $pattern;
return $result; return $result;
} }
public static function firstWildcardInPattern($pattern) /**
* Searches for the first wildcard character in the pattern.
* @param string $pattern the pattern to search in
* @return integer|boolean position of first wildcard character or false if not found
*/
private static function firstWildcardInPattern($pattern)
{ {
$wildcards = array('*','?','[','\\'); $wildcards = array('*','?','[','\\');
$wildcardSearch = function($r, $c) use ($pattern) { $wildcardSearch = function($r, $c) use ($pattern) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment