first commit

This commit is contained in:
Sampanna Rimal
2024-08-27 17:48:06 +05:45
commit 53c0140f58
10839 changed files with 1125847 additions and 0 deletions

2
vendor/league/flysystem/INFO.md vendored Normal file
View File

@ -0,0 +1,2 @@
View the docs at: https://flysystem.thephpleague.com/docs/
Changelog at: https://github.com/thephpleague/flysystem/blob/3.x/CHANGELOG.md

19
vendor/league/flysystem/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2013-2024 Frank de Jonge
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

69
vendor/league/flysystem/composer.json vendored Normal file
View File

@ -0,0 +1,69 @@
{
"name": "league/flysystem",
"description": "File storage abstraction for PHP",
"keywords": [
"filesystem", "filesystems", "files", "storage", "aws",
"s3", "ftp", "sftp", "webdav", "file", "cloud"
],
"scripts": {
"phpstan": "vendor/bin/phpstan analyse -l 6 src"
},
"type": "library",
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"League\\Flysystem\\": "src"
}
},
"require": {
"php": "^8.0.2",
"league/flysystem-local": "^3.0.0",
"league/mime-type-detection": "^1.0.0"
},
"require-dev": {
"ext-zip": "*",
"ext-fileinfo": "*",
"ext-ftp": "*",
"microsoft/azure-storage-blob": "^1.1",
"phpunit/phpunit": "^9.5.11|^10.0",
"phpstan/phpstan": "^1.10",
"phpseclib/phpseclib": "^3.0.36",
"aws/aws-sdk-php": "^3.295.10",
"composer/semver": "^3.0",
"friendsofphp/php-cs-fixer": "^3.5",
"google/cloud-storage": "^1.23",
"async-aws/s3": "^1.5 || ^2.0",
"async-aws/simple-s3": "^1.1 || ^2.0",
"sabre/dav": "^4.6.0"
},
"conflict": {
"async-aws/core": "<1.19.0",
"async-aws/s3": "<1.14.0",
"symfony/http-client": "<5.2",
"guzzlehttp/ringphp": "<1.1.1",
"guzzlehttp/guzzle": "<7.0",
"aws/aws-sdk-php": "3.209.31 || 3.210.0",
"phpseclib/phpseclib": "3.0.15"
},
"license": "MIT",
"authors": [
{
"name": "Frank de Jonge",
"email": "info@frankdejonge.nl"
}
],
"repositories": [
{
"type": "package",
"package": {
"name": "league/flysystem-local",
"version": "3.0.0",
"dist": {
"type": "path",
"url": "src/Local"
}
}
}
]
}

58
vendor/league/flysystem/readme.md vendored Normal file
View File

@ -0,0 +1,58 @@
# League\Flysystem
[![Author](https://img.shields.io/badge/author-@frankdejonge-blue.svg)](https://twitter.com/frankdejonge)
[![Source Code](https://img.shields.io/badge/source-thephpleague/flysystem-blue.svg)](https://github.com/thephpleague/flysystem)
[![Latest Version](https://img.shields.io/github/tag/thephpleague/flysystem.svg)](https://github.com/thephpleague/flysystem/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/thephpleague/flysystem/blob/master/LICENSE)
[![Quality Assurance](https://github.com/thephpleague/flysystem/workflows/Quality%20Assurance/badge.svg?branch=2.x)](https://github.com/thephpleague/flysystem/actions?query=workflow%3A%22Quality+Assurance%22)
[![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem.svg)](https://packagist.org/packages/league/flysystem)
![php 7.2+](https://img.shields.io/badge/php-min%208.0.2-red.svg)
## About Flysystem
Flysystem is a file storage library for PHP. It provides one interface to
interact with many types of filesystems. When you use Flysystem, you're
not only protected from vendor lock-in, you'll also have a consistent experience
for which ever storage is right for you.
## Getting Started
* **[New in V3](https://flysystem.thephpleague.com/docs/what-is-new/)**: What is new in Flysystem V2/V3?
* **[Architecture](https://flysystem.thephpleague.com/docs/architecture/)**: Flysystem's internal architecture
* **[Flysystem API](https://flysystem.thephpleague.com/docs/usage/filesystem-api/)**: How to interact with your Flysystem instance
* **[Upgrade from 1x](https://flysystem.thephpleague.com/docs/upgrade-from-1.x/)**: How to upgrade from 1.x/2.x
### Officially supported adapters
* **[Local](https://flysystem.thephpleague.com/docs/adapter/local/)**
* **[FTP](https://flysystem.thephpleague.com/docs/adapter/ftp/)**
* **[SFTP](https://flysystem.thephpleague.com/docs/adapter/sftp-v3/)**
* **[Memory](https://flysystem.thephpleague.com/docs/adapter/in-memory/)**
* **[AWS S3](https://flysystem.thephpleague.com/docs/adapter/aws-s3-v3/)**
* **[AsyncAws S3](https://flysystem.thephpleague.com/docs/adapter/async-aws-s3/)**
* **[Google Cloud Storage](https://flysystem.thephpleague.com/docs/adapter/google-cloud-storage/)**
* **[Azure Blob Storage](https://flysystem.thephpleague.com/docs/adapter/azure-blob-storage/)**
* **[WebDAV](https://flysystem.thephpleague.com/docs/adapter/webdav/)**
* **[ZipArchive](https://flysystem.thephpleague.com/docs/adapter/zip-archive/)**
### Third party Adapters
* **[Gitlab](https://github.com/RoyVoetman/flysystem-gitlab-storage)**
* **[Google Drive (using regular paths)](https://github.com/masbug/flysystem-google-drive-ext)**
* **[bunny.net / BunnyCDN](https://github.com/PlatformCommunity/flysystem-bunnycdn/tree/v3)**
* **[Sharepoint 365 / One Drive (Using MS Graph)](https://github.com/shitware-ltd/flysystem-msgraph)**
* **[OneDrive](https://github.com/doerffler/flysystem-onedrive)**
* **[Dropbox](https://github.com/spatie/flysystem-dropbox)**
* **[ReplicateAdapter](https://github.com/ajgarlag/flysystem-replicate)**
* **[Uploadcare](https://github.com/vormkracht10/flysystem-uploadcare)**
* **[Useful adapters (FallbackAdapter, LogAdapter, ReadWriteAdapter, RetryAdapter)](https://github.com/ElGigi/FlysystemUsefulAdapters)**
You can always [create an adapter](https://flysystem.thephpleague.com/docs/advanced/creating-an-adapter/) yourself.
## Security
If you discover any security related issues, please email info@frankdejonge.nl instead of using the issue tracker.
## Enjoy
Oh, and if you've come down this far, you might as well follow me on [twitter](https://twitter.com/frankdejonge).

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use function hash_final;
use function hash_init;
use function hash_update_stream;
trait CalculateChecksumFromStream
{
private function calculateChecksumFromStream(string $path, Config $config): string
{
try {
$stream = $this->readStream($path);
$algo = (string) $config->get('checksum_algo', 'md5');
$context = hash_init($algo);
hash_update_stream($context, $stream);
return hash_final($context);
} catch (FilesystemException $exception) {
throw new UnableToProvideChecksum($exception->getMessage(), $path, $exception);
}
}
/**
* @return resource
*/
abstract public function readStream(string $path);
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use InvalidArgumentException;
final class ChecksumAlgoIsNotSupported extends InvalidArgumentException
{
}

View File

@ -0,0 +1,14 @@
<?php
namespace League\Flysystem;
interface ChecksumProvider
{
/**
* @return string MD5 hash of the file contents
*
* @throws UnableToProvideChecksum
* @throws ChecksumAlgoIsNotSupported
*/
public function checksum(string $path, Config $config): string;
}

57
vendor/league/flysystem/src/Config.php vendored Normal file
View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use function array_diff_key;
use function array_flip;
use function array_merge;
class Config
{
public const OPTION_COPY_IDENTICAL_PATH = 'copy_destination_same_as_source';
public const OPTION_MOVE_IDENTICAL_PATH = 'move_destination_same_as_source';
public const OPTION_VISIBILITY = 'visibility';
public const OPTION_DIRECTORY_VISIBILITY = 'directory_visibility';
public const OPTION_RETAIN_VISIBILITY = 'retain_visibility';
public function __construct(private array $options = [])
{
}
/**
* @param mixed $default
*
* @return mixed
*/
public function get(string $property, $default = null)
{
return $this->options[$property] ?? $default;
}
public function extend(array $options): Config
{
return new Config(array_merge($this->options, $options));
}
public function withDefaults(array $defaults): Config
{
return new Config($this->options + $defaults);
}
public function toArray(): array
{
return $this->options;
}
public function withSetting(string $property, mixed $setting): Config
{
return $this->extend([$property => $setting]);
}
public function withoutSettings(string ...$settings): Config
{
return new Config(array_diff_key($this->options, array_flip($settings)));
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace League\Flysystem;
use RuntimeException;
final class CorruptedPathDetected extends RuntimeException implements FilesystemException
{
public static function forPath(string $path): CorruptedPathDetected
{
return new CorruptedPathDetected("Corrupted path detected: " . $path);
}
}

View File

@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
abstract class DecoratedAdapter implements FilesystemAdapter
{
public function __construct(protected FilesystemAdapter $adapter)
{
}
public function fileExists(string $path): bool
{
return $this->adapter->fileExists($path);
}
public function directoryExists(string $path): bool
{
return $this->adapter->directoryExists($path);
}
public function write(string $path, string $contents, Config $config): void
{
$this->adapter->write($path, $contents, $config);
}
public function writeStream(string $path, $contents, Config $config): void
{
$this->adapter->writeStream($path, $contents, $config);
}
public function read(string $path): string
{
return $this->adapter->read($path);
}
public function readStream(string $path)
{
return $this->adapter->readStream($path);
}
public function delete(string $path): void
{
$this->adapter->delete($path);
}
public function deleteDirectory(string $path): void
{
$this->adapter->deleteDirectory($path);
}
public function createDirectory(string $path, Config $config): void
{
$this->adapter->createDirectory($path, $config);
}
public function setVisibility(string $path, string $visibility): void
{
$this->adapter->setVisibility($path, $visibility);
}
public function visibility(string $path): FileAttributes
{
return $this->adapter->visibility($path);
}
public function mimeType(string $path): FileAttributes
{
return $this->adapter->mimeType($path);
}
public function lastModified(string $path): FileAttributes
{
return $this->adapter->lastModified($path);
}
public function fileSize(string $path): FileAttributes
{
return $this->adapter->fileSize($path);
}
public function listContents(string $path, bool $deep): iterable
{
return $this->adapter->listContents($path, $deep);
}
public function move(string $source, string $destination, Config $config): void
{
$this->adapter->move($source, $destination, $config);
}
public function copy(string $source, string $destination, Config $config): void
{
$this->adapter->copy($source, $destination, $config);
}
}

View File

@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
class DirectoryAttributes implements StorageAttributes
{
use ProxyArrayAccessToProperties;
private string $type = StorageAttributes::TYPE_DIRECTORY;
public function __construct(
private string $path,
private ?string $visibility = null,
private ?int $lastModified = null,
private array $extraMetadata = []
) {
$this->path = trim($this->path, '/');
}
public function path(): string
{
return $this->path;
}
public function type(): string
{
return $this->type;
}
public function visibility(): ?string
{
return $this->visibility;
}
public function lastModified(): ?int
{
return $this->lastModified;
}
public function extraMetadata(): array
{
return $this->extraMetadata;
}
public function isFile(): bool
{
return false;
}
public function isDir(): bool
{
return true;
}
public function withPath(string $path): self
{
$clone = clone $this;
$clone->path = $path;
return $clone;
}
public static function fromArray(array $attributes): self
{
return new DirectoryAttributes(
$attributes[StorageAttributes::ATTRIBUTE_PATH],
$attributes[StorageAttributes::ATTRIBUTE_VISIBILITY] ?? null,
$attributes[StorageAttributes::ATTRIBUTE_LAST_MODIFIED] ?? null,
$attributes[StorageAttributes::ATTRIBUTE_EXTRA_METADATA] ?? []
);
}
/**
* @inheritDoc
*/
public function jsonSerialize(): array
{
return [
StorageAttributes::ATTRIBUTE_TYPE => $this->type,
StorageAttributes::ATTRIBUTE_PATH => $this->path,
StorageAttributes::ATTRIBUTE_VISIBILITY => $this->visibility,
StorageAttributes::ATTRIBUTE_LAST_MODIFIED => $this->lastModified,
StorageAttributes::ATTRIBUTE_EXTRA_METADATA => $this->extraMetadata,
];
}
}

View File

@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use ArrayIterator;
use Generator;
use IteratorAggregate;
use Traversable;
/**
* @template T
*/
class DirectoryListing implements IteratorAggregate
{
/**
* @param iterable<T> $listing
*/
public function __construct(private iterable $listing)
{
}
/**
* @param callable(T): bool $filter
*
* @return DirectoryListing<T>
*/
public function filter(callable $filter): DirectoryListing
{
$generator = (static function (iterable $listing) use ($filter): Generator {
foreach ($listing as $item) {
if ($filter($item)) {
yield $item;
}
}
})($this->listing);
return new DirectoryListing($generator);
}
/**
* @template R
*
* @param callable(T): R $mapper
*
* @return DirectoryListing<R>
*/
public function map(callable $mapper): DirectoryListing
{
$generator = (static function (iterable $listing) use ($mapper): Generator {
foreach ($listing as $item) {
yield $mapper($item);
}
})($this->listing);
return new DirectoryListing($generator);
}
/**
* @return DirectoryListing<T>
*/
public function sortByPath(): DirectoryListing
{
$listing = $this->toArray();
usort($listing, function (StorageAttributes $a, StorageAttributes $b) {
return $a->path() <=> $b->path();
});
return new DirectoryListing($listing);
}
/**
* @return Traversable<T>
*/
public function getIterator(): Traversable
{
return $this->listing instanceof Traversable
? $this->listing
: new ArrayIterator($this->listing);
}
/**
* @return T[]
*/
public function toArray(): array
{
return $this->listing instanceof Traversable
? iterator_to_array($this->listing, false)
: (array) $this->listing;
}
}

View File

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
class FileAttributes implements StorageAttributes
{
use ProxyArrayAccessToProperties;
private string $type = StorageAttributes::TYPE_FILE;
public function __construct(
private string $path,
private ?int $fileSize = null,
private ?string $visibility = null,
private ?int $lastModified = null,
private ?string $mimeType = null,
private array $extraMetadata = []
) {
$this->path = ltrim($this->path, '/');
}
public function type(): string
{
return $this->type;
}
public function path(): string
{
return $this->path;
}
public function fileSize(): ?int
{
return $this->fileSize;
}
public function visibility(): ?string
{
return $this->visibility;
}
public function lastModified(): ?int
{
return $this->lastModified;
}
public function mimeType(): ?string
{
return $this->mimeType;
}
public function extraMetadata(): array
{
return $this->extraMetadata;
}
public function isFile(): bool
{
return true;
}
public function isDir(): bool
{
return false;
}
public function withPath(string $path): self
{
$clone = clone $this;
$clone->path = $path;
return $clone;
}
public static function fromArray(array $attributes): self
{
return new FileAttributes(
$attributes[StorageAttributes::ATTRIBUTE_PATH],
$attributes[StorageAttributes::ATTRIBUTE_FILE_SIZE] ?? null,
$attributes[StorageAttributes::ATTRIBUTE_VISIBILITY] ?? null,
$attributes[StorageAttributes::ATTRIBUTE_LAST_MODIFIED] ?? null,
$attributes[StorageAttributes::ATTRIBUTE_MIME_TYPE] ?? null,
$attributes[StorageAttributes::ATTRIBUTE_EXTRA_METADATA] ?? []
);
}
public function jsonSerialize(): array
{
return [
StorageAttributes::ATTRIBUTE_TYPE => self::TYPE_FILE,
StorageAttributes::ATTRIBUTE_PATH => $this->path,
StorageAttributes::ATTRIBUTE_FILE_SIZE => $this->fileSize,
StorageAttributes::ATTRIBUTE_VISIBILITY => $this->visibility,
StorageAttributes::ATTRIBUTE_LAST_MODIFIED => $this->lastModified,
StorageAttributes::ATTRIBUTE_MIME_TYPE => $this->mimeType,
StorageAttributes::ATTRIBUTE_EXTRA_METADATA => $this->extraMetadata,
];
}
}

View File

@ -0,0 +1,281 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use DateTimeInterface;
use Generator;
use League\Flysystem\UrlGeneration\PrefixPublicUrlGenerator;
use League\Flysystem\UrlGeneration\PublicUrlGenerator;
use League\Flysystem\UrlGeneration\ShardedPrefixPublicUrlGenerator;
use League\Flysystem\UrlGeneration\TemporaryUrlGenerator;
use Throwable;
use function array_key_exists;
use function is_array;
class Filesystem implements FilesystemOperator
{
use CalculateChecksumFromStream;
private Config $config;
private PathNormalizer $pathNormalizer;
public function __construct(
private FilesystemAdapter $adapter,
array $config = [],
?PathNormalizer $pathNormalizer = null,
private ?PublicUrlGenerator $publicUrlGenerator = null,
private ?TemporaryUrlGenerator $temporaryUrlGenerator = null,
) {
$this->config = new Config($config);
$this->pathNormalizer = $pathNormalizer ?? new WhitespacePathNormalizer();
}
public function fileExists(string $location): bool
{
return $this->adapter->fileExists($this->pathNormalizer->normalizePath($location));
}
public function directoryExists(string $location): bool
{
return $this->adapter->directoryExists($this->pathNormalizer->normalizePath($location));
}
public function has(string $location): bool
{
$path = $this->pathNormalizer->normalizePath($location);
return $this->adapter->fileExists($path) || $this->adapter->directoryExists($path);
}
public function write(string $location, string $contents, array $config = []): void
{
$this->adapter->write(
$this->pathNormalizer->normalizePath($location),
$contents,
$this->config->extend($config)
);
}
public function writeStream(string $location, $contents, array $config = []): void
{
/* @var resource $contents */
$this->assertIsResource($contents);
$this->rewindStream($contents);
$this->adapter->writeStream(
$this->pathNormalizer->normalizePath($location),
$contents,
$this->config->extend($config)
);
}
public function read(string $location): string
{
return $this->adapter->read($this->pathNormalizer->normalizePath($location));
}
public function readStream(string $location)
{
return $this->adapter->readStream($this->pathNormalizer->normalizePath($location));
}
public function delete(string $location): void
{
$this->adapter->delete($this->pathNormalizer->normalizePath($location));
}
public function deleteDirectory(string $location): void
{
$this->adapter->deleteDirectory($this->pathNormalizer->normalizePath($location));
}
public function createDirectory(string $location, array $config = []): void
{
$this->adapter->createDirectory(
$this->pathNormalizer->normalizePath($location),
$this->config->extend($config)
);
}
public function listContents(string $location, bool $deep = self::LIST_SHALLOW): DirectoryListing
{
$path = $this->pathNormalizer->normalizePath($location);
$listing = $this->adapter->listContents($path, $deep);
return new DirectoryListing($this->pipeListing($location, $deep, $listing));
}
private function pipeListing(string $location, bool $deep, iterable $listing): Generator
{
try {
foreach ($listing as $item) {
yield $item;
}
} catch (Throwable $exception) {
throw UnableToListContents::atLocation($location, $deep, $exception);
}
}
public function move(string $source, string $destination, array $config = []): void
{
$config = $this->resolveConfigForMoveAndCopy($config);
$from = $this->pathNormalizer->normalizePath($source);
$to = $this->pathNormalizer->normalizePath($destination);
if ($from === $to) {
$resolutionStrategy = $config->get(Config::OPTION_MOVE_IDENTICAL_PATH, ResolveIdenticalPathConflict::TRY);
if ($resolutionStrategy === ResolveIdenticalPathConflict::FAIL) {
throw UnableToMoveFile::sourceAndDestinationAreTheSame($source, $destination);
} elseif ($resolutionStrategy === ResolveIdenticalPathConflict::IGNORE) {
return;
}
}
$this->adapter->move($from, $to, $config);
}
public function copy(string $source, string $destination, array $config = []): void
{
$config = $this->resolveConfigForMoveAndCopy($config);
$from = $this->pathNormalizer->normalizePath($source);
$to = $this->pathNormalizer->normalizePath($destination);
if ($from === $to) {
$resolutionStrategy = $config->get(Config::OPTION_COPY_IDENTICAL_PATH, ResolveIdenticalPathConflict::TRY);
if ($resolutionStrategy === ResolveIdenticalPathConflict::FAIL) {
throw UnableToCopyFile::sourceAndDestinationAreTheSame($source, $destination);
} elseif ($resolutionStrategy === ResolveIdenticalPathConflict::IGNORE) {
return;
}
}
$this->adapter->copy($from, $to, $config);
}
public function lastModified(string $path): int
{
return $this->adapter->lastModified($this->pathNormalizer->normalizePath($path))->lastModified();
}
public function fileSize(string $path): int
{
return $this->adapter->fileSize($this->pathNormalizer->normalizePath($path))->fileSize();
}
public function mimeType(string $path): string
{
return $this->adapter->mimeType($this->pathNormalizer->normalizePath($path))->mimeType();
}
public function setVisibility(string $path, string $visibility): void
{
$this->adapter->setVisibility($this->pathNormalizer->normalizePath($path), $visibility);
}
public function visibility(string $path): string
{
return $this->adapter->visibility($this->pathNormalizer->normalizePath($path))->visibility();
}
public function publicUrl(string $path, array $config = []): string
{
$this->publicUrlGenerator ??= $this->resolvePublicUrlGenerator()
?? throw UnableToGeneratePublicUrl::noGeneratorConfigured($path);
$config = $this->config->extend($config);
return $this->publicUrlGenerator->publicUrl($this->pathNormalizer->normalizePath($path), $config);
}
public function temporaryUrl(string $path, DateTimeInterface $expiresAt, array $config = []): string
{
$generator = $this->temporaryUrlGenerator ?? $this->adapter;
if ($generator instanceof TemporaryUrlGenerator) {
return $generator->temporaryUrl(
$this->pathNormalizer->normalizePath($path),
$expiresAt,
$this->config->extend($config)
);
}
throw UnableToGenerateTemporaryUrl::noGeneratorConfigured($path);
}
public function checksum(string $path, array $config = []): string
{
$config = $this->config->extend($config);
if ( ! $this->adapter instanceof ChecksumProvider) {
return $this->calculateChecksumFromStream($path, $config);
}
try {
return $this->adapter->checksum($path, $config);
} catch (ChecksumAlgoIsNotSupported) {
return $this->calculateChecksumFromStream($path, $config);
}
}
private function resolvePublicUrlGenerator(): ?PublicUrlGenerator
{
if ($publicUrl = $this->config->get('public_url')) {
return match (true) {
is_array($publicUrl) => new ShardedPrefixPublicUrlGenerator($publicUrl),
default => new PrefixPublicUrlGenerator($publicUrl),
};
}
if ($this->adapter instanceof PublicUrlGenerator) {
return $this->adapter;
}
return null;
}
/**
* @param mixed $contents
*/
private function assertIsResource($contents): void
{
if (is_resource($contents) === false) {
throw new InvalidStreamProvided(
"Invalid stream provided, expected stream resource, received " . gettype($contents)
);
} elseif ($type = get_resource_type($contents) !== 'stream') {
throw new InvalidStreamProvided(
"Invalid stream provided, expected stream resource, received resource of type " . $type
);
}
}
/**
* @param resource $resource
*/
private function rewindStream($resource): void
{
if (ftell($resource) !== 0 && stream_get_meta_data($resource)['seekable']) {
rewind($resource);
}
}
private function resolveConfigForMoveAndCopy(array $config): Config
{
$retainVisibility = $this->config->get(Config::OPTION_RETAIN_VISIBILITY, $config[Config::OPTION_RETAIN_VISIBILITY] ?? true);
$fullConfig = $this->config->extend($config);
/*
* By default, we retain visibility. When we do not retain visibility, the visibility setting
* from the default configuration is ignored. Only when it is set explicitly, we propagate the
* setting.
*/
if ($retainVisibility && ! array_key_exists(Config::OPTION_VISIBILITY, $config)) {
$fullConfig = $fullConfig->withoutSettings(Config::OPTION_VISIBILITY)->extend($config);
}
return $fullConfig;
}
}

View File

@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
interface FilesystemAdapter
{
/**
* @throws FilesystemException
* @throws UnableToCheckExistence
*/
public function fileExists(string $path): bool;
/**
* @throws FilesystemException
* @throws UnableToCheckExistence
*/
public function directoryExists(string $path): bool;
/**
* @throws UnableToWriteFile
* @throws FilesystemException
*/
public function write(string $path, string $contents, Config $config): void;
/**
* @param resource $contents
*
* @throws UnableToWriteFile
* @throws FilesystemException
*/
public function writeStream(string $path, $contents, Config $config): void;
/**
* @throws UnableToReadFile
* @throws FilesystemException
*/
public function read(string $path): string;
/**
* @return resource
*
* @throws UnableToReadFile
* @throws FilesystemException
*/
public function readStream(string $path);
/**
* @throws UnableToDeleteFile
* @throws FilesystemException
*/
public function delete(string $path): void;
/**
* @throws UnableToDeleteDirectory
* @throws FilesystemException
*/
public function deleteDirectory(string $path): void;
/**
* @throws UnableToCreateDirectory
* @throws FilesystemException
*/
public function createDirectory(string $path, Config $config): void;
/**
* @throws InvalidVisibilityProvided
* @throws FilesystemException
*/
public function setVisibility(string $path, string $visibility): void;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function visibility(string $path): FileAttributes;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function mimeType(string $path): FileAttributes;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function lastModified(string $path): FileAttributes;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function fileSize(string $path): FileAttributes;
/**
* @return iterable<StorageAttributes>
*
* @throws FilesystemException
*/
public function listContents(string $path, bool $deep): iterable;
/**
* @throws UnableToMoveFile
* @throws FilesystemException
*/
public function move(string $source, string $destination, Config $config): void;
/**
* @throws UnableToCopyFile
* @throws FilesystemException
*/
public function copy(string $source, string $destination, Config $config): void;
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use Throwable;
interface FilesystemException extends Throwable
{
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
interface FilesystemOperationFailed extends FilesystemException
{
public const OPERATION_WRITE = 'WRITE';
public const OPERATION_UPDATE = 'UPDATE'; // not used
public const OPERATION_EXISTENCE_CHECK = 'EXISTENCE_CHECK';
public const OPERATION_DIRECTORY_EXISTS = 'DIRECTORY_EXISTS';
public const OPERATION_FILE_EXISTS = 'FILE_EXISTS';
public const OPERATION_CREATE_DIRECTORY = 'CREATE_DIRECTORY';
public const OPERATION_DELETE = 'DELETE';
public const OPERATION_DELETE_DIRECTORY = 'DELETE_DIRECTORY';
public const OPERATION_MOVE = 'MOVE';
public const OPERATION_RETRIEVE_METADATA = 'RETRIEVE_METADATA';
public const OPERATION_COPY = 'COPY';
public const OPERATION_READ = 'READ';
public const OPERATION_SET_VISIBILITY = 'SET_VISIBILITY';
public const OPERATION_LIST_CONTENTS = 'LIST_CONTENTS';
public function operation(): string;
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
interface FilesystemOperator extends FilesystemReader, FilesystemWriter
{
}

View File

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use DateTimeInterface;
/**
* This interface contains everything to read from and inspect
* a filesystem. All methods containing are non-destructive.
*
* @method string publicUrl(string $path, array $config = []) Will be added in 4.0
* @method string temporaryUrl(string $path, DateTimeInterface $expiresAt, array $config = []) Will be added in 4.0
* @method string checksum(string $path, array $config = []) Will be added in 4.0
*/
interface FilesystemReader
{
public const LIST_SHALLOW = false;
public const LIST_DEEP = true;
/**
* @throws FilesystemException
* @throws UnableToCheckExistence
*/
public function fileExists(string $location): bool;
/**
* @throws FilesystemException
* @throws UnableToCheckExistence
*/
public function directoryExists(string $location): bool;
/**
* @throws FilesystemException
* @throws UnableToCheckExistence
*/
public function has(string $location): bool;
/**
* @throws UnableToReadFile
* @throws FilesystemException
*/
public function read(string $location): string;
/**
* @return resource
*
* @throws UnableToReadFile
* @throws FilesystemException
*/
public function readStream(string $location);
/**
* @return DirectoryListing<StorageAttributes>
*
* @throws FilesystemException
* @throws UnableToListContents
*/
public function listContents(string $location, bool $deep = self::LIST_SHALLOW): DirectoryListing;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function lastModified(string $path): int;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function fileSize(string $path): int;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function mimeType(string $path): string;
/**
* @throws UnableToRetrieveMetadata
* @throws FilesystemException
*/
public function visibility(string $path): string;
}

View File

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
interface FilesystemWriter
{
/**
* @throws UnableToWriteFile
* @throws FilesystemException
*/
public function write(string $location, string $contents, array $config = []): void;
/**
* @param mixed $contents
*
* @throws UnableToWriteFile
* @throws FilesystemException
*/
public function writeStream(string $location, $contents, array $config = []): void;
/**
* @throws UnableToSetVisibility
* @throws FilesystemException
*/
public function setVisibility(string $path, string $visibility): void;
/**
* @throws UnableToDeleteFile
* @throws FilesystemException
*/
public function delete(string $location): void;
/**
* @throws UnableToDeleteDirectory
* @throws FilesystemException
*/
public function deleteDirectory(string $location): void;
/**
* @throws UnableToCreateDirectory
* @throws FilesystemException
*/
public function createDirectory(string $location, array $config = []): void;
/**
* @throws UnableToMoveFile
* @throws FilesystemException
*/
public function move(string $source, string $destination, array $config = []): void;
/**
* @throws UnableToCopyFile
* @throws FilesystemException
*/
public function copy(string $source, string $destination, array $config = []): void;
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use InvalidArgumentException as BaseInvalidArgumentException;
class InvalidStreamProvided extends BaseInvalidArgumentException implements FilesystemException
{
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use InvalidArgumentException;
use function var_export;
class InvalidVisibilityProvided extends InvalidArgumentException implements FilesystemException
{
public static function withVisibility(string $visibility, string $expectedMessage): InvalidVisibilityProvided
{
$provided = var_export($visibility, true);
$message = "Invalid visibility provided. Expected {$expectedMessage}, received {$provided}";
throw new InvalidVisibilityProvided($message);
}
}

View File

@ -0,0 +1,434 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use DateTimeInterface;
use Throwable;
use function compact;
use function method_exists;
use function sprintf;
class MountManager implements FilesystemOperator
{
/**
* @var array<string, FilesystemOperator>
*/
private $filesystems = [];
/**
* @var Config
*/
private $config;
/**
* MountManager constructor.
*
* @param array<string,FilesystemOperator> $filesystems
*/
public function __construct(array $filesystems = [], array $config = [])
{
$this->mountFilesystems($filesystems);
$this->config = new Config($config);
}
/**
* It is not recommended to mount filesystems after creation because interacting
* with the Mount Manager becomes unpredictable. Use this as an escape hatch.
*/
public function dangerouslyMountFilesystems(string $key, FilesystemOperator $filesystem): void
{
$this->mountFilesystem($key, $filesystem);
}
/**
* @param array<string,FilesystemOperator> $filesystems
*/
public function extend(array $filesystems, array $config = []): MountManager
{
$clone = clone $this;
$clone->config = $this->config->extend($config);
$clone->mountFilesystems($filesystems);
return $clone;
}
public function fileExists(string $location): bool
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->fileExists($path);
} catch (Throwable $exception) {
throw UnableToCheckFileExistence::forLocation($location, $exception);
}
}
public function has(string $location): bool
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->fileExists($path) || $filesystem->directoryExists($path);
} catch (Throwable $exception) {
throw UnableToCheckExistence::forLocation($location, $exception);
}
}
public function directoryExists(string $location): bool
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->directoryExists($path);
} catch (Throwable $exception) {
throw UnableToCheckDirectoryExistence::forLocation($location, $exception);
}
}
public function read(string $location): string
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->read($path);
} catch (UnableToReadFile $exception) {
throw UnableToReadFile::fromLocation($location, $exception->reason(), $exception);
}
}
public function readStream(string $location)
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->readStream($path);
} catch (UnableToReadFile $exception) {
throw UnableToReadFile::fromLocation($location, $exception->reason(), $exception);
}
}
public function listContents(string $location, bool $deep = self::LIST_SHALLOW): DirectoryListing
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path, $mountIdentifier] = $this->determineFilesystemAndPath($location);
return
$filesystem
->listContents($path, $deep)
->map(
function (StorageAttributes $attributes) use ($mountIdentifier) {
return $attributes->withPath(sprintf('%s://%s', $mountIdentifier, $attributes->path()));
}
);
}
public function lastModified(string $location): int
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->lastModified($path);
} catch (UnableToRetrieveMetadata $exception) {
throw UnableToRetrieveMetadata::lastModified($location, $exception->reason(), $exception);
}
}
public function fileSize(string $location): int
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->fileSize($path);
} catch (UnableToRetrieveMetadata $exception) {
throw UnableToRetrieveMetadata::fileSize($location, $exception->reason(), $exception);
}
}
public function mimeType(string $location): string
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
return $filesystem->mimeType($path);
} catch (UnableToRetrieveMetadata $exception) {
throw UnableToRetrieveMetadata::mimeType($location, $exception->reason(), $exception);
}
}
public function visibility(string $path): string
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $location] = $this->determineFilesystemAndPath($path);
try {
return $filesystem->visibility($location);
} catch (UnableToRetrieveMetadata $exception) {
throw UnableToRetrieveMetadata::visibility($path, $exception->reason(), $exception);
}
}
public function write(string $location, string $contents, array $config = []): void
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
$filesystem->write($path, $contents, $this->config->extend($config)->toArray());
} catch (UnableToWriteFile $exception) {
throw UnableToWriteFile::atLocation($location, $exception->reason(), $exception);
}
}
public function writeStream(string $location, $contents, array $config = []): void
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
$filesystem->writeStream($path, $contents, $this->config->extend($config)->toArray());
}
public function setVisibility(string $path, string $visibility): void
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($path);
$filesystem->setVisibility($path, $visibility);
}
public function delete(string $location): void
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
$filesystem->delete($path);
} catch (UnableToDeleteFile $exception) {
throw UnableToDeleteFile::atLocation($location, $exception->reason(), $exception);
}
}
public function deleteDirectory(string $location): void
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
$filesystem->deleteDirectory($path);
} catch (UnableToDeleteDirectory $exception) {
throw UnableToDeleteDirectory::atLocation($location, $exception->reason(), $exception);
}
}
public function createDirectory(string $location, array $config = []): void
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($location);
try {
$filesystem->createDirectory($path, $this->config->extend($config)->toArray());
} catch (UnableToCreateDirectory $exception) {
throw UnableToCreateDirectory::dueToFailure($location, $exception);
}
}
public function move(string $source, string $destination, array $config = []): void
{
/** @var FilesystemOperator $sourceFilesystem */
/* @var FilesystemOperator $destinationFilesystem */
[$sourceFilesystem, $sourcePath] = $this->determineFilesystemAndPath($source);
[$destinationFilesystem, $destinationPath] = $this->determineFilesystemAndPath($destination);
$sourceFilesystem === $destinationFilesystem ? $this->moveInTheSameFilesystem(
$sourceFilesystem,
$sourcePath,
$destinationPath,
$source,
$destination,
$config,
) : $this->moveAcrossFilesystems($source, $destination, $config);
}
public function copy(string $source, string $destination, array $config = []): void
{
/** @var FilesystemOperator $sourceFilesystem */
/* @var FilesystemOperator $destinationFilesystem */
[$sourceFilesystem, $sourcePath] = $this->determineFilesystemAndPath($source);
[$destinationFilesystem, $destinationPath] = $this->determineFilesystemAndPath($destination);
$sourceFilesystem === $destinationFilesystem ? $this->copyInSameFilesystem(
$sourceFilesystem,
$sourcePath,
$destinationPath,
$source,
$destination,
$config,
) : $this->copyAcrossFilesystem(
$sourceFilesystem,
$sourcePath,
$destinationFilesystem,
$destinationPath,
$source,
$destination,
$config,
);
}
public function publicUrl(string $path, array $config = []): string
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($path);
if ( ! method_exists($filesystem, 'publicUrl')) {
throw new UnableToGeneratePublicUrl(sprintf('%s does not support generating public urls.', $filesystem::class), $path);
}
return $filesystem->publicUrl($path, $config);
}
public function temporaryUrl(string $path, DateTimeInterface $expiresAt, array $config = []): string
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($path);
if ( ! method_exists($filesystem, 'temporaryUrl')) {
throw new UnableToGenerateTemporaryUrl(sprintf('%s does not support generating public urls.', $filesystem::class), $path);
}
return $filesystem->temporaryUrl($path, $expiresAt, $this->config->extend($config)->toArray());
}
public function checksum(string $path, array $config = []): string
{
/** @var FilesystemOperator $filesystem */
[$filesystem, $path] = $this->determineFilesystemAndPath($path);
if ( ! method_exists($filesystem, 'checksum')) {
throw new UnableToProvideChecksum(sprintf('%s does not support providing checksums.', $filesystem::class), $path);
}
return $filesystem->checksum($path, $this->config->extend($config)->toArray());
}
private function mountFilesystems(array $filesystems): void
{
foreach ($filesystems as $key => $filesystem) {
$this->guardAgainstInvalidMount($key, $filesystem);
/* @var string $key */
/* @var FilesystemOperator $filesystem */
$this->mountFilesystem($key, $filesystem);
}
}
private function guardAgainstInvalidMount(mixed $key, mixed $filesystem): void
{
if ( ! is_string($key)) {
throw UnableToMountFilesystem::becauseTheKeyIsNotValid($key);
}
if ( ! $filesystem instanceof FilesystemOperator) {
throw UnableToMountFilesystem::becauseTheFilesystemWasNotValid($filesystem);
}
}
private function mountFilesystem(string $key, FilesystemOperator $filesystem): void
{
$this->filesystems[$key] = $filesystem;
}
/**
* @param string $path
*
* @return array{0:FilesystemOperator, 1:string, 2:string}
*/
private function determineFilesystemAndPath(string $path): array
{
if (strpos($path, '://') < 1) {
throw UnableToResolveFilesystemMount::becauseTheSeparatorIsMissing($path);
}
/** @var string $mountIdentifier */
/** @var string $mountPath */
[$mountIdentifier, $mountPath] = explode('://', $path, 2);
if ( ! array_key_exists($mountIdentifier, $this->filesystems)) {
throw UnableToResolveFilesystemMount::becauseTheMountWasNotRegistered($mountIdentifier);
}
return [$this->filesystems[$mountIdentifier], $mountPath, $mountIdentifier];
}
private function copyInSameFilesystem(
FilesystemOperator $sourceFilesystem,
string $sourcePath,
string $destinationPath,
string $source,
string $destination,
array $config,
): void {
try {
$sourceFilesystem->copy($sourcePath, $destinationPath, $this->config->extend($config)->toArray());
} catch (UnableToCopyFile $exception) {
throw UnableToCopyFile::fromLocationTo($source, $destination, $exception);
}
}
private function copyAcrossFilesystem(
FilesystemOperator $sourceFilesystem,
string $sourcePath,
FilesystemOperator $destinationFilesystem,
string $destinationPath,
string $source,
string $destination,
array $config,
): void {
$config = $this->config->extend($config);
$retainVisibility = (bool) $config->get(Config::OPTION_RETAIN_VISIBILITY, true);
$visibility = $config->get(Config::OPTION_VISIBILITY);
try {
if ($visibility == null && $retainVisibility) {
$visibility = $sourceFilesystem->visibility($sourcePath);
$config = $config->extend(compact('visibility'));
}
$stream = $sourceFilesystem->readStream($sourcePath);
$destinationFilesystem->writeStream($destinationPath, $stream, $config->toArray());
} catch (UnableToRetrieveMetadata | UnableToReadFile | UnableToWriteFile $exception) {
throw UnableToCopyFile::fromLocationTo($source, $destination, $exception);
}
}
private function moveInTheSameFilesystem(
FilesystemOperator $sourceFilesystem,
string $sourcePath,
string $destinationPath,
string $source,
string $destination,
array $config,
): void {
try {
$sourceFilesystem->move($sourcePath, $destinationPath, $this->config->extend($config)->toArray());
} catch (UnableToMoveFile $exception) {
throw UnableToMoveFile::fromLocationTo($source, $destination, $exception);
}
}
private function moveAcrossFilesystems(string $source, string $destination, array $config = []): void
{
try {
$this->copy($source, $destination, $config);
$this->delete($source);
} catch (UnableToCopyFile | UnableToDeleteFile $exception) {
throw UnableToMoveFile::fromLocationTo($source, $destination, $exception);
}
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
interface PathNormalizer
{
public function normalizePath(string $path): string;
}

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use function rtrim;
use function strlen;
use function substr;
final class PathPrefixer
{
private string $prefix = '';
public function __construct(string $prefix, private string $separator = '/')
{
$this->prefix = rtrim($prefix, '\\/');
if ($this->prefix !== '' || $prefix === $separator) {
$this->prefix .= $separator;
}
}
public function prefixPath(string $path): string
{
return $this->prefix . ltrim($path, '\\/');
}
public function stripPrefix(string $path): string
{
/* @var string */
return substr($path, strlen($this->prefix));
}
public function stripDirectoryPrefix(string $path): string
{
return rtrim($this->stripPrefix($path), '\\/');
}
public function prefixDirectoryPath(string $path): string
{
$prefixedPath = $this->prefixPath(rtrim($path, '\\/'));
if ($prefixedPath === '' || substr($prefixedPath, -1) === $this->separator) {
return $prefixedPath;
}
return $prefixedPath . $this->separator;
}
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
class PathTraversalDetected extends RuntimeException implements FilesystemException
{
private string $path;
public function path(): string
{
return $this->path;
}
public static function forPath(string $path): PathTraversalDetected
{
$e = new PathTraversalDetected("Path traversal detected: {$path}");
$e->path = $path;
return $e;
}
}

View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
final class PortableVisibilityGuard
{
public static function guardAgainstInvalidInput(string $visibility): void
{
if ($visibility !== Visibility::PUBLIC && $visibility !== Visibility::PRIVATE) {
$className = Visibility::class;
throw InvalidVisibilityProvided::withVisibility(
$visibility,
"either {$className}::PUBLIC or {$className}::PRIVATE"
);
}
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
/**
* @internal
*/
trait ProxyArrayAccessToProperties
{
private function formatPropertyName(string $offset): string
{
return str_replace('_', '', lcfirst(ucwords($offset, '_')));
}
/**
* @param mixed $offset
*
* @return bool
*/
public function offsetExists($offset): bool
{
$property = $this->formatPropertyName((string) $offset);
return isset($this->{$property});
}
/**
* @param mixed $offset
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
$property = $this->formatPropertyName((string) $offset);
return $this->{$property};
}
/**
* @param mixed $offset
* @param mixed $value
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value): void
{
throw new RuntimeException('Properties can not be manipulated');
}
/**
* @param mixed $offset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset): void
{
throw new RuntimeException('Properties can not be manipulated');
}
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
class ResolveIdenticalPathConflict
{
public const IGNORE = 'ignore';
public const FAIL = 'fail';
public const TRY = 'try';
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use ArrayAccess;
use JsonSerializable;
interface StorageAttributes extends JsonSerializable, ArrayAccess
{
public const ATTRIBUTE_PATH = 'path';
public const ATTRIBUTE_TYPE = 'type';
public const ATTRIBUTE_FILE_SIZE = 'file_size';
public const ATTRIBUTE_VISIBILITY = 'visibility';
public const ATTRIBUTE_LAST_MODIFIED = 'last_modified';
public const ATTRIBUTE_MIME_TYPE = 'mime_type';
public const ATTRIBUTE_EXTRA_METADATA = 'extra_metadata';
public const TYPE_FILE = 'file';
public const TYPE_DIRECTORY = 'dir';
public function path(): string;
public function type(): string;
public function visibility(): ?string;
public function lastModified(): ?int;
public static function fromArray(array $attributes): StorageAttributes;
public function isFile(): bool;
public function isDir(): bool;
public function withPath(string $path): StorageAttributes;
public function extraMetadata(): array;
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
final class SymbolicLinkEncountered extends RuntimeException implements FilesystemException
{
private string $location;
public function location(): string
{
return $this->location;
}
public static function atLocation(string $pathName): SymbolicLinkEncountered
{
$e = new static("Unsupported symbolic link encountered at location $pathName");
$e->location = $pathName;
return $e;
}
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
class UnableToCheckDirectoryExistence extends UnableToCheckExistence
{
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_DIRECTORY_EXISTS;
}
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
class UnableToCheckExistence extends RuntimeException implements FilesystemOperationFailed
{
final public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
public static function forLocation(string $path, ?Throwable $exception = null): static
{
return new static("Unable to check existence for: {$path}", 0, $exception);
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_EXISTENCE_CHECK;
}
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
class UnableToCheckFileExistence extends UnableToCheckExistence
{
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_FILE_EXISTS;
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToCopyFile extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $source;
/**
* @var string
*/
private $destination;
public function source(): string
{
return $this->source;
}
public function destination(): string
{
return $this->destination;
}
public static function fromLocationTo(
string $sourcePath,
string $destinationPath,
?Throwable $previous = null
): UnableToCopyFile {
$e = new static("Unable to copy file from $sourcePath to $destinationPath", 0 , $previous);
$e->source = $sourcePath;
$e->destination = $destinationPath;
return $e;
}
public static function sourceAndDestinationAreTheSame(string $source, string $destination): UnableToCopyFile
{
return UnableToCopyFile::because('Source and destination are the same', $source, $destination);
}
public static function because(string $reason, string $sourcePath, string $destinationPath): UnableToCopyFile
{
$e = new static("Unable to copy file from $sourcePath to $destinationPath, because $reason");
$e->source = $sourcePath;
$e->destination = $destinationPath;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_COPY;
}
}

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToCreateDirectory extends RuntimeException implements FilesystemOperationFailed
{
private string $location;
private string $reason = '';
public static function atLocation(string $dirname, string $errorMessage = '', ?Throwable $previous = null): UnableToCreateDirectory
{
$message = "Unable to create a directory at {$dirname}. {$errorMessage}";
$e = new static(rtrim($message), 0, $previous);
$e->location = $dirname;
$e->reason = $errorMessage;
return $e;
}
public static function dueToFailure(string $dirname, Throwable $previous): UnableToCreateDirectory
{
$reason = $previous instanceof UnableToCreateDirectory ? $previous->reason() : '';
$message = "Unable to create a directory at $dirname. $reason";
$e = new static(rtrim($message), 0, $previous);
$e->location = $dirname;
$e->reason = $reason ?: $message;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_CREATE_DIRECTORY;
}
public function reason(): string
{
return $this->reason;
}
public function location(): string
{
return $this->location;
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToDeleteDirectory extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $location = '';
/**
* @var string
*/
private $reason;
public static function atLocation(
string $location,
string $reason = '',
?Throwable $previous = null
): UnableToDeleteDirectory {
$e = new static(rtrim("Unable to delete directory located at: {$location}. {$reason}"), 0, $previous);
$e->location = $location;
$e->reason = $reason;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_DELETE_DIRECTORY;
}
public function reason(): string
{
return $this->reason;
}
public function location(): string
{
return $this->location;
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToDeleteFile extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $location = '';
/**
* @var string
*/
private $reason;
public static function atLocation(string $location, string $reason = '', ?Throwable $previous = null): UnableToDeleteFile
{
$e = new static(rtrim("Unable to delete file located at: {$location}. {$reason}"), 0, $previous);
$e->location = $location;
$e->reason = $reason;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_DELETE;
}
public function reason(): string
{
return $this->reason;
}
public function location(): string
{
return $this->location;
}
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToGeneratePublicUrl extends RuntimeException implements FilesystemException
{
public function __construct(string $reason, string $path, ?Throwable $previous = null)
{
parent::__construct("Unable to generate public url for $path: $reason", 0, $previous);
}
public static function dueToError(string $path, Throwable $exception): static
{
return new static($exception->getMessage(), $path, $exception);
}
public static function noGeneratorConfigured(string $path, string $extraReason = ''): static
{
return new static('No generator was configured ' . $extraReason, $path);
}
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToGenerateTemporaryUrl extends RuntimeException implements FilesystemException
{
public function __construct(string $reason, string $path, ?Throwable $previous = null)
{
parent::__construct("Unable to generate temporary url for $path: $reason", 0, $previous);
}
public static function dueToError(string $path, Throwable $exception): static
{
return new static($exception->getMessage(), $path, $exception);
}
public static function noGeneratorConfigured(string $path, string $extraReason = ''): static
{
return new static('No generator was configured ' . $extraReason, $path);
}
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToListContents extends RuntimeException implements FilesystemOperationFailed
{
public static function atLocation(string $location, bool $deep, Throwable $previous): UnableToListContents
{
$message = "Unable to list contents for '$location', " . ($deep ? 'deep' : 'shallow') . " listing\n\n"
. 'Reason: ' . $previous->getMessage();
return new UnableToListContents($message, 0, $previous);
}
public function operation(): string
{
return self::OPERATION_LIST_CONTENTS;
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use LogicException;
class UnableToMountFilesystem extends LogicException implements FilesystemException
{
/**
* @param mixed $key
*/
public static function becauseTheKeyIsNotValid($key): UnableToMountFilesystem
{
return new UnableToMountFilesystem(
'Unable to mount filesystem, key was invalid. String expected, received: ' . gettype($key)
);
}
/**
* @param mixed $filesystem
*/
public static function becauseTheFilesystemWasNotValid($filesystem): UnableToMountFilesystem
{
$received = is_object($filesystem) ? get_class($filesystem) : gettype($filesystem);
return new UnableToMountFilesystem(
'Unable to mount filesystem, filesystem was invalid. Instance of ' . FilesystemOperator::class . ' expected, received: ' . $received
);
}
}

View File

@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToMoveFile extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $source;
/**
* @var string
*/
private $destination;
public static function sourceAndDestinationAreTheSame(string $source, string $destination): UnableToMoveFile
{
return UnableToMoveFile::because('Source and destination are the same', $source, $destination);
}
public function source(): string
{
return $this->source;
}
public function destination(): string
{
return $this->destination;
}
public static function fromLocationTo(
string $sourcePath,
string $destinationPath,
?Throwable $previous = null
): UnableToMoveFile {
$message = $previous?->getMessage() ?? "Unable to move file from $sourcePath to $destinationPath";
$e = new static($message, 0, $previous);
$e->source = $sourcePath;
$e->destination = $destinationPath;
return $e;
}
public static function because(
string $reason,
string $sourcePath,
string $destinationPath,
): UnableToMoveFile {
$message = "Unable to move file from $sourcePath to $destinationPath, because $reason";
$e = new static($message);
$e->source = $sourcePath;
$e->destination = $destinationPath;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_MOVE;
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToProvideChecksum extends RuntimeException implements FilesystemException
{
public function __construct(string $reason, string $path, ?Throwable $previous = null)
{
parent::__construct("Unable to get checksum for $path: $reason", 0, $previous);
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToReadFile extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $location = '';
/**
* @var string
*/
private $reason = '';
public static function fromLocation(string $location, string $reason = '', ?Throwable $previous = null): UnableToReadFile
{
$e = new static(rtrim("Unable to read file from location: {$location}. {$reason}"), 0, $previous);
$e->location = $location;
$e->reason = $reason;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_READ;
}
public function reason(): string
{
return $this->reason;
}
public function location(): string
{
return $this->location;
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
class UnableToResolveFilesystemMount extends RuntimeException implements FilesystemException
{
public static function becauseTheSeparatorIsMissing(string $path): UnableToResolveFilesystemMount
{
return new UnableToResolveFilesystemMount("Unable to resolve the filesystem mount because the path ($path) is missing a separator (://).");
}
public static function becauseTheMountWasNotRegistered(string $mountIdentifier): UnableToResolveFilesystemMount
{
return new UnableToResolveFilesystemMount("Unable to resolve the filesystem mount because the mount ($mountIdentifier) was not registered.");
}
}

View File

@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToRetrieveMetadata extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $location;
/**
* @var string
*/
private $metadataType;
/**
* @var string
*/
private $reason;
public static function lastModified(string $location, string $reason = '', ?Throwable $previous = null): self
{
return static::create($location, FileAttributes::ATTRIBUTE_LAST_MODIFIED, $reason, $previous);
}
public static function visibility(string $location, string $reason = '', ?Throwable $previous = null): self
{
return static::create($location, FileAttributes::ATTRIBUTE_VISIBILITY, $reason, $previous);
}
public static function fileSize(string $location, string $reason = '', ?Throwable $previous = null): self
{
return static::create($location, FileAttributes::ATTRIBUTE_FILE_SIZE, $reason, $previous);
}
public static function mimeType(string $location, string $reason = '', ?Throwable $previous = null): self
{
return static::create($location, FileAttributes::ATTRIBUTE_MIME_TYPE, $reason, $previous);
}
public static function create(string $location, string $type, string $reason = '', ?Throwable $previous = null): self
{
$e = new static("Unable to retrieve the $type for file at location: $location. {$reason}", 0, $previous);
$e->reason = $reason;
$e->location = $location;
$e->metadataType = $type;
return $e;
}
public function reason(): string
{
return $this->reason;
}
public function location(): string
{
return $this->location;
}
public function metadataType(): string
{
return $this->metadataType;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_RETRIEVE_METADATA;
}
}

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
use function rtrim;
final class UnableToSetVisibility extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $location;
/**
* @var string
*/
private $reason;
public function reason(): string
{
return $this->reason;
}
public static function atLocation(string $filename, string $extraMessage = '', ?Throwable $previous = null): self
{
$message = "Unable to set visibility for file {$filename}. $extraMessage";
$e = new static(rtrim($message), 0, $previous);
$e->reason = $extraMessage;
$e->location = $filename;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_SET_VISIBILITY;
}
public function location(): string
{
return $this->location;
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
use Throwable;
final class UnableToWriteFile extends RuntimeException implements FilesystemOperationFailed
{
/**
* @var string
*/
private $location = '';
/**
* @var string
*/
private $reason;
public static function atLocation(string $location, string $reason = '', ?Throwable $previous = null): UnableToWriteFile
{
$e = new static(rtrim("Unable to write file at location: {$location}. {$reason}"), 0, $previous);
$e->location = $location;
$e->reason = $reason;
return $e;
}
public function operation(): string
{
return FilesystemOperationFailed::OPERATION_WRITE;
}
public function reason(): string
{
return $this->reason;
}
public function location(): string
{
return $this->location;
}
}

View File

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace League\Flysystem\UnixVisibility;
use League\Flysystem\PortableVisibilityGuard;
use League\Flysystem\Visibility;
class PortableVisibilityConverter implements VisibilityConverter
{
public function __construct(
private int $filePublic = 0644,
private int $filePrivate = 0600,
private int $directoryPublic = 0755,
private int $directoryPrivate = 0700,
private string $defaultForDirectories = Visibility::PRIVATE
) {
}
public function forFile(string $visibility): int
{
PortableVisibilityGuard::guardAgainstInvalidInput($visibility);
return $visibility === Visibility::PUBLIC
? $this->filePublic
: $this->filePrivate;
}
public function forDirectory(string $visibility): int
{
PortableVisibilityGuard::guardAgainstInvalidInput($visibility);
return $visibility === Visibility::PUBLIC
? $this->directoryPublic
: $this->directoryPrivate;
}
public function inverseForFile(int $visibility): string
{
if ($visibility === $this->filePublic) {
return Visibility::PUBLIC;
} elseif ($visibility === $this->filePrivate) {
return Visibility::PRIVATE;
}
return Visibility::PUBLIC; // default
}
public function inverseForDirectory(int $visibility): string
{
if ($visibility === $this->directoryPublic) {
return Visibility::PUBLIC;
} elseif ($visibility === $this->directoryPrivate) {
return Visibility::PRIVATE;
}
return Visibility::PUBLIC; // default
}
public function defaultForDirectories(): int
{
return $this->defaultForDirectories === Visibility::PUBLIC ? $this->directoryPublic : $this->directoryPrivate;
}
/**
* @param array<mixed> $permissionMap
*/
public static function fromArray(array $permissionMap, string $defaultForDirectories = Visibility::PRIVATE): PortableVisibilityConverter
{
return new PortableVisibilityConverter(
$permissionMap['file']['public'] ?? 0644,
$permissionMap['file']['private'] ?? 0600,
$permissionMap['dir']['public'] ?? 0755,
$permissionMap['dir']['private'] ?? 0700,
$defaultForDirectories
);
}
}

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace League\Flysystem\UnixVisibility;
interface VisibilityConverter
{
public function forFile(string $visibility): int;
public function forDirectory(string $visibility): int;
public function inverseForFile(int $visibility): string;
public function inverseForDirectory(int $visibility): string;
public function defaultForDirectories(): int;
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
use RuntimeException;
final class UnreadableFileEncountered extends RuntimeException implements FilesystemException
{
/**
* @var string
*/
private $location;
public function location(): string
{
return $this->location;
}
public static function atLocation(string $location): UnreadableFileEncountered
{
$e = new static("Unreadable file encountered at location {$location}.");
$e->location = $location;
return $e;
}
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace League\Flysystem\UrlGeneration;
use League\Flysystem\Config;
use League\Flysystem\UnableToGeneratePublicUrl;
final class ChainedPublicUrlGenerator implements PublicUrlGenerator
{
/**
* @param PublicUrlGenerator[] $generators
*/
public function __construct(private iterable $generators)
{
}
public function publicUrl(string $path, Config $config): string
{
foreach ($this->generators as $generator) {
try {
return $generator->publicUrl($path, $config);
} catch (UnableToGeneratePublicUrl) {
}
}
throw new UnableToGeneratePublicUrl('No supported public url generator found.', $path);
}
}

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace League\Flysystem\UrlGeneration;
use League\Flysystem\Config;
use League\Flysystem\PathPrefixer;
class PrefixPublicUrlGenerator implements PublicUrlGenerator
{
private PathPrefixer $prefixer;
public function __construct(string $urlPrefix)
{
$this->prefixer = new PathPrefixer($urlPrefix, '/');
}
public function publicUrl(string $path, Config $config): string
{
return $this->prefixer->prefixPath($path);
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace League\Flysystem\UrlGeneration;
use League\Flysystem\Config;
use League\Flysystem\UnableToGeneratePublicUrl;
interface PublicUrlGenerator
{
/**
* @throws UnableToGeneratePublicUrl
*/
public function publicUrl(string $path, Config $config): string;
}

View File

@ -0,0 +1,39 @@
<?php
namespace League\Flysystem\UrlGeneration;
use InvalidArgumentException;
use League\Flysystem\Config;
use League\Flysystem\PathPrefixer;
use function array_map;
use function count;
use function crc32;
final class ShardedPrefixPublicUrlGenerator implements PublicUrlGenerator
{
/** @var PathPrefixer[] */
private array $prefixes;
private int $count;
/**
* @param string[] $prefixes
*/
public function __construct(array $prefixes)
{
$this->count = count($prefixes);
if ($this->count === 0) {
throw new InvalidArgumentException('At least one prefix is required.');
}
$this->prefixes = array_map(static fn (string $prefix) => new PathPrefixer($prefix, '/'), $prefixes);
}
public function publicUrl(string $path, Config $config): string
{
$index = abs(crc32($path)) % $this->count;
return $this->prefixes[$index]->prefixPath($path);
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace League\Flysystem\UrlGeneration;
use DateTimeInterface;
use League\Flysystem\Config;
use League\Flysystem\UnableToGenerateTemporaryUrl;
interface TemporaryUrlGenerator
{
/**
* @throws UnableToGenerateTemporaryUrl
*/
public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string;
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
final class Visibility
{
public const PUBLIC = 'public';
public const PRIVATE = 'private';
}

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace League\Flysystem;
class WhitespacePathNormalizer implements PathNormalizer
{
public function normalizePath(string $path): string
{
$path = str_replace('\\', '/', $path);
$this->rejectFunkyWhiteSpace($path);
return $this->normalizeRelativePath($path);
}
private function rejectFunkyWhiteSpace(string $path): void
{
if (preg_match('#\p{C}+#u', $path)) {
throw CorruptedPathDetected::forPath($path);
}
}
private function normalizeRelativePath(string $path): string
{
$parts = [];
foreach (explode('/', $path) as $part) {
switch ($part) {
case '':
case '.':
break;
case '..':
if (empty($parts)) {
throw PathTraversalDetected::forPath($path);
}
array_pop($parts);
break;
default:
$parts[] = $part;
break;
}
}
return implode('/', $parts);
}
}