This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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\Adapter; |
||
4 | |||
5 | use DirectoryIterator; |
||
6 | use FilesystemIterator; |
||
7 | use finfo as Finfo; |
||
8 | use League\Flysystem\AdapterInterface; |
||
9 | use League\Flysystem\Config; |
||
10 | use League\Flysystem\Exception; |
||
11 | use League\Flysystem\NotSupportedException; |
||
12 | use League\Flysystem\UnreadableFileException; |
||
13 | use League\Flysystem\Util; |
||
14 | use LogicException; |
||
15 | use RecursiveDirectoryIterator; |
||
16 | use RecursiveIteratorIterator; |
||
17 | use SplFileInfo; |
||
18 | |||
19 | class Local extends AbstractAdapter |
||
20 | { |
||
21 | /** |
||
22 | * @var int |
||
23 | */ |
||
24 | const SKIP_LINKS = 0001; |
||
25 | |||
26 | /** |
||
27 | * @var int |
||
28 | */ |
||
29 | const DISALLOW_LINKS = 0002; |
||
30 | |||
31 | /** |
||
32 | * @var array |
||
33 | */ |
||
34 | protected static $permissions = array( |
||
35 | 'file' => array( |
||
36 | 'public' => 0644, |
||
37 | 'private' => 0600, |
||
38 | ), |
||
39 | 'dir' => array( |
||
40 | 'public' => 0755, |
||
41 | 'private' => 0700, |
||
42 | ), |
||
43 | ); |
||
44 | |||
45 | /** |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $pathSeparator = DIRECTORY_SEPARATOR; |
||
49 | |||
50 | /** |
||
51 | * @var array |
||
52 | */ |
||
53 | protected $permissionMap; |
||
54 | |||
55 | /** |
||
56 | * @var int |
||
57 | */ |
||
58 | protected $writeFlags; |
||
59 | /** |
||
60 | * @var int |
||
61 | */ |
||
62 | private $linkHandling; |
||
63 | |||
64 | /** |
||
65 | * Constructor. |
||
66 | * |
||
67 | * @param string $root |
||
68 | * @param int $writeFlags |
||
69 | * @param int $linkHandling |
||
70 | * @param array $permissions |
||
71 | */ |
||
72 | 159 | public function __construct($root, $writeFlags = LOCK_EX, $linkHandling = self::DISALLOW_LINKS, array $permissions = array()) |
|
73 | { |
||
74 | 159 | $root = is_link($root) ? realpath($root) : $root; |
|
75 | 159 | $this->permissionMap = array_replace_recursive(static::$permissions, $permissions); |
|
76 | 159 | $realRoot = $this->ensureDirectory($root); |
|
77 | |||
78 | 159 | if ( ! is_dir($realRoot) || ! is_readable($realRoot)) { |
|
79 | 3 | throw new LogicException('The root path ' . $root . ' is not readable.'); |
|
80 | } |
||
81 | |||
82 | 159 | $this->setPathPrefix($realRoot); |
|
83 | 159 | $this->writeFlags = $writeFlags; |
|
84 | 159 | $this->linkHandling = $linkHandling; |
|
85 | 159 | } |
|
86 | |||
87 | /** |
||
88 | * Ensure the root directory exists. |
||
89 | * |
||
90 | * @param string $root root directory path |
||
91 | * |
||
92 | * @return string real path to root |
||
93 | * |
||
94 | * @throws Exception in case the root directory can not be created |
||
95 | */ |
||
96 | 159 | protected function ensureDirectory($root) |
|
97 | { |
||
98 | 159 | if ( ! is_dir($root)) { |
|
99 | 21 | $umask = umask(0); |
|
100 | 21 | @mkdir($root, $this->permissionMap['dir']['public'], true); |
|
0 ignored issues
–
show
|
|||
101 | 21 | umask($umask); |
|
102 | |||
103 | 21 | if ( ! is_dir($root)) { |
|
104 | 3 | throw new Exception(sprintf('Impossible to create the root directory "%s".', $root)); |
|
105 | } |
||
106 | 18 | } |
|
107 | |||
108 | 159 | return realpath($root); |
|
109 | } |
||
110 | |||
111 | /** |
||
112 | * @inheritdoc |
||
113 | */ |
||
114 | 75 | public function has($path) |
|
115 | { |
||
116 | 75 | $location = $this->applyPathPrefix($path); |
|
117 | |||
118 | 75 | return file_exists($location); |
|
119 | } |
||
120 | |||
121 | /** |
||
122 | * @inheritdoc |
||
123 | */ |
||
124 | 99 | public function write($path, $contents, Config $config) |
|
125 | { |
||
126 | 99 | $location = $this->applyPathPrefix($path); |
|
127 | 99 | $this->ensureDirectory(dirname($location)); |
|
128 | |||
129 | 99 | if (($size = file_put_contents($location, $contents, $this->writeFlags)) === false) { |
|
130 | 3 | return false; |
|
131 | } |
||
132 | |||
133 | 96 | $type = 'file'; |
|
134 | 96 | $result = compact('contents', 'type', 'size', 'path'); |
|
135 | |||
136 | 96 | if ($visibility = $config->get('visibility')) { |
|
137 | 3 | $result['visibility'] = $visibility; |
|
138 | 3 | $this->setVisibility($path, $visibility); |
|
139 | 3 | } |
|
140 | |||
141 | 96 | return $result; |
|
142 | } |
||
143 | |||
144 | /** |
||
145 | * @inheritdoc |
||
146 | */ |
||
147 | 21 | public function writeStream($path, $resource, Config $config) |
|
148 | { |
||
149 | 18 | $location = $this->applyPathPrefix($path); |
|
150 | 18 | $this->ensureDirectory(dirname($location)); |
|
151 | 18 | $stream = fopen($location, 'w+b'); |
|
152 | |||
153 | 18 | if ( ! $stream) { |
|
154 | 3 | return false; |
|
155 | } |
||
156 | |||
157 | 21 | stream_copy_to_stream($resource, $stream); |
|
158 | |||
159 | 18 | if ( ! fclose($stream)) { |
|
160 | 3 | return false; |
|
161 | } |
||
162 | |||
163 | 15 | if ($visibility = $config->get('visibility')) { |
|
164 | 3 | $this->setVisibility($path, $visibility); |
|
165 | 3 | } |
|
166 | |||
167 | 15 | return compact('path', 'visibility'); |
|
168 | } |
||
169 | |||
170 | /** |
||
171 | * @inheritdoc |
||
172 | */ |
||
173 | 6 | public function readStream($path) |
|
174 | { |
||
175 | 6 | $location = $this->applyPathPrefix($path); |
|
176 | 6 | $stream = fopen($location, 'rb'); |
|
177 | |||
178 | 6 | return compact('stream', 'path'); |
|
179 | } |
||
180 | |||
181 | /** |
||
182 | * @inheritdoc |
||
183 | */ |
||
184 | 9 | public function updateStream($path, $resource, Config $config) |
|
185 | { |
||
186 | 9 | return $this->writeStream($path, $resource, $config); |
|
187 | } |
||
188 | |||
189 | /** |
||
190 | * @inheritdoc |
||
191 | */ |
||
192 | 9 | public function update($path, $contents, Config $config) |
|
193 | { |
||
194 | 9 | $location = $this->applyPathPrefix($path); |
|
195 | 9 | $mimetype = Util::guessMimeType($path, $contents); |
|
196 | 9 | $size = file_put_contents($location, $contents, $this->writeFlags); |
|
197 | |||
198 | 9 | if ($size === false) { |
|
199 | 3 | return false; |
|
200 | } |
||
201 | |||
202 | 6 | return compact('path', 'size', 'contents', 'mimetype'); |
|
203 | } |
||
204 | |||
205 | /** |
||
206 | * @inheritdoc |
||
207 | */ |
||
208 | 27 | public function read($path) |
|
209 | { |
||
210 | 27 | $location = $this->applyPathPrefix($path); |
|
211 | 27 | $contents = file_get_contents($location); |
|
212 | |||
213 | 27 | if ($contents === false) { |
|
214 | 3 | return false; |
|
215 | } |
||
216 | |||
217 | 24 | return compact('contents', 'path'); |
|
218 | } |
||
219 | |||
220 | /** |
||
221 | * @inheritdoc |
||
222 | */ |
||
223 | 6 | public function rename($path, $newpath) |
|
224 | { |
||
225 | 6 | $location = $this->applyPathPrefix($path); |
|
226 | 6 | $destination = $this->applyPathPrefix($newpath); |
|
227 | 6 | $parentDirectory = $this->applyPathPrefix(Util::dirname($newpath)); |
|
228 | 6 | $this->ensureDirectory($parentDirectory); |
|
229 | |||
230 | 6 | return rename($location, $destination); |
|
231 | } |
||
232 | |||
233 | /** |
||
234 | * @inheritdoc |
||
235 | */ |
||
236 | 6 | public function copy($path, $newpath) |
|
237 | { |
||
238 | 6 | $location = $this->applyPathPrefix($path); |
|
239 | 6 | $destination = $this->applyPathPrefix($newpath); |
|
240 | 6 | $this->ensureDirectory(dirname($destination)); |
|
241 | |||
242 | 6 | return copy($location, $destination); |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * @inheritdoc |
||
247 | */ |
||
248 | 66 | public function delete($path) |
|
249 | { |
||
250 | 66 | $location = $this->applyPathPrefix($path); |
|
251 | |||
252 | 66 | return unlink($location); |
|
253 | } |
||
254 | |||
255 | /** |
||
256 | * @inheritdoc |
||
257 | */ |
||
258 | 15 | public function listContents($directory = '', $recursive = false) |
|
259 | { |
||
260 | 15 | $result = array(); |
|
261 | 15 | $location = $this->applyPathPrefix($directory) . $this->pathSeparator; |
|
262 | |||
263 | 15 | if ( ! is_dir($location)) { |
|
264 | 3 | return array(); |
|
265 | } |
||
266 | |||
267 | 12 | $iterator = $recursive ? $this->getRecursiveDirectoryIterator($location) : $this->getDirectoryIterator($location); |
|
268 | |||
269 | 12 | foreach ($iterator as $file) { |
|
270 | 12 | $path = $this->getFilePath($file); |
|
271 | |||
272 | 12 | if (preg_match('#(^|/|\\\\)\.{1,2}$#', $path)) { |
|
273 | 9 | continue; |
|
274 | } |
||
275 | |||
276 | 12 | $result[] = $this->normalizeFileInfo($file); |
|
277 | 12 | } |
|
278 | |||
279 | 9 | return array_filter($result); |
|
280 | } |
||
281 | |||
282 | /** |
||
283 | * @inheritdoc |
||
284 | */ |
||
285 | 45 | public function getMetadata($path) |
|
286 | { |
||
287 | 45 | $location = $this->applyPathPrefix($path); |
|
288 | 45 | $info = new SplFileInfo($location); |
|
289 | |||
290 | 45 | return $this->normalizeFileInfo($info); |
|
291 | } |
||
292 | |||
293 | /** |
||
294 | * @inheritdoc |
||
295 | */ |
||
296 | 6 | public function getSize($path) |
|
297 | { |
||
298 | 6 | return $this->getMetadata($path); |
|
299 | } |
||
300 | |||
301 | /** |
||
302 | * @inheritdoc |
||
303 | */ |
||
304 | 6 | public function getMimetype($path) |
|
305 | { |
||
306 | 6 | $location = $this->applyPathPrefix($path); |
|
307 | 6 | $finfo = new Finfo(FILEINFO_MIME_TYPE); |
|
308 | |||
309 | 6 | return array('mimetype' => $finfo->file($location)); |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * @inheritdoc |
||
314 | */ |
||
315 | 6 | public function getTimestamp($path) |
|
316 | { |
||
317 | 6 | return $this->getMetadata($path); |
|
318 | } |
||
319 | |||
320 | /** |
||
321 | * @inheritdoc |
||
322 | */ |
||
323 | 18 | public function getVisibility($path) |
|
324 | { |
||
325 | 18 | $location = $this->applyPathPrefix($path); |
|
326 | 18 | clearstatcache(false, $location); |
|
327 | 18 | $permissions = octdec(substr(sprintf('%o', fileperms($location)), -4)); |
|
328 | 18 | $visibility = $permissions & 0044 ? AdapterInterface::VISIBILITY_PUBLIC : AdapterInterface::VISIBILITY_PRIVATE; |
|
329 | |||
330 | 18 | return compact('visibility'); |
|
331 | } |
||
332 | |||
333 | /** |
||
334 | * @inheritdoc |
||
335 | */ |
||
336 | 21 | public function setVisibility($path, $visibility) |
|
337 | { |
||
338 | 21 | $location = $this->applyPathPrefix($path); |
|
339 | 21 | $type = is_dir($location) ? 'dir' : 'file'; |
|
340 | 21 | $success = chmod($location, $this->permissionMap[$type][$visibility]); |
|
341 | |||
342 | 21 | if ($success === false) { |
|
343 | 3 | return false; |
|
344 | } |
||
345 | |||
346 | 18 | return compact('visibility'); |
|
347 | } |
||
348 | |||
349 | /** |
||
350 | * @inheritdoc |
||
351 | */ |
||
352 | 75 | public function createDir($dirname, Config $config) |
|
353 | { |
||
354 | 75 | $location = $this->applyPathPrefix($dirname); |
|
355 | 75 | $umask = umask(0); |
|
356 | 75 | $visibility = $config->get('visibility', 'public'); |
|
357 | |||
358 | 75 | if ( ! is_dir($location) && ! mkdir($location, $this->permissionMap['dir'][$visibility], true)) { |
|
359 | 3 | $return = false; |
|
360 | 3 | } else { |
|
361 | 72 | $return = array('path' => $dirname, 'type' => 'dir'); |
|
362 | } |
||
363 | |||
364 | 75 | umask($umask); |
|
365 | |||
366 | 75 | return $return; |
|
367 | } |
||
368 | |||
369 | /** |
||
370 | * @inheritdoc |
||
371 | */ |
||
372 | 75 | public function deleteDir($dirname) |
|
373 | { |
||
374 | 75 | $location = $this->applyPathPrefix($dirname); |
|
375 | |||
376 | 75 | if ( ! is_dir($location)) { |
|
377 | 57 | return false; |
|
378 | } |
||
379 | |||
380 | 72 | $contents = $this->getRecursiveDirectoryIterator($location, RecursiveIteratorIterator::CHILD_FIRST); |
|
381 | |||
382 | /** @var SplFileInfo $file */ |
||
383 | 72 | foreach ($contents as $file) { |
|
384 | 27 | $this->guardAgainstUnreadableFileInfo($file); |
|
385 | 27 | $this->deleteFileInfoObject($file); |
|
386 | 72 | } |
|
387 | |||
388 | 72 | return rmdir($location); |
|
389 | } |
||
390 | |||
391 | /** |
||
392 | * @param SplFileInfo $file |
||
393 | */ |
||
394 | 27 | protected function deleteFileInfoObject(SplFileInfo $file) |
|
395 | { |
||
396 | 27 | switch ($file->getType()) { |
|
397 | 27 | case 'dir': |
|
398 | 3 | rmdir($file->getRealPath()); |
|
399 | 3 | break; |
|
400 | 27 | case 'link': |
|
401 | 3 | unlink($file->getPathname()); |
|
402 | 3 | break; |
|
403 | 24 | default: |
|
404 | 24 | unlink($file->getRealPath()); |
|
405 | 27 | } |
|
406 | 27 | } |
|
407 | |||
408 | /** |
||
409 | * Normalize the file info. |
||
410 | * |
||
411 | * @param SplFileInfo $file |
||
412 | * |
||
413 | * @return array |
||
414 | */ |
||
415 | 57 | protected function normalizeFileInfo(SplFileInfo $file) |
|
416 | { |
||
417 | 57 | if ( ! $file->isLink()) { |
|
418 | 57 | return $this->mapFileInfo($file); |
|
419 | } |
||
420 | |||
421 | 6 | if ($this->linkHandling & self::DISALLOW_LINKS) { |
|
422 | 3 | throw NotSupportedException::forLink($file); |
|
423 | } |
||
424 | 3 | } |
|
425 | |||
426 | /** |
||
427 | * Get the normalized path from a SplFileInfo object. |
||
428 | * |
||
429 | * @param SplFileInfo $file |
||
430 | * |
||
431 | * @return string |
||
432 | */ |
||
433 | 57 | protected function getFilePath(SplFileInfo $file) |
|
434 | { |
||
435 | 57 | $location = $file->getPathname(); |
|
436 | 57 | $path = $this->removePathPrefix($location); |
|
437 | |||
438 | 57 | return trim(str_replace('\\', '/', $path), '/'); |
|
439 | } |
||
440 | |||
441 | /** |
||
442 | * @param string $path |
||
443 | * @param int $mode |
||
444 | * |
||
445 | * @return RecursiveIteratorIterator |
||
446 | */ |
||
447 | 75 | protected function getRecursiveDirectoryIterator($path, $mode = RecursiveIteratorIterator::SELF_FIRST) |
|
448 | { |
||
449 | 75 | return new RecursiveIteratorIterator( |
|
450 | 75 | new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), |
|
451 | $mode |
||
452 | 75 | ); |
|
453 | } |
||
454 | |||
455 | /** |
||
456 | * @param string $path |
||
457 | * |
||
458 | * @return DirectoryIterator |
||
459 | */ |
||
460 | 9 | protected function getDirectoryIterator($path) |
|
461 | { |
||
462 | 9 | $iterator = new DirectoryIterator($path); |
|
463 | |||
464 | 9 | return $iterator; |
|
465 | } |
||
466 | |||
467 | /** |
||
468 | * @param SplFileInfo $file |
||
469 | * |
||
470 | * @return array |
||
471 | */ |
||
472 | 57 | protected function mapFileInfo(SplFileInfo $file) |
|
473 | { |
||
474 | $normalized = array( |
||
475 | 57 | 'type' => $file->getType(), |
|
476 | 57 | 'path' => $this->getFilePath($file), |
|
477 | 57 | ); |
|
478 | |||
479 | 57 | $normalized['timestamp'] = $file->getMTime(); |
|
480 | |||
481 | 57 | if ($normalized['type'] === 'file') { |
|
482 | 57 | $normalized['size'] = $file->getSize(); |
|
483 | 57 | } |
|
484 | |||
485 | 57 | return $normalized; |
|
486 | } |
||
487 | |||
488 | /** |
||
489 | * @inheritdoc |
||
490 | */ |
||
491 | 144 | public function applyPathPrefix($path) |
|
492 | { |
||
493 | 144 | $prefixedPath = parent::applyPathPrefix($path); |
|
494 | |||
495 | 144 | return str_replace('/', DIRECTORY_SEPARATOR, $prefixedPath); |
|
496 | } |
||
497 | |||
498 | /** |
||
499 | * @param SplFileInfo $file |
||
500 | * |
||
501 | * @throws UnreadableFileException |
||
502 | */ |
||
503 | 30 | protected function guardAgainstUnreadableFileInfo(SplFileInfo $file) |
|
504 | { |
||
505 | 30 | if ( ! $file->isReadable()) { |
|
506 | 3 | throw UnreadableFileException::forFileInfo($file); |
|
507 | } |
||
508 | 27 | } |
|
509 | } |
||
510 |
If you suppress an error, we recommend checking for the error condition explicitly: