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