973 lines
25 KiB
PHP
973 lines
25 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Illuminate\Filesystem;
|
||
|
|
||
|
use Closure;
|
||
|
use Illuminate\Contracts\Filesystem\Cloud as CloudFilesystemContract;
|
||
|
use Illuminate\Contracts\Filesystem\Filesystem as FilesystemContract;
|
||
|
use Illuminate\Http\File;
|
||
|
use Illuminate\Http\UploadedFile;
|
||
|
use Illuminate\Support\Arr;
|
||
|
use Illuminate\Support\Str;
|
||
|
use Illuminate\Support\Traits\Conditionable;
|
||
|
use Illuminate\Support\Traits\Macroable;
|
||
|
use InvalidArgumentException;
|
||
|
use League\Flysystem\FilesystemAdapter as FlysystemAdapter;
|
||
|
use League\Flysystem\FilesystemOperator;
|
||
|
use League\Flysystem\Ftp\FtpAdapter;
|
||
|
use League\Flysystem\Local\LocalFilesystemAdapter as LocalAdapter;
|
||
|
use League\Flysystem\PathPrefixer;
|
||
|
use League\Flysystem\PhpseclibV3\SftpAdapter;
|
||
|
use League\Flysystem\StorageAttributes;
|
||
|
use League\Flysystem\UnableToCopyFile;
|
||
|
use League\Flysystem\UnableToCreateDirectory;
|
||
|
use League\Flysystem\UnableToDeleteDirectory;
|
||
|
use League\Flysystem\UnableToDeleteFile;
|
||
|
use League\Flysystem\UnableToMoveFile;
|
||
|
use League\Flysystem\UnableToProvideChecksum;
|
||
|
use League\Flysystem\UnableToReadFile;
|
||
|
use League\Flysystem\UnableToRetrieveMetadata;
|
||
|
use League\Flysystem\UnableToSetVisibility;
|
||
|
use League\Flysystem\UnableToWriteFile;
|
||
|
use League\Flysystem\Visibility;
|
||
|
use PHPUnit\Framework\Assert as PHPUnit;
|
||
|
use Psr\Http\Message\StreamInterface;
|
||
|
use RuntimeException;
|
||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||
|
|
||
|
/**
|
||
|
* @mixin \League\Flysystem\FilesystemOperator
|
||
|
*/
|
||
|
class FilesystemAdapter implements CloudFilesystemContract
|
||
|
{
|
||
|
use Conditionable;
|
||
|
use Macroable {
|
||
|
__call as macroCall;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The Flysystem filesystem implementation.
|
||
|
*
|
||
|
* @var \League\Flysystem\FilesystemOperator
|
||
|
*/
|
||
|
protected $driver;
|
||
|
|
||
|
/**
|
||
|
* The Flysystem adapter implementation.
|
||
|
*
|
||
|
* @var \League\Flysystem\FilesystemAdapter
|
||
|
*/
|
||
|
protected $adapter;
|
||
|
|
||
|
/**
|
||
|
* The filesystem configuration.
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $config;
|
||
|
|
||
|
/**
|
||
|
* The Flysystem PathPrefixer instance.
|
||
|
*
|
||
|
* @var \League\Flysystem\PathPrefixer
|
||
|
*/
|
||
|
protected $prefixer;
|
||
|
|
||
|
/**
|
||
|
* The temporary URL builder callback.
|
||
|
*
|
||
|
* @var \Closure|null
|
||
|
*/
|
||
|
protected $temporaryUrlCallback;
|
||
|
|
||
|
/**
|
||
|
* Create a new filesystem adapter instance.
|
||
|
*
|
||
|
* @param \League\Flysystem\FilesystemOperator $driver
|
||
|
* @param \League\Flysystem\FilesystemAdapter $adapter
|
||
|
* @param array $config
|
||
|
* @return void
|
||
|
*/
|
||
|
public function __construct(FilesystemOperator $driver, FlysystemAdapter $adapter, array $config = [])
|
||
|
{
|
||
|
$this->driver = $driver;
|
||
|
$this->adapter = $adapter;
|
||
|
$this->config = $config;
|
||
|
$separator = $config['directory_separator'] ?? DIRECTORY_SEPARATOR;
|
||
|
|
||
|
$this->prefixer = new PathPrefixer($config['root'] ?? '', $separator);
|
||
|
|
||
|
if (isset($config['prefix'])) {
|
||
|
$this->prefixer = new PathPrefixer($this->prefixer->prefixPath($config['prefix']), $separator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Assert that the given file or directory exists.
|
||
|
*
|
||
|
* @param string|array $path
|
||
|
* @param string|null $content
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function assertExists($path, $content = null)
|
||
|
{
|
||
|
clearstatcache();
|
||
|
|
||
|
$paths = Arr::wrap($path);
|
||
|
|
||
|
foreach ($paths as $path) {
|
||
|
PHPUnit::assertTrue(
|
||
|
$this->exists($path), "Unable to find a file or directory at path [{$path}]."
|
||
|
);
|
||
|
|
||
|
if (! is_null($content)) {
|
||
|
$actual = $this->get($path);
|
||
|
|
||
|
PHPUnit::assertSame(
|
||
|
$content,
|
||
|
$actual,
|
||
|
"File or directory [{$path}] was found, but content [{$actual}] does not match [{$content}]."
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Assert that the given file or directory does not exist.
|
||
|
*
|
||
|
* @param string|array $path
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function assertMissing($path)
|
||
|
{
|
||
|
clearstatcache();
|
||
|
|
||
|
$paths = Arr::wrap($path);
|
||
|
|
||
|
foreach ($paths as $path) {
|
||
|
PHPUnit::assertFalse(
|
||
|
$this->exists($path), "Found unexpected file or directory at path [{$path}]."
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Assert that the given directory is empty.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function assertDirectoryEmpty($path)
|
||
|
{
|
||
|
PHPUnit::assertEmpty(
|
||
|
$this->allFiles($path), "Directory [{$path}] is not empty."
|
||
|
);
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if a file or directory exists.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function exists($path)
|
||
|
{
|
||
|
return $this->driver->has($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if a file or directory is missing.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function missing($path)
|
||
|
{
|
||
|
return ! $this->exists($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if a file exists.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function fileExists($path)
|
||
|
{
|
||
|
return $this->driver->fileExists($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if a file is missing.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function fileMissing($path)
|
||
|
{
|
||
|
return ! $this->fileExists($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if a directory exists.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function directoryExists($path)
|
||
|
{
|
||
|
return $this->driver->directoryExists($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if a directory is missing.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function directoryMissing($path)
|
||
|
{
|
||
|
return ! $this->directoryExists($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the full path for the file at the given "short" path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string
|
||
|
*/
|
||
|
public function path($path)
|
||
|
{
|
||
|
return $this->prefixer->prefixPath($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the contents of a file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string|null
|
||
|
*/
|
||
|
public function get($path)
|
||
|
{
|
||
|
try {
|
||
|
return $this->driver->read($path);
|
||
|
} catch (UnableToReadFile $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a streamed response for a given file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param string|null $name
|
||
|
* @param array $headers
|
||
|
* @param string|null $disposition
|
||
|
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
||
|
*/
|
||
|
public function response($path, $name = null, array $headers = [], $disposition = 'inline')
|
||
|
{
|
||
|
$response = new StreamedResponse;
|
||
|
|
||
|
if (! array_key_exists('Content-Type', $headers)) {
|
||
|
$headers['Content-Type'] = $this->mimeType($path);
|
||
|
}
|
||
|
|
||
|
if (! array_key_exists('Content-Length', $headers)) {
|
||
|
$headers['Content-Length'] = $this->size($path);
|
||
|
}
|
||
|
|
||
|
if (! array_key_exists('Content-Disposition', $headers)) {
|
||
|
$filename = $name ?? basename($path);
|
||
|
|
||
|
$disposition = $response->headers->makeDisposition(
|
||
|
$disposition, $filename, $this->fallbackName($filename)
|
||
|
);
|
||
|
|
||
|
$headers['Content-Disposition'] = $disposition;
|
||
|
}
|
||
|
|
||
|
$response->headers->replace($headers);
|
||
|
|
||
|
$response->setCallback(function () use ($path) {
|
||
|
$stream = $this->readStream($path);
|
||
|
fpassthru($stream);
|
||
|
fclose($stream);
|
||
|
});
|
||
|
|
||
|
return $response;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a streamed download response for a given file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param string|null $name
|
||
|
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
||
|
*/
|
||
|
public function download($path, $name = null, array $headers = [])
|
||
|
{
|
||
|
return $this->response($path, $name, $headers, 'attachment');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Convert the string to ASCII characters that are equivalent to the given name.
|
||
|
*
|
||
|
* @param string $name
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function fallbackName($name)
|
||
|
{
|
||
|
return str_replace('%', '', Str::ascii($name));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write the contents of a file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param \Psr\Http\Message\StreamInterface|\Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|resource $contents
|
||
|
* @param mixed $options
|
||
|
* @return string|bool
|
||
|
*/
|
||
|
public function put($path, $contents, $options = [])
|
||
|
{
|
||
|
$options = is_string($options)
|
||
|
? ['visibility' => $options]
|
||
|
: (array) $options;
|
||
|
|
||
|
// If the given contents is actually a file or uploaded file instance than we will
|
||
|
// automatically store the file using a stream. This provides a convenient path
|
||
|
// for the developer to store streams without managing them manually in code.
|
||
|
if ($contents instanceof File ||
|
||
|
$contents instanceof UploadedFile) {
|
||
|
return $this->putFile($path, $contents, $options);
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
if ($contents instanceof StreamInterface) {
|
||
|
$this->driver->writeStream($path, $contents->detach(), $options);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
is_resource($contents)
|
||
|
? $this->driver->writeStream($path, $contents, $options)
|
||
|
: $this->driver->write($path, $contents, $options);
|
||
|
} catch (UnableToWriteFile|UnableToSetVisibility $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Store the uploaded file on the disk.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $file
|
||
|
* @param mixed $options
|
||
|
* @return string|false
|
||
|
*/
|
||
|
public function putFile($path, $file, $options = [])
|
||
|
{
|
||
|
$file = is_string($file) ? new File($file) : $file;
|
||
|
|
||
|
return $this->putFileAs($path, $file, $file->hashName(), $options);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Store the uploaded file on the disk with a given name.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $file
|
||
|
* @param string $name
|
||
|
* @param mixed $options
|
||
|
* @return string|false
|
||
|
*/
|
||
|
public function putFileAs($path, $file, $name, $options = [])
|
||
|
{
|
||
|
$stream = fopen(is_string($file) ? $file : $file->getRealPath(), 'r');
|
||
|
|
||
|
// Next, we will format the path of the file and store the file using a stream since
|
||
|
// they provide better performance than alternatives. Once we write the file this
|
||
|
// stream will get closed automatically by us so the developer doesn't have to.
|
||
|
$result = $this->put(
|
||
|
$path = trim($path.'/'.$name, '/'), $stream, $options
|
||
|
);
|
||
|
|
||
|
if (is_resource($stream)) {
|
||
|
fclose($stream);
|
||
|
}
|
||
|
|
||
|
return $result ? $path : false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the visibility for the given path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getVisibility($path)
|
||
|
{
|
||
|
if ($this->driver->visibility($path) == Visibility::PUBLIC) {
|
||
|
return FilesystemContract::VISIBILITY_PUBLIC;
|
||
|
}
|
||
|
|
||
|
return FilesystemContract::VISIBILITY_PRIVATE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the visibility for the given path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param string $visibility
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function setVisibility($path, $visibility)
|
||
|
{
|
||
|
try {
|
||
|
$this->driver->setVisibility($path, $this->parseVisibility($visibility));
|
||
|
} catch (UnableToSetVisibility $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Prepend to a file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param string $data
|
||
|
* @param string $separator
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function prepend($path, $data, $separator = PHP_EOL)
|
||
|
{
|
||
|
if ($this->fileExists($path)) {
|
||
|
return $this->put($path, $data.$separator.$this->get($path));
|
||
|
}
|
||
|
|
||
|
return $this->put($path, $data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Append to a file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param string $data
|
||
|
* @param string $separator
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function append($path, $data, $separator = PHP_EOL)
|
||
|
{
|
||
|
if ($this->fileExists($path)) {
|
||
|
return $this->put($path, $this->get($path).$separator.$data);
|
||
|
}
|
||
|
|
||
|
return $this->put($path, $data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Delete the file at a given path.
|
||
|
*
|
||
|
* @param string|array $paths
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function delete($paths)
|
||
|
{
|
||
|
$paths = is_array($paths) ? $paths : func_get_args();
|
||
|
|
||
|
$success = true;
|
||
|
|
||
|
foreach ($paths as $path) {
|
||
|
try {
|
||
|
$this->driver->delete($path);
|
||
|
} catch (UnableToDeleteFile $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
$success = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $success;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Copy a file to a new location.
|
||
|
*
|
||
|
* @param string $from
|
||
|
* @param string $to
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function copy($from, $to)
|
||
|
{
|
||
|
try {
|
||
|
$this->driver->copy($from, $to);
|
||
|
} catch (UnableToCopyFile $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Move a file to a new location.
|
||
|
*
|
||
|
* @param string $from
|
||
|
* @param string $to
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function move($from, $to)
|
||
|
{
|
||
|
try {
|
||
|
$this->driver->move($from, $to);
|
||
|
} catch (UnableToMoveFile $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the file size of a given file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return int
|
||
|
*/
|
||
|
public function size($path)
|
||
|
{
|
||
|
return $this->driver->fileSize($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the checksum for a file.
|
||
|
*
|
||
|
* @return string|false
|
||
|
*
|
||
|
* @throws UnableToProvideChecksum
|
||
|
*/
|
||
|
public function checksum(string $path, array $options = [])
|
||
|
{
|
||
|
try {
|
||
|
return $this->driver->checksum($path, $options);
|
||
|
} catch (UnableToProvideChecksum $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the mime-type of a given file.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string|false
|
||
|
*/
|
||
|
public function mimeType($path)
|
||
|
{
|
||
|
try {
|
||
|
return $this->driver->mimeType($path);
|
||
|
} catch (UnableToRetrieveMetadata $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the file's last modification time.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return int
|
||
|
*/
|
||
|
public function lastModified($path)
|
||
|
{
|
||
|
return $this->driver->lastModified($path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
public function readStream($path)
|
||
|
{
|
||
|
try {
|
||
|
return $this->driver->readStream($path);
|
||
|
} catch (UnableToReadFile $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritdoc}
|
||
|
*/
|
||
|
public function writeStream($path, $resource, array $options = [])
|
||
|
{
|
||
|
try {
|
||
|
$this->driver->writeStream($path, $resource, $options);
|
||
|
} catch (UnableToWriteFile|UnableToSetVisibility $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the URL for the file at the given path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string
|
||
|
*
|
||
|
* @throws \RuntimeException
|
||
|
*/
|
||
|
public function url($path)
|
||
|
{
|
||
|
if (isset($this->config['prefix'])) {
|
||
|
$path = $this->concatPathToUrl($this->config['prefix'], $path);
|
||
|
}
|
||
|
|
||
|
$adapter = $this->adapter;
|
||
|
|
||
|
if (method_exists($adapter, 'getUrl')) {
|
||
|
return $adapter->getUrl($path);
|
||
|
} elseif (method_exists($this->driver, 'getUrl')) {
|
||
|
return $this->driver->getUrl($path);
|
||
|
} elseif ($adapter instanceof FtpAdapter || $adapter instanceof SftpAdapter) {
|
||
|
return $this->getFtpUrl($path);
|
||
|
} elseif ($adapter instanceof LocalAdapter) {
|
||
|
return $this->getLocalUrl($path);
|
||
|
} else {
|
||
|
throw new RuntimeException('This driver does not support retrieving URLs.');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the URL for the file at the given path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function getFtpUrl($path)
|
||
|
{
|
||
|
return isset($this->config['url'])
|
||
|
? $this->concatPathToUrl($this->config['url'], $path)
|
||
|
: $path;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the URL for the file at the given path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function getLocalUrl($path)
|
||
|
{
|
||
|
// If an explicit base URL has been set on the disk configuration then we will use
|
||
|
// it as the base URL instead of the default path. This allows the developer to
|
||
|
// have full control over the base path for this filesystem's generated URLs.
|
||
|
if (isset($this->config['url'])) {
|
||
|
return $this->concatPathToUrl($this->config['url'], $path);
|
||
|
}
|
||
|
|
||
|
$path = '/storage/'.$path;
|
||
|
|
||
|
// If the path contains "storage/public", it probably means the developer is using
|
||
|
// the default disk to generate the path instead of the "public" disk like they
|
||
|
// are really supposed to use. We will remove the public from this path here.
|
||
|
if (str_contains($path, '/storage/public/')) {
|
||
|
return Str::replaceFirst('/public/', '/', $path);
|
||
|
}
|
||
|
|
||
|
return $path;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if temporary URLs can be generated.
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function providesTemporaryUrls()
|
||
|
{
|
||
|
return method_exists($this->adapter, 'getTemporaryUrl') || isset($this->temporaryUrlCallback);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a temporary URL for the file at the given path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param \DateTimeInterface $expiration
|
||
|
* @param array $options
|
||
|
* @return string
|
||
|
*
|
||
|
* @throws \RuntimeException
|
||
|
*/
|
||
|
public function temporaryUrl($path, $expiration, array $options = [])
|
||
|
{
|
||
|
if (method_exists($this->adapter, 'getTemporaryUrl')) {
|
||
|
return $this->adapter->getTemporaryUrl($path, $expiration, $options);
|
||
|
}
|
||
|
|
||
|
if ($this->temporaryUrlCallback) {
|
||
|
return $this->temporaryUrlCallback->bindTo($this, static::class)(
|
||
|
$path, $expiration, $options
|
||
|
);
|
||
|
}
|
||
|
|
||
|
throw new RuntimeException('This driver does not support creating temporary URLs.');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a temporary upload URL for the file at the given path.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @param \DateTimeInterface $expiration
|
||
|
* @param array $options
|
||
|
* @return array
|
||
|
*
|
||
|
* @throws \RuntimeException
|
||
|
*/
|
||
|
public function temporaryUploadUrl($path, $expiration, array $options = [])
|
||
|
{
|
||
|
if (method_exists($this->adapter, 'temporaryUploadUrl')) {
|
||
|
return $this->adapter->temporaryUploadUrl($path, $expiration, $options);
|
||
|
}
|
||
|
|
||
|
throw new RuntimeException('This driver does not support creating temporary upload URLs.');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Concatenate a path to a URL.
|
||
|
*
|
||
|
* @param string $url
|
||
|
* @param string $path
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function concatPathToUrl($url, $path)
|
||
|
{
|
||
|
return rtrim($url, '/').'/'.ltrim($path, '/');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Replace the scheme, host and port of the given UriInterface with values from the given URL.
|
||
|
*
|
||
|
* @param \Psr\Http\Message\UriInterface $uri
|
||
|
* @param string $url
|
||
|
* @return \Psr\Http\Message\UriInterface
|
||
|
*/
|
||
|
protected function replaceBaseUrl($uri, $url)
|
||
|
{
|
||
|
$parsed = parse_url($url);
|
||
|
|
||
|
return $uri
|
||
|
->withScheme($parsed['scheme'])
|
||
|
->withHost($parsed['host'])
|
||
|
->withPort($parsed['port'] ?? null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get an array of all files in a directory.
|
||
|
*
|
||
|
* @param string|null $directory
|
||
|
* @param bool $recursive
|
||
|
* @return array
|
||
|
*/
|
||
|
public function files($directory = null, $recursive = false)
|
||
|
{
|
||
|
return $this->driver->listContents($directory ?? '', $recursive)
|
||
|
->filter(function (StorageAttributes $attributes) {
|
||
|
return $attributes->isFile();
|
||
|
})
|
||
|
->sortByPath()
|
||
|
->map(function (StorageAttributes $attributes) {
|
||
|
return $attributes->path();
|
||
|
})
|
||
|
->toArray();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all of the files from the given directory (recursive).
|
||
|
*
|
||
|
* @param string|null $directory
|
||
|
* @return array
|
||
|
*/
|
||
|
public function allFiles($directory = null)
|
||
|
{
|
||
|
return $this->files($directory, true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all of the directories within a given directory.
|
||
|
*
|
||
|
* @param string|null $directory
|
||
|
* @param bool $recursive
|
||
|
* @return array
|
||
|
*/
|
||
|
public function directories($directory = null, $recursive = false)
|
||
|
{
|
||
|
return $this->driver->listContents($directory ?? '', $recursive)
|
||
|
->filter(function (StorageAttributes $attributes) {
|
||
|
return $attributes->isDir();
|
||
|
})
|
||
|
->map(function (StorageAttributes $attributes) {
|
||
|
return $attributes->path();
|
||
|
})
|
||
|
->toArray();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all the directories within a given directory (recursive).
|
||
|
*
|
||
|
* @param string|null $directory
|
||
|
* @return array
|
||
|
*/
|
||
|
public function allDirectories($directory = null)
|
||
|
{
|
||
|
return $this->directories($directory, true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a directory.
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function makeDirectory($path)
|
||
|
{
|
||
|
try {
|
||
|
$this->driver->createDirectory($path);
|
||
|
} catch (UnableToCreateDirectory|UnableToSetVisibility $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Recursively delete a directory.
|
||
|
*
|
||
|
* @param string $directory
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function deleteDirectory($directory)
|
||
|
{
|
||
|
try {
|
||
|
$this->driver->deleteDirectory($directory);
|
||
|
} catch (UnableToDeleteDirectory $e) {
|
||
|
throw_if($this->throwsExceptions(), $e);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the Flysystem driver.
|
||
|
*
|
||
|
* @return \League\Flysystem\FilesystemOperator
|
||
|
*/
|
||
|
public function getDriver()
|
||
|
{
|
||
|
return $this->driver;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the Flysystem adapter.
|
||
|
*
|
||
|
* @return \League\Flysystem\FilesystemAdapter
|
||
|
*/
|
||
|
public function getAdapter()
|
||
|
{
|
||
|
return $this->adapter;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the configuration values.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getConfig()
|
||
|
{
|
||
|
return $this->config;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parse the given visibility value.
|
||
|
*
|
||
|
* @param string|null $visibility
|
||
|
* @return string|null
|
||
|
*
|
||
|
* @throws \InvalidArgumentException
|
||
|
*/
|
||
|
protected function parseVisibility($visibility)
|
||
|
{
|
||
|
if (is_null($visibility)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
return match ($visibility) {
|
||
|
FilesystemContract::VISIBILITY_PUBLIC => Visibility::PUBLIC,
|
||
|
FilesystemContract::VISIBILITY_PRIVATE => Visibility::PRIVATE,
|
||
|
default => throw new InvalidArgumentException("Unknown visibility: {$visibility}."),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Define a custom temporary URL builder callback.
|
||
|
*
|
||
|
* @param \Closure $callback
|
||
|
* @return void
|
||
|
*/
|
||
|
public function buildTemporaryUrlsUsing(Closure $callback)
|
||
|
{
|
||
|
$this->temporaryUrlCallback = $callback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if Flysystem exceptions should be thrown.
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
protected function throwsExceptions(): bool
|
||
|
{
|
||
|
return (bool) ($this->config['throw'] ?? false);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Pass dynamic methods call onto Flysystem.
|
||
|
*
|
||
|
* @param string $method
|
||
|
* @param array $parameters
|
||
|
* @return mixed
|
||
|
*
|
||
|
* @throws \BadMethodCallException
|
||
|
*/
|
||
|
public function __call($method, array $parameters)
|
||
|
{
|
||
|
if (static::hasMacro($method)) {
|
||
|
return $this->macroCall($method, $parameters);
|
||
|
}
|
||
|
|
||
|
return $this->driver->{$method}(...$parameters);
|
||
|
}
|
||
|
}
|