Completed
Push — master ( f400aa...d3ce2f )
by Frank
02:06
created

src/Util.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace League\Flysystem;
4
5
use League\Flysystem\Util\MimeType;
6
use LogicException;
7
8
class Util
9
{
10
    /**
11
     * Get normalized pathinfo.
12
     *
13
     * @param string $path
14
     *
15
     * @return array pathinfo
16
     */
17 129
    public static function pathinfo($path)
18
    {
19 129
        $pathinfo = compact('path');
20
21 129
        if ('' !== $dirname = dirname($path)) {
22 126
            $pathinfo['dirname'] = static::normalizeDirname($dirname);
23 126
        }
24
25 129
        $pathinfo['basename'] = static::basename($path);
0 ignored issues
show
Since basename() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of basename() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
26
27 129
        $pathinfo += pathinfo($pathinfo['basename']);
28
29 129
        return $pathinfo;
30
    }
31
32
    /**
33
     * Normalize a dirname return value.
34
     *
35
     * @param string $dirname
36
     *
37
     * @return string normalized dirname
38
     */
39 150
    public static function normalizeDirname($dirname)
40
    {
41 150
        return $dirname === '.' ? '' : $dirname;
42
    }
43
44
    /**
45
     * Get a normalized dirname from a path.
46
     *
47
     * @param string $path
48
     *
49
     * @return string dirname
50
     */
51 33
    public static function dirname($path)
52
    {
53 33
        return static::normalizeDirname(dirname($path));
54
    }
55
56
    /**
57
     * Map result arrays.
58
     *
59
     * @param array $object
60
     * @param array $map
61
     *
62
     * @return array mapped result
63
     */
64 6
    public static function map(array $object, array $map)
65
    {
66 6
        $result = [];
67
68 6
        foreach ($map as $from => $to) {
69 6
            if ( ! isset($object[$from])) {
70 3
                continue;
71
            }
72
73 6
            $result[$to] = $object[$from];
74 6
        }
75
76 6
        return $result;
77
    }
78
79
    /**
80
     * Normalize path.
81
     *
82
     * @param string $path
83
     *
84
     * @throws LogicException
85
     *
86
     * @return string
87
     */
88 285
    public static function normalizePath($path)
89
    {
90 285
        return static::normalizeRelativePath($path);
91
    }
92
93
    /**
94
     * Normalize relative directories in a path.
95
     *
96
     * @param string $path
97
     *
98
     * @throws LogicException
99
     *
100
     * @return string
101
     */
102 285
    public static function normalizeRelativePath($path)
103
    {
104 285
        $path = str_replace('\\', '/', $path);
105 285
        $path = static::removeFunkyWhiteSpace($path);
106
107 285
        $parts = [];
108
109 285
        foreach (explode('/', $path) as $part) {
110
            switch ($part) {
111 285
                case '':
112 285
                case '.':
113 66
                break;
114
115 276
            case '..':
116 30
                if (empty($parts)) {
117 15
                    throw new LogicException(
118 15
                        'Path is outside of the defined root, path: [' . $path . ']'
119 15
                    );
120
                }
121 27
                array_pop($parts);
122 27
                break;
123
124 273
            default:
125 273
                $parts[] = $part;
126 273
                break;
127 273
            }
128 282
        }
129
130 270
        return implode('/', $parts);
131
    }
132
133
    /**
134
     * Removes unprintable characters and invalid unicode characters.
135
     *
136
     * @param string $path
137
     *
138
     * @return string $path
139
     */
140 285
    protected static function removeFunkyWhiteSpace($path) {
141
        // We do this check in a loop, since removing invalid unicode characters
142
        // can lead to new characters being created.
143 285
        while (preg_match('#\p{C}+|^\./#u', $path)) {
144 6
            $path = preg_replace('#\p{C}+|^\./#u', '', $path);
145 6
        }
146
147 285
        return $path;
148
    }
149
150
    /**
151
     * Normalize prefix.
152
     *
153
     * @param string $prefix
154
     * @param string $separator
155
     *
156
     * @return string normalized path
157
     */
158 3
    public static function normalizePrefix($prefix, $separator)
159
    {
160 3
        return rtrim($prefix, $separator) . $separator;
161
    }
162
163
    /**
164
     * Get content size.
165
     *
166
     * @param string $contents
167
     *
168
     * @return int content size
169
     */
170 3
    public static function contentSize($contents)
171
    {
172 3
        return defined('MB_OVERLOAD_STRING') ? mb_strlen($contents, '8bit') : strlen($contents);
173
    }
174
175
    /**
176
     * Guess MIME Type based on the path of the file and it's content.
177
     *
178
     * @param string $path
179
     * @param string|resource $content
180
     *
181
     * @return string|null MIME Type or NULL if no extension detected
182
     */
183 27
    public static function guessMimeType($path, $content)
184
    {
185 27
        $mimeType = MimeType::detectByContent($content);
186
187 27
        if ( ! (empty($mimeType) || in_array($mimeType, ['application/x-empty', 'text/plain', 'text/x-asm']))) {
188 3
            return $mimeType;
189
        }
190
191 24
        return MimeType::detectByFilename($path);
192
    }
193
194
    /**
195
     * Emulate directories.
196
     *
197
     * @param array $listing
198
     *
199
     * @return array listing with emulated directories
200
     */
201 3
    public static function emulateDirectories(array $listing)
202
    {
203 3
        $directories = [];
204 3
        $listedDirectories = [];
205
206 3
        foreach ($listing as $object) {
207 3
            list($directories, $listedDirectories) = static::emulateObjectDirectories(
208 3
                $object,
209 3
                $directories,
210
                $listedDirectories
211 3
            );
212 3
        }
213
214 3
        $directories = array_diff(array_unique($directories), array_unique($listedDirectories));
215
216 3
        foreach ($directories as $directory) {
217 3
            $listing[] = static::pathinfo($directory) + ['type' => 'dir'];
218 3
        }
219
220 3
        return $listing;
221
    }
222
223
    /**
224
     * Ensure a Config instance.
225
     *
226
     * @param null|array|Config $config
227
     *
228
     * @return Config config instance
229
     *
230
     * @throw  LogicException
231
     */
232 147
    public static function ensureConfig($config)
233
    {
234 147
        if ($config === null) {
235 3
            return new Config();
236
        }
237
238 147
        if ($config instanceof Config) {
239 144
            return $config;
240
        }
241
242 6
        if (is_array($config)) {
243 3
            return new Config($config);
244
        }
245
246 3
        throw new LogicException('A config should either be an array or a Flysystem\Config object.');
247
    }
248
249
    /**
250
     * Rewind a stream.
251
     *
252
     * @param resource $resource
253
     */
254 39
    public static function rewindStream($resource)
255
    {
256 39
        if (ftell($resource) !== 0 && static::isSeekableStream($resource)) {
257 21
            rewind($resource);
258 21
        }
259 39
    }
260
261 21
    public static function isSeekableStream($resource)
262
    {
263 21
        $metadata = stream_get_meta_data($resource);
264
265 21
        return $metadata['seekable'];
266
    }
267
268
    /**
269
     * Get the size of a stream.
270
     *
271
     * @param resource $resource
272
     *
273
     * @return int stream size
274
     */
275 3
    public static function getStreamSize($resource)
276
    {
277 3
        $stat = fstat($resource);
278
279 3
        return $stat['size'];
280
    }
281
282
    /**
283
     * Emulate the directories of a single object.
284
     *
285
     * @param array $object
286
     * @param array $directories
287
     * @param array $listedDirectories
288
     *
289
     * @return array
290
     */
291 3
    protected static function emulateObjectDirectories(array $object, array $directories, array $listedDirectories)
292
    {
293 3
        if ($object['type'] === 'dir') {
294 3
            $listedDirectories[] = $object['path'];
295 3
        }
296
297 3
        if (empty($object['dirname'])) {
298 3
            return [$directories, $listedDirectories];
299
        }
300
301 3
        $parent = $object['dirname'];
302
303 3
        while ( ! empty($parent) && ! in_array($parent, $directories)) {
304 3
            $directories[] = $parent;
305 3
            $parent = static::dirname($parent);
306 3
        }
307
308 3
        if (isset($object['type']) && $object['type'] === 'dir') {
309 3
            $listedDirectories[] = $object['path'];
310
311 3
            return [$directories, $listedDirectories];
312
        }
313
314 3
        return [$directories, $listedDirectories];
315
    }
316
317
    /**
318
     * Returns the trailing name component of the path.
319
     *
320
     * @param string $path
321
     *
322
     * @return string
323
     */
324 129
    private static function basename($path)
325
    {
326 129
        $separators = DIRECTORY_SEPARATOR === '/' ? '/' : '\/';
327
328 129
        $path = rtrim($path, $separators);
329
330 129
        $basename = preg_replace('#.*?([^' . preg_quote($separators, '#') . ']+$)#', '$1', $path);
331
332 129
        if (DIRECTORY_SEPARATOR === '/') {
333 129
            return $basename;
334
        }
335
        // @codeCoverageIgnoreStart
336
        // Extra Windows path munging. This is tested via AppVeyor, but code
337
        // coverage is not reported.
338
339
        // Handle relative paths with drive letters. c:file.txt.
340
        while (preg_match('#^[a-zA-Z]{1}:[^\\\/]#', $basename)) {
341
            $basename = substr($basename, 2);
342
        }
343
344
        // Remove colon for standalone drive letter names.
345
        if (preg_match('#^[a-zA-Z]{1}:$#', $basename)) {
346
            $basename = rtrim($basename, ':');
347
        }
348
349
        return $basename;
350
        // @codeCoverageIgnoreEnd
351
    }
352
}
353