Chris@0: GLOB_MARK, Chris@0: self::GLOB_NOSORT => GLOB_NOSORT, Chris@0: self::GLOB_NOCHECK => GLOB_NOCHECK, Chris@0: self::GLOB_NOESCAPE => GLOB_NOESCAPE, Chris@0: self::GLOB_BRACE => defined('GLOB_BRACE') ? GLOB_BRACE : 0, Chris@0: self::GLOB_ONLYDIR => GLOB_ONLYDIR, Chris@0: self::GLOB_ERR => GLOB_ERR, Chris@0: ]; Chris@0: Chris@0: $globFlags = 0; Chris@0: Chris@0: foreach ($flagMap as $internalFlag => $globFlag) { Chris@0: if ($flags & $internalFlag) { Chris@0: $globFlags |= $globFlag; Chris@0: } Chris@0: } Chris@0: } else { Chris@0: $globFlags = 0; Chris@0: } Chris@0: Chris@0: ErrorHandler::start(); Chris@0: $res = glob($pattern, $globFlags); Chris@0: $err = ErrorHandler::stop(); Chris@0: if ($res === false) { Chris@0: throw new Exception\RuntimeException("glob('{$pattern}', {$globFlags}) failed", 0, $err); Chris@0: } Chris@0: return $res; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Expand braces manually, then use the system glob. Chris@0: * Chris@0: * @param string $pattern Chris@0: * @param int $flags Chris@0: * @return array Chris@0: * @throws Exception\RuntimeException Chris@0: */ Chris@0: protected static function fallbackGlob($pattern, $flags) Chris@0: { Chris@12: if (! $flags & self::GLOB_BRACE) { Chris@0: return static::systemGlob($pattern, $flags); Chris@0: } Chris@0: Chris@0: $flags &= ~self::GLOB_BRACE; Chris@0: $length = strlen($pattern); Chris@0: $paths = []; Chris@0: Chris@0: if ($flags & self::GLOB_NOESCAPE) { Chris@0: $begin = strpos($pattern, '{'); Chris@0: } else { Chris@0: $begin = 0; Chris@0: Chris@0: while (true) { Chris@0: if ($begin === $length) { Chris@0: $begin = false; Chris@0: break; Chris@0: } elseif ($pattern[$begin] === '\\' && ($begin + 1) < $length) { Chris@0: $begin++; Chris@0: } elseif ($pattern[$begin] === '{') { Chris@0: break; Chris@0: } Chris@0: Chris@0: $begin++; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($begin === false) { Chris@0: return static::systemGlob($pattern, $flags); Chris@0: } Chris@0: Chris@0: $next = static::nextBraceSub($pattern, $begin + 1, $flags); Chris@0: Chris@0: if ($next === null) { Chris@0: return static::systemGlob($pattern, $flags); Chris@0: } Chris@0: Chris@0: $rest = $next; Chris@0: Chris@0: while ($pattern[$rest] !== '}') { Chris@0: $rest = static::nextBraceSub($pattern, $rest + 1, $flags); Chris@0: Chris@0: if ($rest === null) { Chris@0: return static::systemGlob($pattern, $flags); Chris@0: } Chris@0: } Chris@0: Chris@0: $p = $begin + 1; Chris@0: Chris@0: while (true) { Chris@0: $subPattern = substr($pattern, 0, $begin) Chris@0: . substr($pattern, $p, $next - $p) Chris@0: . substr($pattern, $rest + 1); Chris@0: Chris@0: $result = static::fallbackGlob($subPattern, $flags | self::GLOB_BRACE); Chris@0: Chris@0: if ($result) { Chris@0: $paths = array_merge($paths, $result); Chris@0: } Chris@0: Chris@0: if ($pattern[$next] === '}') { Chris@0: break; Chris@0: } Chris@0: Chris@0: $p = $next + 1; Chris@0: $next = static::nextBraceSub($pattern, $p, $flags); Chris@0: } Chris@0: Chris@0: return array_unique($paths); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Find the end of the sub-pattern in a brace expression. Chris@0: * Chris@0: * @param string $pattern Chris@0: * @param int $begin Chris@0: * @param int $flags Chris@0: * @return int|null Chris@0: */ Chris@0: protected static function nextBraceSub($pattern, $begin, $flags) Chris@0: { Chris@0: $length = strlen($pattern); Chris@0: $depth = 0; Chris@0: $current = $begin; Chris@0: Chris@0: while ($current < $length) { Chris@12: if (! $flags & self::GLOB_NOESCAPE && $pattern[$current] === '\\') { Chris@0: if (++$current === $length) { Chris@0: break; Chris@0: } Chris@0: Chris@0: $current++; Chris@0: } else { Chris@0: if (($pattern[$current] === '}' && $depth-- === 0) || ($pattern[$current] === ',' && $depth === 0)) { Chris@0: break; Chris@0: } elseif ($pattern[$current++] === '{') { Chris@0: $depth++; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return ($current < $length ? $current : null); Chris@0: } Chris@0: }