vendor/league/flysystem/src/Filesystem.php line 161

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace League\Flysystem;
  4. use DateTimeInterface;
  5. use Generator;
  6. use League\Flysystem\UrlGeneration\PrefixPublicUrlGenerator;
  7. use League\Flysystem\UrlGeneration\PublicUrlGenerator;
  8. use League\Flysystem\UrlGeneration\ShardedPrefixPublicUrlGenerator;
  9. use League\Flysystem\UrlGeneration\TemporaryUrlGenerator;
  10. use Throwable;
  11. use function array_key_exists;
  12. use function is_array;
  13. class Filesystem implements FilesystemOperator
  14. {
  15.     use CalculateChecksumFromStream;
  16.     private Config $config;
  17.     private PathNormalizer $pathNormalizer;
  18.     public function __construct(
  19.         private FilesystemAdapter $adapter,
  20.         array $config = [],
  21.         ?PathNormalizer $pathNormalizer null,
  22.         private ?PublicUrlGenerator $publicUrlGenerator null,
  23.         private ?TemporaryUrlGenerator $temporaryUrlGenerator null,
  24.     ) {
  25.         $this->config = new Config($config);
  26.         $this->pathNormalizer $pathNormalizer ?? new WhitespacePathNormalizer();
  27.     }
  28.     public function fileExists(string $location): bool
  29.     {
  30.         return $this->adapter->fileExists($this->pathNormalizer->normalizePath($location));
  31.     }
  32.     public function directoryExists(string $location): bool
  33.     {
  34.         return $this->adapter->directoryExists($this->pathNormalizer->normalizePath($location));
  35.     }
  36.     public function has(string $location): bool
  37.     {
  38.         $path $this->pathNormalizer->normalizePath($location);
  39.         return $this->adapter->fileExists($path) || $this->adapter->directoryExists($path);
  40.     }
  41.     public function write(string $locationstring $contents, array $config = []): void
  42.     {
  43.         $this->adapter->write(
  44.             $this->pathNormalizer->normalizePath($location),
  45.             $contents,
  46.             $this->config->extend($config)
  47.         );
  48.     }
  49.     public function writeStream(string $location$contents, array $config = []): void
  50.     {
  51.         /* @var resource $contents */
  52.         $this->assertIsResource($contents);
  53.         $this->rewindStream($contents);
  54.         $this->adapter->writeStream(
  55.             $this->pathNormalizer->normalizePath($location),
  56.             $contents,
  57.             $this->config->extend($config)
  58.         );
  59.     }
  60.     public function read(string $location): string
  61.     {
  62.         return $this->adapter->read($this->pathNormalizer->normalizePath($location));
  63.     }
  64.     public function readStream(string $location)
  65.     {
  66.         return $this->adapter->readStream($this->pathNormalizer->normalizePath($location));
  67.     }
  68.     public function delete(string $location): void
  69.     {
  70.         $this->adapter->delete($this->pathNormalizer->normalizePath($location));
  71.     }
  72.     public function deleteDirectory(string $location): void
  73.     {
  74.         $this->adapter->deleteDirectory($this->pathNormalizer->normalizePath($location));
  75.     }
  76.     public function createDirectory(string $location, array $config = []): void
  77.     {
  78.         $this->adapter->createDirectory(
  79.             $this->pathNormalizer->normalizePath($location),
  80.             $this->config->extend($config)
  81.         );
  82.     }
  83.     public function listContents(string $locationbool $deep self::LIST_SHALLOW): DirectoryListing
  84.     {
  85.         $path $this->pathNormalizer->normalizePath($location);
  86.         $listing $this->adapter->listContents($path$deep);
  87.         return new DirectoryListing($this->pipeListing($location$deep$listing));
  88.     }
  89.     private function pipeListing(string $locationbool $deepiterable $listing): Generator
  90.     {
  91.         try {
  92.             foreach ($listing as $item) {
  93.                 yield $item;
  94.             }
  95.         } catch (Throwable $exception) {
  96.             throw UnableToListContents::atLocation($location$deep$exception);
  97.         }
  98.     }
  99.     public function move(string $sourcestring $destination, array $config = []): void
  100.     {
  101.         $config $this->resolveConfigForMoveAndCopy($config);
  102.         $from $this->pathNormalizer->normalizePath($source);
  103.         $to $this->pathNormalizer->normalizePath($destination);
  104.         if ($from === $to) {
  105.             $resolutionStrategy $config->get(Config::OPTION_MOVE_IDENTICAL_PATHResolveIdenticalPathConflict::TRY);
  106.             if ($resolutionStrategy === ResolveIdenticalPathConflict::FAIL) {
  107.                 throw UnableToMoveFile::sourceAndDestinationAreTheSame($source$destination);
  108.             } elseif ($resolutionStrategy === ResolveIdenticalPathConflict::IGNORE) {
  109.                 return;
  110.             }
  111.         }
  112.         $this->adapter->move($from$to$config);
  113.     }
  114.     public function copy(string $sourcestring $destination, array $config = []): void
  115.     {
  116.         $config $this->resolveConfigForMoveAndCopy($config);
  117.         $from $this->pathNormalizer->normalizePath($source);
  118.         $to $this->pathNormalizer->normalizePath($destination);
  119.         if ($from === $to) {
  120.             $resolutionStrategy $config->get(Config::OPTION_COPY_IDENTICAL_PATHResolveIdenticalPathConflict::TRY);
  121.             if ($resolutionStrategy === ResolveIdenticalPathConflict::FAIL) {
  122.                 throw UnableToCopyFile::sourceAndDestinationAreTheSame($source$destination);
  123.             } elseif ($resolutionStrategy === ResolveIdenticalPathConflict::IGNORE) {
  124.                 return;
  125.             }
  126.         }
  127.         $this->adapter->copy($from$to$config);
  128.     }
  129.     public function lastModified(string $path): int
  130.     {
  131.         return $this->adapter->lastModified($this->pathNormalizer->normalizePath($path))->lastModified();
  132.     }
  133.     public function fileSize(string $path): int
  134.     {
  135.         return $this->adapter->fileSize($this->pathNormalizer->normalizePath($path))->fileSize();
  136.     }
  137.     public function mimeType(string $path): string
  138.     {
  139.         return $this->adapter->mimeType($this->pathNormalizer->normalizePath($path))->mimeType();
  140.     }
  141.     public function setVisibility(string $pathstring $visibility): void
  142.     {
  143.         $this->adapter->setVisibility($this->pathNormalizer->normalizePath($path), $visibility);
  144.     }
  145.     public function visibility(string $path): string
  146.     {
  147.         return $this->adapter->visibility($this->pathNormalizer->normalizePath($path))->visibility();
  148.     }
  149.     public function publicUrl(string $path, array $config = []): string
  150.     {
  151.         $this->publicUrlGenerator ??= $this->resolvePublicUrlGenerator()
  152.             ?? throw UnableToGeneratePublicUrl::noGeneratorConfigured($path);
  153.         $config $this->config->extend($config);
  154.         return $this->publicUrlGenerator->publicUrl($this->pathNormalizer->normalizePath($path), $config);
  155.     }
  156.     public function temporaryUrl(string $pathDateTimeInterface $expiresAt, array $config = []): string
  157.     {
  158.         $generator $this->temporaryUrlGenerator ?? $this->adapter;
  159.         if ($generator instanceof TemporaryUrlGenerator) {
  160.             return $generator->temporaryUrl(
  161.                 $this->pathNormalizer->normalizePath($path),
  162.                 $expiresAt,
  163.                 $this->config->extend($config)
  164.             );
  165.         }
  166.         throw UnableToGenerateTemporaryUrl::noGeneratorConfigured($path);
  167.     }
  168.     public function checksum(string $path, array $config = []): string
  169.     {
  170.         $config $this->config->extend($config);
  171.         if ( ! $this->adapter instanceof ChecksumProvider) {
  172.             return $this->calculateChecksumFromStream($path$config);
  173.         }
  174.         try {
  175.             return $this->adapter->checksum($path$config);
  176.         } catch (ChecksumAlgoIsNotSupported) {
  177.             return $this->calculateChecksumFromStream($path$config);
  178.         }
  179.     }
  180.     private function resolvePublicUrlGenerator(): ?PublicUrlGenerator
  181.     {
  182.         if ($publicUrl $this->config->get('public_url')) {
  183.             return match (true) {
  184.                 is_array($publicUrl) => new ShardedPrefixPublicUrlGenerator($publicUrl),
  185.                 default => new PrefixPublicUrlGenerator($publicUrl),
  186.             };
  187.         }
  188.         if ($this->adapter instanceof PublicUrlGenerator) {
  189.             return $this->adapter;
  190.         }
  191.         return null;
  192.     }
  193.     /**
  194.      * @param mixed $contents
  195.      */
  196.     private function assertIsResource($contents): void
  197.     {
  198.         if (is_resource($contents) === false) {
  199.             throw new InvalidStreamProvided(
  200.                 "Invalid stream provided, expected stream resource, received " gettype($contents)
  201.             );
  202.         } elseif ($type get_resource_type($contents) !== 'stream') {
  203.             throw new InvalidStreamProvided(
  204.                 "Invalid stream provided, expected stream resource, received resource of type " $type
  205.             );
  206.         }
  207.     }
  208.     /**
  209.      * @param resource $resource
  210.      */
  211.     private function rewindStream($resource): void
  212.     {
  213.         if (ftell($resource) !== && stream_get_meta_data($resource)['seekable']) {
  214.             rewind($resource);
  215.         }
  216.     }
  217.     private function resolveConfigForMoveAndCopy(array $config): Config
  218.     {
  219.         $retainVisibility $this->config->get(Config::OPTION_RETAIN_VISIBILITY$config[Config::OPTION_RETAIN_VISIBILITY] ?? true);
  220.         $fullConfig $this->config->extend($config);
  221.         /*
  222.          * By default, we retain visibility. When we do not retain visibility, the visibility setting
  223.          * from the default configuration is ignored. Only when it is set explicitly, we propagate the
  224.          * setting.
  225.          */
  226.         if ($retainVisibility && ! array_key_exists(Config::OPTION_VISIBILITY$config)) {
  227.             $fullConfig $fullConfig->withoutSettings(Config::OPTION_VISIBILITY)->extend($config);
  228.         }
  229.         return $fullConfig;
  230.     }
  231. }