PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.12.6
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.12.6
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / vendor / league / flysystem-local / LocalFilesystemAdapter.php

LocalFilesystemAdapter.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.12.6, at vendor/league/flysystem-local/LocalFilesystemAdapter.php

488 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace League\Flysystem\Local;
6
7 use const DIRECTORY_SEPARATOR;
8 use const LOCK_EX;
9 use DirectoryIterator;
10 use FilesystemIterator;
11 use Generator;
12 use League\Flysystem\ChecksumProvider;
13 use League\Flysystem\Config;
14 use League\Flysystem\DirectoryAttributes;
15 use League\Flysystem\FileAttributes;
16 use League\Flysystem\FilesystemAdapter;
17 use League\Flysystem\PathPrefixer;
18 use League\Flysystem\SymbolicLinkEncountered;
19 use League\Flysystem\UnableToCopyFile;
20 use League\Flysystem\UnableToCreateDirectory;
21 use League\Flysystem\UnableToDeleteDirectory;
22 use League\Flysystem\UnableToDeleteFile;
23 use League\Flysystem\UnableToMoveFile;
24 use League\Flysystem\UnableToProvideChecksum;
25 use League\Flysystem\UnableToReadFile;
26 use League\Flysystem\UnableToRetrieveMetadata;
27 use League\Flysystem\UnableToSetVisibility;
28 use League\Flysystem\UnableToWriteFile;
29 use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
30 use League\Flysystem\UnixVisibility\VisibilityConverter;
31 use League\MimeTypeDetection\FinfoMimeTypeDetector;
32 use League\MimeTypeDetection\MimeTypeDetector;
33 use RecursiveDirectoryIterator;
34 use RecursiveIteratorIterator;
35 use SplFileInfo;
36 use Throwable;
37 use function chmod;
38 use function clearstatcache;
39 use function dirname;
40 use function error_clear_last;
41 use function error_get_last;
42 use function file_exists;
43 use function file_put_contents;
44 use function hash_file;
45 use function is_dir;
46 use function is_file;
47 use function mkdir;
48 use function rename;
49
50 class LocalFilesystemAdapter implements FilesystemAdapter, ChecksumProvider
51 {
52 /**
53 * @var int
54 */
55 public const SKIP_LINKS = 0001;
56
57 /**
58 * @var int
59 */
60 public const DISALLOW_LINKS = 0002;
61
62 private PathPrefixer $prefixer;
63 private VisibilityConverter $visibility;
64 private MimeTypeDetector $mimeTypeDetector;
65 private string $rootLocation;
66
67 /**
68 * @var bool
69 */
70 private $rootLocationIsSetup = false;
71
72 public function __construct(
73 string $location,
74 ?VisibilityConverter $visibility = null,
75 private int $writeFlags = LOCK_EX,
76 private int $linkHandling = self::DISALLOW_LINKS,
77 ?MimeTypeDetector $mimeTypeDetector = null,
78 bool $lazyRootCreation = false,
79 bool $useInconclusiveMimeTypeFallback = false,
80 ) {
81 $this->prefixer = new PathPrefixer($location, DIRECTORY_SEPARATOR);
82 $visibility ??= new PortableVisibilityConverter();
83 $this->visibility = $visibility;
84 $this->rootLocation = $location;
85 $this->mimeTypeDetector = $mimeTypeDetector ?? new FallbackMimeTypeDetector(
86 detector: new FinfoMimeTypeDetector(),
87 useInconclusiveMimeTypeFallback: $useInconclusiveMimeTypeFallback,
88 );
89
90 if ( ! $lazyRootCreation) {
91 $this->ensureRootDirectoryExists();
92 }
93 }
94
95 private function ensureRootDirectoryExists(): void
96 {
97 if ($this->rootLocationIsSetup) {
98 return;
99 }
100
101 $this->ensureDirectoryExists($this->rootLocation, $this->visibility->defaultForDirectories());
102 $this->rootLocationIsSetup = true;
103 }
104
105 public function write(string $path, string $contents, Config $config): void
106 {
107 $this->writeToFile($path, $contents, $config);
108 }
109
110 public function writeStream(string $path, $contents, Config $config): void
111 {
112 $this->writeToFile($path, $contents, $config);
113 }
114
115 /**
116 * @param resource|string $contents
117 */
118 private function writeToFile(string $path, $contents, Config $config): void
119 {
120 $prefixedLocation = $this->prefixer->prefixPath($path);
121 $this->ensureRootDirectoryExists();
122 $this->ensureDirectoryExists(
123 dirname($prefixedLocation),
124 $this->resolveDirectoryVisibility($config->get(Config::OPTION_DIRECTORY_VISIBILITY))
125 );
126 error_clear_last();
127
128 if (@file_put_contents($prefixedLocation, $contents, $this->writeFlags) === false) {
129 throw UnableToWriteFile::atLocation($path, error_get_last()['message'] ?? '');
130 }
131
132 if ($visibility = $config->get(Config::OPTION_VISIBILITY)) {
133 $this->setVisibility($path, (string) $visibility);
134 }
135 }
136
137 public function delete(string $path): void
138 {
139 $location = $this->prefixer->prefixPath($path);
140
141 if ( ! file_exists($location)) {
142 return;
143 }
144
145 error_clear_last();
146
147 if ( ! @unlink($location)) {
148 throw UnableToDeleteFile::atLocation($location, error_get_last()['message'] ?? '');
149 }
150 }
151
152 public function deleteDirectory(string $prefix): void
153 {
154 $location = $this->prefixer->prefixPath($prefix);
155
156 if ( ! is_dir($location)) {
157 return;
158 }
159
160 $contents = $this->listDirectoryRecursively($location, RecursiveIteratorIterator::CHILD_FIRST);
161
162 /** @var SplFileInfo $file */
163 foreach ($contents as $file) {
164 if ( ! $this->deleteFileInfoObject($file)) {
165 throw UnableToDeleteDirectory::atLocation($prefix, "Unable to delete file at " . $file->getPathname());
166 }
167 }
168
169 unset($contents);
170
171 if ( ! @rmdir($location)) {
172 throw UnableToDeleteDirectory::atLocation($prefix, error_get_last()['message'] ?? '');
173 }
174 }
175
176 private function listDirectoryRecursively(
177 string $path,
178 int $mode = RecursiveIteratorIterator::SELF_FIRST
179 ): Generator {
180 if ( ! is_dir($path)) {
181 return;
182 }
183
184 yield from new RecursiveIteratorIterator(
185 new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
186 $mode
187 );
188 }
189
190 protected function deleteFileInfoObject(SplFileInfo $file): bool
191 {
192 switch ($file->getType()) {
193 case 'dir':
194 return @rmdir((string) $file->getRealPath());
195 case 'link':
196 return @unlink((string) $file->getPathname());
197 default:
198 return @unlink((string) $file->getRealPath());
199 }
200 }
201
202 public function listContents(string $path, bool $deep): iterable
203 {
204 $location = $this->prefixer->prefixPath($path);
205
206 if ( ! is_dir($location)) {
207 return;
208 }
209
210 /** @var SplFileInfo[] $iterator */
211 $iterator = $deep ? $this->listDirectoryRecursively($location) : $this->listDirectory($location);
212
213 foreach ($iterator as $fileInfo) {
214 $pathName = $fileInfo->getPathname();
215
216 try {
217 if ($fileInfo->isLink()) {
218 if ($this->linkHandling & self::SKIP_LINKS) {
219 continue;
220 }
221 throw SymbolicLinkEncountered::atLocation($pathName);
222 }
223
224 $path = $this->prefixer->stripPrefix($pathName);
225 $lastModified = $fileInfo->getMTime();
226 $isDirectory = $fileInfo->isDir();
227 $permissions = octdec(substr(sprintf('%o', $fileInfo->getPerms()), -4));
228 $visibility = $isDirectory ? $this->visibility->inverseForDirectory($permissions) : $this->visibility->inverseForFile($permissions);
229
230 yield $isDirectory ? new DirectoryAttributes(str_replace('\\', '/', $path), $visibility, $lastModified) : new FileAttributes(
231 str_replace('\\', '/', $path),
232 $fileInfo->getSize(),
233 $visibility,
234 $lastModified
235 );
236 } catch (Throwable $exception) {
237 if (file_exists($pathName)) {
238 throw $exception;
239 }
240 }
241 }
242 }
243
244 public function move(string $source, string $destination, Config $config): void
245 {
246 $sourcePath = $this->prefixer->prefixPath($source);
247 $destinationPath = $this->prefixer->prefixPath($destination);
248
249 $this->ensureRootDirectoryExists();
250 $this->ensureDirectoryExists(
251 dirname($destinationPath),
252 $this->resolveDirectoryVisibility($config->get(Config::OPTION_DIRECTORY_VISIBILITY))
253 );
254
255 error_clear_last();
256 if ( ! @rename($sourcePath, $destinationPath)) {
257 throw UnableToMoveFile::because(error_get_last()['message'] ?? 'unknown reason', $source, $destination);
258 }
259
260 if ($visibility = $config->get(Config::OPTION_VISIBILITY)) {
261 $this->setVisibility($destination, (string) $visibility);
262 }
263 }
264
265 public function copy(string $source, string $destination, Config $config): void
266 {
267 $sourcePath = $this->prefixer->prefixPath($source);
268 $destinationPath = $this->prefixer->prefixPath($destination);
269 $this->ensureRootDirectoryExists();
270 $this->ensureDirectoryExists(
271 dirname($destinationPath),
272 $this->resolveDirectoryVisibility($config->get(Config::OPTION_DIRECTORY_VISIBILITY))
273 );
274
275 error_clear_last();
276 if ($sourcePath !== $destinationPath && ! @copy($sourcePath, $destinationPath)) {
277 throw UnableToCopyFile::because(error_get_last()['message'] ?? 'unknown', $source, $destination);
278 }
279
280 $visibility = $config->get(
281 Config::OPTION_VISIBILITY,
282 $config->get(Config::OPTION_RETAIN_VISIBILITY, true)
283 ? $this->visibility($source)->visibility()
284 : null,
285 );
286
287 if ($visibility) {
288 $this->setVisibility($destination, (string) $visibility);
289 }
290 }
291
292 public function read(string $path): string
293 {
294 $location = $this->prefixer->prefixPath($path);
295 error_clear_last();
296 $contents = @file_get_contents($location);
297
298 if ($contents === false) {
299 throw UnableToReadFile::fromLocation($path, error_get_last()['message'] ?? '');
300 }
301
302 return $contents;
303 }
304
305 public function readStream(string $path)
306 {
307 $location = $this->prefixer->prefixPath($path);
308 error_clear_last();
309 $contents = @fopen($location, 'rb');
310
311 if ($contents === false) {
312 throw UnableToReadFile::fromLocation($path, error_get_last()['message'] ?? '');
313 }
314
315 return $contents;
316 }
317
318 protected function ensureDirectoryExists(string $dirname, int $visibility): void
319 {
320 if (is_dir($dirname)) {
321 return;
322 }
323
324 error_clear_last();
325
326 if ( ! @mkdir($dirname, $visibility, true)) {
327 $mkdirError = error_get_last();
328 }
329
330 clearstatcache(true, $dirname);
331
332 if ( ! is_dir($dirname)) {
333 $errorMessage = isset($mkdirError['message']) ? $mkdirError['message'] : '';
334
335 throw UnableToCreateDirectory::atLocation($dirname, $errorMessage);
336 }
337 }
338
339 public function fileExists(string $location): bool
340 {
341 $location = $this->prefixer->prefixPath($location);
342 clearstatcache();
343 return is_file($location);
344 }
345
346 public function directoryExists(string $location): bool
347 {
348 $location = $this->prefixer->prefixPath($location);
349 clearstatcache();
350 return is_dir($location);
351 }
352
353 public function createDirectory(string $path, Config $config): void
354 {
355 $this->ensureRootDirectoryExists();
356 $location = $this->prefixer->prefixPath($path);
357 $visibility = $config->get(Config::OPTION_VISIBILITY, $config->get(Config::OPTION_DIRECTORY_VISIBILITY));
358 $permissions = $this->resolveDirectoryVisibility($visibility);
359
360 if (is_dir($location)) {
361 $this->setPermissions($location, $permissions);
362
363 return;
364 }
365
366 error_clear_last();
367
368 if ( ! @mkdir($location, $permissions, true)) {
369 throw UnableToCreateDirectory::atLocation($path, error_get_last()['message'] ?? '');
370 }
371 }
372
373 public function setVisibility(string $path, string $visibility): void
374 {
375 $path = $this->prefixer->prefixPath($path);
376 $visibility = is_dir($path) ? $this->visibility->forDirectory($visibility) : $this->visibility->forFile(
377 $visibility
378 );
379
380 $this->setPermissions($path, $visibility);
381 }
382
383 public function visibility(string $path): FileAttributes
384 {
385 $location = $this->prefixer->prefixPath($path);
386 clearstatcache(false, $location);
387 error_clear_last();
388 $fileperms = @fileperms($location);
389
390 if ($fileperms === false) {
391 throw UnableToRetrieveMetadata::visibility($path, error_get_last()['message'] ?? '');
392 }
393
394 $permissions = $fileperms & 0777;
395 $visibility = $this->visibility->inverseForFile($permissions);
396
397 return new FileAttributes($path, null, $visibility);
398 }
399
400 private function resolveDirectoryVisibility(?string $visibility): int
401 {
402 return $visibility === null ? $this->visibility->defaultForDirectories() : $this->visibility->forDirectory(
403 $visibility
404 );
405 }
406
407 public function mimeType(string $path): FileAttributes
408 {
409 $location = $this->prefixer->prefixPath($path);
410 error_clear_last();
411
412 if ( ! is_file($location)) {
413 throw UnableToRetrieveMetadata::mimeType($location, 'No such file exists.');
414 }
415
416 $mimeType = $this->mimeTypeDetector->detectMimeTypeFromFile($location);
417
418 if ($mimeType === null) {
419 throw UnableToRetrieveMetadata::mimeType($path, error_get_last()['message'] ?? '');
420 }
421
422 return new FileAttributes($path, null, null, null, $mimeType);
423 }
424
425 public function lastModified(string $path): FileAttributes
426 {
427 $location = $this->prefixer->prefixPath($path);
428 clearstatcache();
429 error_clear_last();
430 $lastModified = @filemtime($location);
431
432 if ($lastModified === false) {
433 throw UnableToRetrieveMetadata::lastModified($path, error_get_last()['message'] ?? '');
434 }
435
436 return new FileAttributes($path, null, null, $lastModified);
437 }
438
439 public function fileSize(string $path): FileAttributes
440 {
441 $location = $this->prefixer->prefixPath($path);
442 clearstatcache();
443 error_clear_last();
444
445 if (is_file($location) && ($fileSize = @filesize($location)) !== false) {
446 return new FileAttributes($path, $fileSize);
447 }
448
449 throw UnableToRetrieveMetadata::fileSize($path, error_get_last()['message'] ?? '');
450 }
451
452 public function checksum(string $path, Config $config): string
453 {
454 $algo = $config->get('checksum_algo', 'md5');
455 $location = $this->prefixer->prefixPath($path);
456 error_clear_last();
457 $checksum = @hash_file($algo, $location);
458
459 if ($checksum === false) {
460 throw new UnableToProvideChecksum(error_get_last()['message'] ?? '', $path);
461 }
462
463 return $checksum;
464 }
465
466 private function listDirectory(string $location): Generator
467 {
468 $iterator = new DirectoryIterator($location);
469
470 foreach ($iterator as $item) {
471 if ($item->isDot()) {
472 continue;
473 }
474
475 yield $item;
476 }
477 }
478
479 private function setPermissions(string $location, int $visibility): void
480 {
481 error_clear_last();
482 if ( ! @chmod($location, $visibility)) {
483 $extraMessage = error_get_last()['message'] ?? '';
484 throw UnableToSetVisibility::atLocation($this->prefixer->stripPrefix($location), $extraMessage);
485 }
486 }
487 }
488