Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Zend Framework (http://framework.zend.com/)
|
Chris@0
|
4 *
|
Chris@0
|
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
|
Chris@0
|
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
Chris@0
|
7 * @license http://framework.zend.com/license/new-bsd New BSD License
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 namespace Zend\Stdlib;
|
Chris@0
|
11
|
Chris@0
|
12 /**
|
Chris@0
|
13 * Wrapper for glob with fallback if GLOB_BRACE is not available.
|
Chris@0
|
14 */
|
Chris@0
|
15 abstract class Glob
|
Chris@0
|
16 {
|
Chris@0
|
17 /**#@+
|
Chris@0
|
18 * Glob constants.
|
Chris@0
|
19 */
|
Chris@0
|
20 const GLOB_MARK = 0x01;
|
Chris@0
|
21 const GLOB_NOSORT = 0x02;
|
Chris@0
|
22 const GLOB_NOCHECK = 0x04;
|
Chris@0
|
23 const GLOB_NOESCAPE = 0x08;
|
Chris@0
|
24 const GLOB_BRACE = 0x10;
|
Chris@0
|
25 const GLOB_ONLYDIR = 0x20;
|
Chris@0
|
26 const GLOB_ERR = 0x40;
|
Chris@0
|
27 /**#@-*/
|
Chris@0
|
28
|
Chris@0
|
29 /**
|
Chris@0
|
30 * Find pathnames matching a pattern.
|
Chris@0
|
31 *
|
Chris@0
|
32 * @see http://docs.php.net/glob
|
Chris@0
|
33 * @param string $pattern
|
Chris@0
|
34 * @param int $flags
|
Chris@0
|
35 * @param bool $forceFallback
|
Chris@0
|
36 * @return array
|
Chris@0
|
37 * @throws Exception\RuntimeException
|
Chris@0
|
38 */
|
Chris@0
|
39 public static function glob($pattern, $flags = 0, $forceFallback = false)
|
Chris@0
|
40 {
|
Chris@12
|
41 if (! defined('GLOB_BRACE') || $forceFallback) {
|
Chris@0
|
42 return static::fallbackGlob($pattern, $flags);
|
Chris@0
|
43 }
|
Chris@0
|
44
|
Chris@0
|
45 return static::systemGlob($pattern, $flags);
|
Chris@0
|
46 }
|
Chris@0
|
47
|
Chris@0
|
48 /**
|
Chris@0
|
49 * Use the glob function provided by the system.
|
Chris@0
|
50 *
|
Chris@0
|
51 * @param string $pattern
|
Chris@0
|
52 * @param int $flags
|
Chris@0
|
53 * @return array
|
Chris@0
|
54 * @throws Exception\RuntimeException
|
Chris@0
|
55 */
|
Chris@0
|
56 protected static function systemGlob($pattern, $flags)
|
Chris@0
|
57 {
|
Chris@0
|
58 if ($flags) {
|
Chris@0
|
59 $flagMap = [
|
Chris@0
|
60 self::GLOB_MARK => GLOB_MARK,
|
Chris@0
|
61 self::GLOB_NOSORT => GLOB_NOSORT,
|
Chris@0
|
62 self::GLOB_NOCHECK => GLOB_NOCHECK,
|
Chris@0
|
63 self::GLOB_NOESCAPE => GLOB_NOESCAPE,
|
Chris@0
|
64 self::GLOB_BRACE => defined('GLOB_BRACE') ? GLOB_BRACE : 0,
|
Chris@0
|
65 self::GLOB_ONLYDIR => GLOB_ONLYDIR,
|
Chris@0
|
66 self::GLOB_ERR => GLOB_ERR,
|
Chris@0
|
67 ];
|
Chris@0
|
68
|
Chris@0
|
69 $globFlags = 0;
|
Chris@0
|
70
|
Chris@0
|
71 foreach ($flagMap as $internalFlag => $globFlag) {
|
Chris@0
|
72 if ($flags & $internalFlag) {
|
Chris@0
|
73 $globFlags |= $globFlag;
|
Chris@0
|
74 }
|
Chris@0
|
75 }
|
Chris@0
|
76 } else {
|
Chris@0
|
77 $globFlags = 0;
|
Chris@0
|
78 }
|
Chris@0
|
79
|
Chris@0
|
80 ErrorHandler::start();
|
Chris@0
|
81 $res = glob($pattern, $globFlags);
|
Chris@0
|
82 $err = ErrorHandler::stop();
|
Chris@0
|
83 if ($res === false) {
|
Chris@0
|
84 throw new Exception\RuntimeException("glob('{$pattern}', {$globFlags}) failed", 0, $err);
|
Chris@0
|
85 }
|
Chris@0
|
86 return $res;
|
Chris@0
|
87 }
|
Chris@0
|
88
|
Chris@0
|
89 /**
|
Chris@0
|
90 * Expand braces manually, then use the system glob.
|
Chris@0
|
91 *
|
Chris@0
|
92 * @param string $pattern
|
Chris@0
|
93 * @param int $flags
|
Chris@0
|
94 * @return array
|
Chris@0
|
95 * @throws Exception\RuntimeException
|
Chris@0
|
96 */
|
Chris@0
|
97 protected static function fallbackGlob($pattern, $flags)
|
Chris@0
|
98 {
|
Chris@12
|
99 if (! $flags & self::GLOB_BRACE) {
|
Chris@0
|
100 return static::systemGlob($pattern, $flags);
|
Chris@0
|
101 }
|
Chris@0
|
102
|
Chris@0
|
103 $flags &= ~self::GLOB_BRACE;
|
Chris@0
|
104 $length = strlen($pattern);
|
Chris@0
|
105 $paths = [];
|
Chris@0
|
106
|
Chris@0
|
107 if ($flags & self::GLOB_NOESCAPE) {
|
Chris@0
|
108 $begin = strpos($pattern, '{');
|
Chris@0
|
109 } else {
|
Chris@0
|
110 $begin = 0;
|
Chris@0
|
111
|
Chris@0
|
112 while (true) {
|
Chris@0
|
113 if ($begin === $length) {
|
Chris@0
|
114 $begin = false;
|
Chris@0
|
115 break;
|
Chris@0
|
116 } elseif ($pattern[$begin] === '\\' && ($begin + 1) < $length) {
|
Chris@0
|
117 $begin++;
|
Chris@0
|
118 } elseif ($pattern[$begin] === '{') {
|
Chris@0
|
119 break;
|
Chris@0
|
120 }
|
Chris@0
|
121
|
Chris@0
|
122 $begin++;
|
Chris@0
|
123 }
|
Chris@0
|
124 }
|
Chris@0
|
125
|
Chris@0
|
126 if ($begin === false) {
|
Chris@0
|
127 return static::systemGlob($pattern, $flags);
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 $next = static::nextBraceSub($pattern, $begin + 1, $flags);
|
Chris@0
|
131
|
Chris@0
|
132 if ($next === null) {
|
Chris@0
|
133 return static::systemGlob($pattern, $flags);
|
Chris@0
|
134 }
|
Chris@0
|
135
|
Chris@0
|
136 $rest = $next;
|
Chris@0
|
137
|
Chris@0
|
138 while ($pattern[$rest] !== '}') {
|
Chris@0
|
139 $rest = static::nextBraceSub($pattern, $rest + 1, $flags);
|
Chris@0
|
140
|
Chris@0
|
141 if ($rest === null) {
|
Chris@0
|
142 return static::systemGlob($pattern, $flags);
|
Chris@0
|
143 }
|
Chris@0
|
144 }
|
Chris@0
|
145
|
Chris@0
|
146 $p = $begin + 1;
|
Chris@0
|
147
|
Chris@0
|
148 while (true) {
|
Chris@0
|
149 $subPattern = substr($pattern, 0, $begin)
|
Chris@0
|
150 . substr($pattern, $p, $next - $p)
|
Chris@0
|
151 . substr($pattern, $rest + 1);
|
Chris@0
|
152
|
Chris@0
|
153 $result = static::fallbackGlob($subPattern, $flags | self::GLOB_BRACE);
|
Chris@0
|
154
|
Chris@0
|
155 if ($result) {
|
Chris@0
|
156 $paths = array_merge($paths, $result);
|
Chris@0
|
157 }
|
Chris@0
|
158
|
Chris@0
|
159 if ($pattern[$next] === '}') {
|
Chris@0
|
160 break;
|
Chris@0
|
161 }
|
Chris@0
|
162
|
Chris@0
|
163 $p = $next + 1;
|
Chris@0
|
164 $next = static::nextBraceSub($pattern, $p, $flags);
|
Chris@0
|
165 }
|
Chris@0
|
166
|
Chris@0
|
167 return array_unique($paths);
|
Chris@0
|
168 }
|
Chris@0
|
169
|
Chris@0
|
170 /**
|
Chris@0
|
171 * Find the end of the sub-pattern in a brace expression.
|
Chris@0
|
172 *
|
Chris@0
|
173 * @param string $pattern
|
Chris@0
|
174 * @param int $begin
|
Chris@0
|
175 * @param int $flags
|
Chris@0
|
176 * @return int|null
|
Chris@0
|
177 */
|
Chris@0
|
178 protected static function nextBraceSub($pattern, $begin, $flags)
|
Chris@0
|
179 {
|
Chris@0
|
180 $length = strlen($pattern);
|
Chris@0
|
181 $depth = 0;
|
Chris@0
|
182 $current = $begin;
|
Chris@0
|
183
|
Chris@0
|
184 while ($current < $length) {
|
Chris@12
|
185 if (! $flags & self::GLOB_NOESCAPE && $pattern[$current] === '\\') {
|
Chris@0
|
186 if (++$current === $length) {
|
Chris@0
|
187 break;
|
Chris@0
|
188 }
|
Chris@0
|
189
|
Chris@0
|
190 $current++;
|
Chris@0
|
191 } else {
|
Chris@0
|
192 if (($pattern[$current] === '}' && $depth-- === 0) || ($pattern[$current] === ',' && $depth === 0)) {
|
Chris@0
|
193 break;
|
Chris@0
|
194 } elseif ($pattern[$current++] === '{') {
|
Chris@0
|
195 $depth++;
|
Chris@0
|
196 }
|
Chris@0
|
197 }
|
Chris@0
|
198 }
|
Chris@0
|
199
|
Chris@0
|
200 return ($current < $length ? $current : null);
|
Chris@0
|
201 }
|
Chris@0
|
202 }
|