Subiendo proyecto completo sin restricciones de git ignore
This commit is contained in:
508
vendor/league/flysystem-aws-s3-v3/AwsS3V3Adapter.php
vendored
Normal file
508
vendor/league/flysystem-aws-s3-v3/AwsS3V3Adapter.php
vendored
Normal file
@@ -0,0 +1,508 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Flysystem\AwsS3V3;
|
||||
|
||||
use Aws\Api\DateTimeResult;
|
||||
use Aws\S3\S3ClientInterface;
|
||||
use DateTimeInterface;
|
||||
use Generator;
|
||||
use League\Flysystem\ChecksumAlgoIsNotSupported;
|
||||
use League\Flysystem\ChecksumProvider;
|
||||
use League\Flysystem\Config;
|
||||
use League\Flysystem\DirectoryAttributes;
|
||||
use League\Flysystem\FileAttributes;
|
||||
use League\Flysystem\FilesystemAdapter;
|
||||
use League\Flysystem\FilesystemOperationFailed;
|
||||
use League\Flysystem\PathPrefixer;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use League\Flysystem\UnableToCheckDirectoryExistence;
|
||||
use League\Flysystem\UnableToCheckFileExistence;
|
||||
use League\Flysystem\UnableToCopyFile;
|
||||
use League\Flysystem\UnableToDeleteDirectory;
|
||||
use League\Flysystem\UnableToDeleteFile;
|
||||
use League\Flysystem\UnableToGeneratePublicUrl;
|
||||
use League\Flysystem\UnableToGenerateTemporaryUrl;
|
||||
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\UrlGeneration\PublicUrlGenerator;
|
||||
use League\Flysystem\UrlGeneration\TemporaryUrlGenerator;
|
||||
use League\Flysystem\Visibility;
|
||||
use League\MimeTypeDetection\FinfoMimeTypeDetector;
|
||||
use League\MimeTypeDetection\MimeTypeDetector;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Throwable;
|
||||
use function trim;
|
||||
|
||||
class AwsS3V3Adapter implements FilesystemAdapter, PublicUrlGenerator, ChecksumProvider, TemporaryUrlGenerator
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public const AVAILABLE_OPTIONS = [
|
||||
'ACL',
|
||||
'CacheControl',
|
||||
'ContentDisposition',
|
||||
'ContentEncoding',
|
||||
'ContentLength',
|
||||
'ContentType',
|
||||
'ContentMD5',
|
||||
'Expires',
|
||||
'GrantFullControl',
|
||||
'GrantRead',
|
||||
'GrantReadACP',
|
||||
'GrantWriteACP',
|
||||
'Metadata',
|
||||
'MetadataDirective',
|
||||
'RequestPayer',
|
||||
'SSECustomerAlgorithm',
|
||||
'SSECustomerKey',
|
||||
'SSECustomerKeyMD5',
|
||||
'SSEKMSKeyId',
|
||||
'ServerSideEncryption',
|
||||
'StorageClass',
|
||||
'Tagging',
|
||||
'WebsiteRedirectLocation',
|
||||
'ChecksumAlgorithm',
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public const MUP_AVAILABLE_OPTIONS = [
|
||||
'before_upload',
|
||||
'concurrency',
|
||||
'mup_threshold',
|
||||
'params',
|
||||
'part_size',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private const EXTRA_METADATA_FIELDS = [
|
||||
'Metadata',
|
||||
'StorageClass',
|
||||
'ETag',
|
||||
'VersionId',
|
||||
];
|
||||
|
||||
private PathPrefixer $prefixer;
|
||||
private VisibilityConverter $visibility;
|
||||
private MimeTypeDetector $mimeTypeDetector;
|
||||
|
||||
public function __construct(
|
||||
private S3ClientInterface $client,
|
||||
private string $bucket,
|
||||
string $prefix = '',
|
||||
VisibilityConverter $visibility = null,
|
||||
MimeTypeDetector $mimeTypeDetector = null,
|
||||
private array $options = [],
|
||||
private bool $streamReads = true,
|
||||
private array $forwardedOptions = self::AVAILABLE_OPTIONS,
|
||||
private array $metadataFields = self::EXTRA_METADATA_FIELDS,
|
||||
private array $multipartUploadOptions = self::MUP_AVAILABLE_OPTIONS,
|
||||
) {
|
||||
$this->prefixer = new PathPrefixer($prefix);
|
||||
$this->visibility = $visibility ?: new PortableVisibilityConverter();
|
||||
$this->mimeTypeDetector = $mimeTypeDetector ?: new FinfoMimeTypeDetector();
|
||||
}
|
||||
|
||||
public function fileExists(string $path): bool
|
||||
{
|
||||
try {
|
||||
return $this->client->doesObjectExistV2($this->bucket, $this->prefixer->prefixPath($path), false, $this->options);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToCheckFileExistence::forLocation($path, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function directoryExists(string $path): bool
|
||||
{
|
||||
try {
|
||||
$prefix = $this->prefixer->prefixDirectoryPath($path);
|
||||
$options = ['Bucket' => $this->bucket, 'Prefix' => $prefix, 'MaxKeys' => 1, 'Delimiter' => '/'];
|
||||
$command = $this->client->getCommand('ListObjectsV2', $options);
|
||||
$result = $this->client->execute($command);
|
||||
|
||||
return $result->hasKey('Contents') || $result->hasKey('CommonPrefixes');
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToCheckDirectoryExistence::forLocation($path, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function write(string $path, string $contents, Config $config): void
|
||||
{
|
||||
$this->upload($path, $contents, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string|resource $body
|
||||
* @param Config $config
|
||||
*/
|
||||
private function upload(string $path, $body, Config $config): void
|
||||
{
|
||||
$key = $this->prefixer->prefixPath($path);
|
||||
$options = $this->createOptionsFromConfig($config);
|
||||
$acl = $options['params']['ACL'] ?? $this->determineAcl($config);
|
||||
$shouldDetermineMimetype = ! array_key_exists('ContentType', $options['params']);
|
||||
|
||||
if ($shouldDetermineMimetype && $mimeType = $this->mimeTypeDetector->detectMimeType($key, $body)) {
|
||||
$options['params']['ContentType'] = $mimeType;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->client->upload($this->bucket, $key, $body, $acl, $options);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToWriteFile::atLocation($path, $exception->getMessage(), $exception);
|
||||
}
|
||||
}
|
||||
|
||||
private function determineAcl(Config $config): string
|
||||
{
|
||||
$visibility = (string) $config->get(Config::OPTION_VISIBILITY, Visibility::PRIVATE);
|
||||
|
||||
return $this->visibility->visibilityToAcl($visibility);
|
||||
}
|
||||
|
||||
private function createOptionsFromConfig(Config $config): array
|
||||
{
|
||||
$config = $config->withDefaults($this->options);
|
||||
$options = ['params' => []];
|
||||
|
||||
if ($mimetype = $config->get('mimetype')) {
|
||||
$options['params']['ContentType'] = $mimetype;
|
||||
}
|
||||
|
||||
foreach ($this->forwardedOptions as $option) {
|
||||
$value = $config->get($option, '__NOT_SET__');
|
||||
|
||||
if ($value !== '__NOT_SET__') {
|
||||
$options['params'][$option] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->multipartUploadOptions as $option) {
|
||||
$value = $config->get($option, '__NOT_SET__');
|
||||
|
||||
if ($value !== '__NOT_SET__') {
|
||||
$options[$option] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function writeStream(string $path, $contents, Config $config): void
|
||||
{
|
||||
$this->upload($path, $contents, $config);
|
||||
}
|
||||
|
||||
public function read(string $path): string
|
||||
{
|
||||
$body = $this->readObject($path, false);
|
||||
|
||||
return (string) $body->getContents();
|
||||
}
|
||||
|
||||
public function readStream(string $path)
|
||||
{
|
||||
/** @var resource $resource */
|
||||
$resource = $this->readObject($path, true)->detach();
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
public function delete(string $path): void
|
||||
{
|
||||
$arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
|
||||
$command = $this->client->getCommand('DeleteObject', $arguments);
|
||||
|
||||
try {
|
||||
$this->client->execute($command);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToDeleteFile::atLocation($path, '', $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteDirectory(string $path): void
|
||||
{
|
||||
$prefix = $this->prefixer->prefixPath($path);
|
||||
$prefix = ltrim(rtrim($prefix, '/') . '/', '/');
|
||||
|
||||
try {
|
||||
$this->client->deleteMatchingObjects($this->bucket, $prefix);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToDeleteDirectory::atLocation($path, '', $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function createDirectory(string $path, Config $config): void
|
||||
{
|
||||
$defaultVisibility = $config->get('directory_visibility', $this->visibility->defaultForDirectories());
|
||||
$config = $config->withDefaults(['visibility' => $defaultVisibility]);
|
||||
$this->upload(rtrim($path, '/') . '/', '', $config);
|
||||
}
|
||||
|
||||
public function setVisibility(string $path, string $visibility): void
|
||||
{
|
||||
$arguments = [
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->prefixer->prefixPath($path),
|
||||
'ACL' => $this->visibility->visibilityToAcl($visibility),
|
||||
];
|
||||
$command = $this->client->getCommand('PutObjectAcl', $arguments);
|
||||
|
||||
try {
|
||||
$this->client->execute($command);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToSetVisibility::atLocation($path, '', $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function visibility(string $path): FileAttributes
|
||||
{
|
||||
$arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
|
||||
$command = $this->client->getCommand('GetObjectAcl', $arguments);
|
||||
|
||||
try {
|
||||
$result = $this->client->execute($command);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToRetrieveMetadata::visibility($path, '', $exception);
|
||||
}
|
||||
|
||||
$visibility = $this->visibility->aclToVisibility((array) $result->get('Grants'));
|
||||
|
||||
return new FileAttributes($path, null, $visibility);
|
||||
}
|
||||
|
||||
private function fetchFileMetadata(string $path, string $type): FileAttributes
|
||||
{
|
||||
$arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
|
||||
$command = $this->client->getCommand('HeadObject', $arguments);
|
||||
|
||||
try {
|
||||
$result = $this->client->execute($command);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToRetrieveMetadata::create($path, $type, '', $exception);
|
||||
}
|
||||
|
||||
$attributes = $this->mapS3ObjectMetadata($result->toArray(), $path);
|
||||
|
||||
if ( ! $attributes instanceof FileAttributes) {
|
||||
throw UnableToRetrieveMetadata::create($path, $type, '');
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
private function mapS3ObjectMetadata(array $metadata, string $path): StorageAttributes
|
||||
{
|
||||
if (substr($path, -1) === '/') {
|
||||
return new DirectoryAttributes(rtrim($path, '/'));
|
||||
}
|
||||
|
||||
$mimetype = $metadata['ContentType'] ?? null;
|
||||
$fileSize = $metadata['ContentLength'] ?? $metadata['Size'] ?? null;
|
||||
$fileSize = $fileSize === null ? null : (int) $fileSize;
|
||||
$dateTime = $metadata['LastModified'] ?? null;
|
||||
$lastModified = $dateTime instanceof DateTimeResult ? $dateTime->getTimeStamp() : null;
|
||||
|
||||
return new FileAttributes(
|
||||
$path,
|
||||
$fileSize,
|
||||
null,
|
||||
$lastModified,
|
||||
$mimetype,
|
||||
$this->extractExtraMetadata($metadata)
|
||||
);
|
||||
}
|
||||
|
||||
private function extractExtraMetadata(array $metadata): array
|
||||
{
|
||||
$extracted = [];
|
||||
|
||||
foreach ($this->metadataFields as $field) {
|
||||
if (isset($metadata[$field]) && $metadata[$field] !== '') {
|
||||
$extracted[$field] = $metadata[$field];
|
||||
}
|
||||
}
|
||||
|
||||
return $extracted;
|
||||
}
|
||||
|
||||
public function mimeType(string $path): FileAttributes
|
||||
{
|
||||
$attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_MIME_TYPE);
|
||||
|
||||
if ($attributes->mimeType() === null) {
|
||||
throw UnableToRetrieveMetadata::mimeType($path);
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
public function lastModified(string $path): FileAttributes
|
||||
{
|
||||
$attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_LAST_MODIFIED);
|
||||
|
||||
if ($attributes->lastModified() === null) {
|
||||
throw UnableToRetrieveMetadata::lastModified($path);
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
public function fileSize(string $path): FileAttributes
|
||||
{
|
||||
$attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_FILE_SIZE);
|
||||
|
||||
if ($attributes->fileSize() === null) {
|
||||
throw UnableToRetrieveMetadata::fileSize($path);
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
public function listContents(string $path, bool $deep): iterable
|
||||
{
|
||||
$prefix = trim($this->prefixer->prefixPath($path), '/');
|
||||
$prefix = empty($prefix) ? '' : $prefix . '/';
|
||||
$options = ['Bucket' => $this->bucket, 'Prefix' => $prefix];
|
||||
|
||||
if ($deep === false) {
|
||||
$options['Delimiter'] = '/';
|
||||
}
|
||||
|
||||
$listing = $this->retrievePaginatedListing($options);
|
||||
|
||||
foreach ($listing as $item) {
|
||||
$key = $item['Key'] ?? $item['Prefix'];
|
||||
|
||||
if ($key === $prefix) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $this->mapS3ObjectMetadata($item, $this->prefixer->stripPrefix($key));
|
||||
}
|
||||
}
|
||||
|
||||
private function retrievePaginatedListing(array $options): Generator
|
||||
{
|
||||
$resultPaginator = $this->client->getPaginator('ListObjectsV2', $options + $this->options);
|
||||
|
||||
foreach ($resultPaginator as $result) {
|
||||
yield from ($result->get('CommonPrefixes') ?: []);
|
||||
yield from ($result->get('Contents') ?: []);
|
||||
}
|
||||
}
|
||||
|
||||
public function move(string $source, string $destination, Config $config): void
|
||||
{
|
||||
try {
|
||||
$this->copy($source, $destination, $config);
|
||||
$this->delete($source);
|
||||
} catch (FilesystemOperationFailed $exception) {
|
||||
throw UnableToMoveFile::fromLocationTo($source, $destination, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function copy(string $source, string $destination, Config $config): void
|
||||
{
|
||||
try {
|
||||
/** @var string $visibility */
|
||||
$visibility = $config->get(Config::OPTION_VISIBILITY) ?: $this->visibility($source)->visibility();
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToCopyFile::fromLocationTo(
|
||||
$source,
|
||||
$destination,
|
||||
$exception
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->client->copy(
|
||||
$this->bucket,
|
||||
$this->prefixer->prefixPath($source),
|
||||
$this->bucket,
|
||||
$this->prefixer->prefixPath($destination),
|
||||
$this->visibility->visibilityToAcl($visibility),
|
||||
$this->createOptionsFromConfig($config)['params']
|
||||
);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToCopyFile::fromLocationTo($source, $destination, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
private function readObject(string $path, bool $wantsStream): StreamInterface
|
||||
{
|
||||
$options = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
|
||||
|
||||
if ($wantsStream && $this->streamReads && ! isset($this->options['@http']['stream'])) {
|
||||
$options['@http']['stream'] = true;
|
||||
}
|
||||
|
||||
$command = $this->client->getCommand('GetObject', $options + $this->options);
|
||||
|
||||
try {
|
||||
return $this->client->execute($command)->get('Body');
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToReadFile::fromLocation($path, '', $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function publicUrl(string $path, Config $config): string
|
||||
{
|
||||
$location = $this->prefixer->prefixPath($path);
|
||||
|
||||
try {
|
||||
return $this->client->getObjectUrl($this->bucket, $location);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToGeneratePublicUrl::dueToError($path, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function checksum(string $path, Config $config): string
|
||||
{
|
||||
$algo = $config->get('checksum_algo', 'etag');
|
||||
|
||||
if ($algo !== 'etag') {
|
||||
throw new ChecksumAlgoIsNotSupported();
|
||||
}
|
||||
|
||||
try {
|
||||
$metadata = $this->fetchFileMetadata($path, 'checksum')->extraMetadata();
|
||||
} catch (UnableToRetrieveMetadata $exception) {
|
||||
throw new UnableToProvideChecksum($exception->reason(), $path, $exception);
|
||||
}
|
||||
|
||||
if ( ! isset($metadata['ETag'])) {
|
||||
throw new UnableToProvideChecksum('ETag header not available.', $path);
|
||||
}
|
||||
|
||||
return trim($metadata['ETag'], '"');
|
||||
}
|
||||
|
||||
public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string
|
||||
{
|
||||
try {
|
||||
$options = $config->get('get_object_options', []);
|
||||
$command = $this->client->getCommand('GetObject', [
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->prefixer->prefixPath($path),
|
||||
] + $options);
|
||||
|
||||
$presignedRequestOptions = $config->get('presigned_request_options', []);
|
||||
$request = $this->client->createPresignedRequest($command, $expiresAt, $presignedRequestOptions);
|
||||
|
||||
return (string)$request->getUri();
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToGenerateTemporaryUrl::dueToError($path, $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/league/flysystem-aws-s3-v3/LICENSE
vendored
Normal file
21
vendor/league/flysystem-aws-s3-v3/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 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.
|
||||
47
vendor/league/flysystem-aws-s3-v3/PortableVisibilityConverter.php
vendored
Normal file
47
vendor/league/flysystem-aws-s3-v3/PortableVisibilityConverter.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Flysystem\AwsS3V3;
|
||||
|
||||
use League\Flysystem\Visibility;
|
||||
|
||||
class PortableVisibilityConverter implements VisibilityConverter
|
||||
{
|
||||
private const PUBLIC_GRANTEE_URI = 'http://acs.amazonaws.com/groups/global/AllUsers';
|
||||
private const PUBLIC_GRANTS_PERMISSION = 'READ';
|
||||
private const PUBLIC_ACL = 'public-read';
|
||||
private const PRIVATE_ACL = 'private';
|
||||
|
||||
public function __construct(private string $defaultForDirectories = Visibility::PUBLIC)
|
||||
{
|
||||
}
|
||||
|
||||
public function visibilityToAcl(string $visibility): string
|
||||
{
|
||||
if ($visibility === Visibility::PUBLIC) {
|
||||
return self::PUBLIC_ACL;
|
||||
}
|
||||
|
||||
return self::PRIVATE_ACL;
|
||||
}
|
||||
|
||||
public function aclToVisibility(array $grants): string
|
||||
{
|
||||
foreach ($grants as $grant) {
|
||||
$granteeUri = $grant['Grantee']['URI'] ?? null;
|
||||
$permission = $grant['Permission'] ?? null;
|
||||
|
||||
if ($granteeUri === self::PUBLIC_GRANTEE_URI && $permission === self::PUBLIC_GRANTS_PERMISSION) {
|
||||
return Visibility::PUBLIC;
|
||||
}
|
||||
}
|
||||
|
||||
return Visibility::PRIVATE;
|
||||
}
|
||||
|
||||
public function defaultForDirectories(): string
|
||||
{
|
||||
return $this->defaultForDirectories;
|
||||
}
|
||||
}
|
||||
12
vendor/league/flysystem-aws-s3-v3/VisibilityConverter.php
vendored
Normal file
12
vendor/league/flysystem-aws-s3-v3/VisibilityConverter.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Flysystem\AwsS3V3;
|
||||
|
||||
interface VisibilityConverter
|
||||
{
|
||||
public function visibilityToAcl(string $visibility): string;
|
||||
public function aclToVisibility(array $grants): string;
|
||||
public function defaultForDirectories(): string;
|
||||
}
|
||||
161
vendor/league/flysystem-aws-s3-v3/changelog.md
vendored
Normal file
161
vendor/league/flysystem-aws-s3-v3/changelog.md
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.30 - 2022-07-02
|
||||
|
||||
* upgrade to list objects v2
|
||||
|
||||
## 1.0.29 - 2020-10-08
|
||||
|
||||
* copies now switch to multipart copy for large files.
|
||||
|
||||
## 1.0.28 - 2020-08-22
|
||||
|
||||
* __Allow streamed read by default.__<br/>
|
||||
This change prevents the stream from being seekable (func
|
||||
calls like rewind have no effect). Need to seek through the stream?
|
||||
Check out the docs to see how to disable streaming read: https://flysystem.thephpleague.com/v1/docs/adapter/aws-s3-v3/#streamed-reads
|
||||
|
||||
## 1.0.27 - 2020-08-22
|
||||
|
||||
* Revert always streaming reads (degraded functionality).
|
||||
|
||||
## 1.0.26 - 2020-08-18
|
||||
|
||||
* Always stream reads (#211)
|
||||
|
||||
## 1.0.25 - 2020-06-02
|
||||
|
||||
* Use `S3Client::encodeKey` for key encoding.
|
||||
|
||||
## 1.0.24 - 2020-02-23
|
||||
|
||||
* Depend on S3ClientInterface rather than the concrete client.
|
||||
|
||||
## 1.0.23 - 2019-06-05
|
||||
|
||||
* Prevent content type detection for directory creation.
|
||||
* Use `rawurlencode` instead of `urlencode` to treat url encoding in a spec compliant way.
|
||||
|
||||
## 1.0.22 - 2019-01-31
|
||||
|
||||
* Invert type check where string/resource difference is determined for ContentLength option.
|
||||
|
||||
## 1.0.21 - 2018-10-08
|
||||
|
||||
* Catch multipart upload errors.
|
||||
|
||||
## 1.0.20 - 2018-09-25
|
||||
|
||||
* Fixed prefix handling for uploads (writes and updates).
|
||||
|
||||
## 1.0.19 - 2018-03-27
|
||||
|
||||
* Added ETAG to response mapping.
|
||||
|
||||
## 1.0.18 - 2017-06-30
|
||||
|
||||
### Fixed
|
||||
|
||||
* Allow metadata to be returned through the getMetadata method.
|
||||
|
||||
## 1.0.17 - 2017-06-30
|
||||
|
||||
### Fixed
|
||||
|
||||
* Allow passing options to methods that don't accept options.
|
||||
|
||||
## 1.0.16 - 2017-06-08
|
||||
|
||||
### Improved
|
||||
|
||||
* Allow the `Tagging` meta option.
|
||||
|
||||
## 1.0.15 - 2017-04-28
|
||||
|
||||
### Improved
|
||||
|
||||
* Indicate this adapter can overwrite files.
|
||||
|
||||
## 1.0.14 - 2017-01-02
|
||||
|
||||
### Improved
|
||||
|
||||
* Now also detect mimetypes of streams.
|
||||
|
||||
## 1.0.13 - 2016-06-21
|
||||
|
||||
### Fixed
|
||||
|
||||
* Uploading a remote stream no longer results in an unexpected exception.
|
||||
|
||||
## 1.0.12 - 2016-06-06
|
||||
|
||||
### Improved
|
||||
|
||||
* Responses are now streamed instead of downloaded fully.
|
||||
|
||||
## 1.0.11 - 2016-05-03
|
||||
|
||||
### Fixed
|
||||
|
||||
* [::has] A regression introduced in 1.0.10 is addressed.
|
||||
|
||||
## 1.0.10 - 2016-04-19
|
||||
|
||||
### Fixed
|
||||
|
||||
* [::has] The `has` method now also respects implicit directories.
|
||||
|
||||
## 1.0.9 - 2015-11-19
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#49] Large listings only returned the last page of the listing.
|
||||
|
||||
## 1.0.8 - 2015-11-06
|
||||
|
||||
### Improved
|
||||
|
||||
* Non-recursive listings now retrieve a shallow listing for better performance.
|
||||
|
||||
## 1.0.7 - 2015-11-06
|
||||
|
||||
### Fixed
|
||||
|
||||
* The `copy` operation now `urlencode`'s the `CopySource` to allow characters like `+`.
|
||||
|
||||
## 1.0.6 - 2015-09-25
|
||||
|
||||
### Fixed
|
||||
|
||||
* The `has` operation now respects path prefix, bug introduced in 1.0.5.
|
||||
|
||||
## 1.0.5 - 2015-09-22
|
||||
|
||||
### Fixed
|
||||
|
||||
* `has` calls now use `doesObjectExist` rather than retrieving metadata.
|
||||
|
||||
## 1.0.4 - 2015-07-06
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed delete return value.
|
||||
|
||||
## 1.0.3 - 2015-06-16
|
||||
|
||||
### Fixed
|
||||
|
||||
* Use an iterator for contents listing to break through the 1000 objects limit.
|
||||
|
||||
## 1.0.2 - 2015-06-06
|
||||
|
||||
### Fixed
|
||||
|
||||
* Exception due to misconfiguration no longer causes a fatal error but are properly rethrown.
|
||||
|
||||
## 1.0.1 - 2015-05-31
|
||||
|
||||
### Fixed
|
||||
|
||||
* Stable release depending in the first v3 release of the AWS SDK.
|
||||
28
vendor/league/flysystem-aws-s3-v3/composer.json
vendored
Normal file
28
vendor/league/flysystem-aws-s3-v3/composer.json
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "league/flysystem-aws-s3-v3",
|
||||
"description": "AWS S3 filesystem adapter for Flysystem.",
|
||||
"keywords": ["aws", "s3", "flysystem", "filesystem", "storage", "file", "files"],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Flysystem\\AwsS3V3\\": ""
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0.2",
|
||||
"league/flysystem": "^3.10.0",
|
||||
"league/mime-type-detection": "^1.0.0",
|
||||
"aws/aws-sdk-php": "^3.220.0"
|
||||
},
|
||||
"conflict": {
|
||||
"guzzlehttp/ringphp": "<1.1.1",
|
||||
"guzzlehttp/guzzle": "<7.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frankdejonge.nl"
|
||||
}
|
||||
]
|
||||
}
|
||||
723
vendor/league/flysystem-aws-s3-v3/src/AwsS3Adapter.php
vendored
Normal file
723
vendor/league/flysystem-aws-s3-v3/src/AwsS3Adapter.php
vendored
Normal file
@@ -0,0 +1,723 @@
|
||||
<?php
|
||||
|
||||
namespace League\Flysystem\AwsS3v3;
|
||||
|
||||
use Aws\Result;
|
||||
use Aws\S3\Exception\DeleteMultipleObjectsException;
|
||||
use Aws\S3\Exception\S3Exception;
|
||||
use Aws\S3\Exception\S3MultipartUploadException;
|
||||
use Aws\S3\S3Client;
|
||||
use Aws\S3\S3ClientInterface;
|
||||
use League\Flysystem\AdapterInterface;
|
||||
use League\Flysystem\Adapter\AbstractAdapter;
|
||||
use League\Flysystem\Adapter\CanOverwriteFiles;
|
||||
use League\Flysystem\Config;
|
||||
use League\Flysystem\Util;
|
||||
|
||||
class AwsS3Adapter extends AbstractAdapter implements CanOverwriteFiles
|
||||
{
|
||||
const PUBLIC_GRANT_URI = 'http://acs.amazonaws.com/groups/global/AllUsers';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $resultMap = [
|
||||
'Body' => 'contents',
|
||||
'ContentLength' => 'size',
|
||||
'ContentType' => 'mimetype',
|
||||
'Size' => 'size',
|
||||
'Metadata' => 'metadata',
|
||||
'StorageClass' => 'storageclass',
|
||||
'ETag' => 'etag',
|
||||
'VersionId' => 'versionid'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $metaOptions = [
|
||||
'ACL',
|
||||
'CacheControl',
|
||||
'ContentDisposition',
|
||||
'ContentEncoding',
|
||||
'ContentLength',
|
||||
'ContentMD5',
|
||||
'ContentType',
|
||||
'Expires',
|
||||
'GrantFullControl',
|
||||
'GrantRead',
|
||||
'GrantReadACP',
|
||||
'GrantWriteACP',
|
||||
'Metadata',
|
||||
'RequestPayer',
|
||||
'SSECustomerAlgorithm',
|
||||
'SSECustomerKey',
|
||||
'SSECustomerKeyMD5',
|
||||
'SSEKMSKeyId',
|
||||
'ServerSideEncryption',
|
||||
'StorageClass',
|
||||
'Tagging',
|
||||
'WebsiteRedirectLocation',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var S3ClientInterface
|
||||
*/
|
||||
protected $s3Client;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $bucket;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $streamReads;
|
||||
|
||||
public function __construct(S3ClientInterface $client, $bucket, $prefix = '', array $options = [], $streamReads = true)
|
||||
{
|
||||
$this->s3Client = $client;
|
||||
$this->bucket = $bucket;
|
||||
$this->setPathPrefix($prefix);
|
||||
$this->options = $options;
|
||||
$this->streamReads = $streamReads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the S3Client bucket.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBucket()
|
||||
{
|
||||
return $this->bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the S3Client bucket.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function setBucket($bucket)
|
||||
{
|
||||
$this->bucket = $bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the S3Client instance.
|
||||
*
|
||||
* @return S3ClientInterface
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->s3Client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $contents
|
||||
* @param Config $config Config object
|
||||
*
|
||||
* @return false|array false on failure file meta data on success
|
||||
*/
|
||||
public function write($path, $contents, Config $config)
|
||||
{
|
||||
return $this->upload($path, $contents, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $contents
|
||||
* @param Config $config Config object
|
||||
*
|
||||
* @return false|array false on failure file meta data on success
|
||||
*/
|
||||
public function update($path, $contents, Config $config)
|
||||
{
|
||||
return $this->upload($path, $contents, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $newpath
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function rename($path, $newpath)
|
||||
{
|
||||
if ( ! $this->copy($path, $newpath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->delete($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($path)
|
||||
{
|
||||
$location = $this->applyPathPrefix($path);
|
||||
|
||||
$command = $this->s3Client->getCommand(
|
||||
'deleteObject',
|
||||
[
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $location,
|
||||
]
|
||||
);
|
||||
|
||||
$this->s3Client->execute($command);
|
||||
|
||||
return ! $this->has($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a directory.
|
||||
*
|
||||
* @param string $dirname
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteDir($dirname)
|
||||
{
|
||||
try {
|
||||
$prefix = $this->applyPathPrefix($dirname) . '/';
|
||||
$this->s3Client->deleteMatchingObjects($this->bucket, $prefix);
|
||||
} catch (DeleteMultipleObjectsException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory.
|
||||
*
|
||||
* @param string $dirname directory name
|
||||
* @param Config $config
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public function createDir($dirname, Config $config)
|
||||
{
|
||||
return $this->upload($dirname . '/', '', $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a file exists.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($path)
|
||||
{
|
||||
$location = $this->applyPathPrefix($path);
|
||||
|
||||
if ($this->s3Client->doesObjectExist($this->bucket, $location, $this->options)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->doesDirectoryExist($location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return false|array
|
||||
*/
|
||||
public function read($path)
|
||||
{
|
||||
$response = $this->readObject($path);
|
||||
|
||||
if ($response !== false) {
|
||||
$response['contents'] = $response['contents']->getContents();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* List contents of a directory.
|
||||
*
|
||||
* @param string $directory
|
||||
* @param bool $recursive
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listContents($directory = '', $recursive = false)
|
||||
{
|
||||
$prefix = $this->applyPathPrefix(rtrim($directory, '/') . '/');
|
||||
$options = ['Bucket' => $this->bucket, 'Prefix' => ltrim($prefix, '/')];
|
||||
|
||||
if ($recursive === false) {
|
||||
$options['Delimiter'] = '/';
|
||||
}
|
||||
|
||||
$listing = $this->retrievePaginatedListing($options);
|
||||
$normalizer = [$this, 'normalizeResponse'];
|
||||
$normalized = array_map($normalizer, $listing);
|
||||
|
||||
return Util::emulateDirectories($normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function retrievePaginatedListing(array $options)
|
||||
{
|
||||
$resultPaginator = $this->s3Client->getPaginator('ListObjectsV2', $options);
|
||||
$listing = [];
|
||||
|
||||
foreach ($resultPaginator as $result) {
|
||||
$listing = array_merge($listing, $result->get('Contents') ?: [], $result->get('CommonPrefixes') ?: []);
|
||||
}
|
||||
|
||||
return $listing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the meta data of a file or directory.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return false|array
|
||||
*/
|
||||
public function getMetadata($path)
|
||||
{
|
||||
$command = $this->s3Client->getCommand(
|
||||
'headObject',
|
||||
[
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->applyPathPrefix($path),
|
||||
] + $this->options
|
||||
);
|
||||
|
||||
/* @var Result $result */
|
||||
try {
|
||||
$result = $this->s3Client->execute($command);
|
||||
} catch (S3Exception $exception) {
|
||||
if ($this->is404Exception($exception)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $this->normalizeResponse($result->toArray(), $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is404Exception(S3Exception $exception)
|
||||
{
|
||||
$response = $exception->getResponse();
|
||||
|
||||
if ($response !== null && $response->getStatusCode() === 404) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the meta data of a file or directory.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return false|array
|
||||
*/
|
||||
public function getSize($path)
|
||||
{
|
||||
return $this->getMetadata($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mimetype of a file.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return false|array
|
||||
*/
|
||||
public function getMimetype($path)
|
||||
{
|
||||
return $this->getMetadata($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp of a file.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return false|array
|
||||
*/
|
||||
public function getTimestamp($path)
|
||||
{
|
||||
return $this->getMetadata($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new file using a stream.
|
||||
*
|
||||
* @param string $path
|
||||
* @param resource $resource
|
||||
* @param Config $config Config object
|
||||
*
|
||||
* @return array|false false on failure file meta data on success
|
||||
*/
|
||||
public function writeStream($path, $resource, Config $config)
|
||||
{
|
||||
return $this->upload($path, $resource, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a file using a stream.
|
||||
*
|
||||
* @param string $path
|
||||
* @param resource $resource
|
||||
* @param Config $config Config object
|
||||
*
|
||||
* @return array|false false on failure file meta data on success
|
||||
*/
|
||||
public function updateStream($path, $resource, Config $config)
|
||||
{
|
||||
return $this->upload($path, $resource, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $newpath
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function copy($path, $newpath)
|
||||
{
|
||||
try {
|
||||
$this->s3Client->copy(
|
||||
$this->bucket,
|
||||
$this->applyPathPrefix($path),
|
||||
$this->bucket,
|
||||
$this->applyPathPrefix($newpath),
|
||||
$this->getRawVisibility($path) === AdapterInterface::VISIBILITY_PUBLIC
|
||||
? 'public-read' : 'private',
|
||||
$this->options
|
||||
);
|
||||
} catch (S3Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file as a stream.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function readStream($path)
|
||||
{
|
||||
$response = $this->readObject($path);
|
||||
|
||||
if ($response !== false) {
|
||||
$response['stream'] = $response['contents']->detach();
|
||||
unset($response['contents']);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an object and normalize the response.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function readObject($path)
|
||||
{
|
||||
$options = [
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->applyPathPrefix($path),
|
||||
] + $this->options;
|
||||
|
||||
if ($this->streamReads && ! isset($options['@http']['stream'])) {
|
||||
$options['@http']['stream'] = true;
|
||||
}
|
||||
|
||||
$command = $this->s3Client->getCommand('getObject', $options + $this->options);
|
||||
|
||||
try {
|
||||
/** @var Result $response */
|
||||
$response = $this->s3Client->execute($command);
|
||||
} catch (S3Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->normalizeResponse($response->toArray(), $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the visibility for a file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $visibility
|
||||
*
|
||||
* @return array|false file meta data
|
||||
*/
|
||||
public function setVisibility($path, $visibility)
|
||||
{
|
||||
$command = $this->s3Client->getCommand(
|
||||
'putObjectAcl',
|
||||
[
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->applyPathPrefix($path),
|
||||
'ACL' => $visibility === AdapterInterface::VISIBILITY_PUBLIC ? 'public-read' : 'private',
|
||||
]
|
||||
);
|
||||
|
||||
try {
|
||||
$this->s3Client->execute($command);
|
||||
} catch (S3Exception $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return compact('path', 'visibility');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the visibility of a file.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function getVisibility($path)
|
||||
{
|
||||
return ['visibility' => $this->getRawVisibility($path)];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyPathPrefix($path)
|
||||
{
|
||||
return ltrim(parent::applyPathPrefix($path), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPathPrefix($prefix)
|
||||
{
|
||||
$prefix = ltrim((string) $prefix, '/');
|
||||
|
||||
return parent::setPathPrefix($prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object acl presented as a visibility.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRawVisibility($path)
|
||||
{
|
||||
$command = $this->s3Client->getCommand(
|
||||
'getObjectAcl',
|
||||
[
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->applyPathPrefix($path),
|
||||
]
|
||||
);
|
||||
|
||||
$result = $this->s3Client->execute($command);
|
||||
$visibility = AdapterInterface::VISIBILITY_PRIVATE;
|
||||
|
||||
foreach ($result->get('Grants') as $grant) {
|
||||
if (
|
||||
isset($grant['Grantee']['URI'])
|
||||
&& $grant['Grantee']['URI'] === self::PUBLIC_GRANT_URI
|
||||
&& $grant['Permission'] === 'READ'
|
||||
) {
|
||||
$visibility = AdapterInterface::VISIBILITY_PUBLIC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload an object.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string|resource $body
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function upload($path, $body, Config $config)
|
||||
{
|
||||
$key = $this->applyPathPrefix($path);
|
||||
$options = $this->getOptionsFromConfig($config);
|
||||
$acl = array_key_exists('ACL', $options) ? $options['ACL'] : 'private';
|
||||
|
||||
if (!$this->isOnlyDir($path)) {
|
||||
if ( ! isset($options['ContentType'])) {
|
||||
$options['ContentType'] = Util::guessMimeType($path, $body);
|
||||
}
|
||||
|
||||
if ( ! isset($options['ContentLength'])) {
|
||||
$options['ContentLength'] = is_resource($body) ? Util::getStreamSize($body) : Util::contentSize($body);
|
||||
}
|
||||
|
||||
if ($options['ContentLength'] === null) {
|
||||
unset($options['ContentLength']);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$this->s3Client->upload($this->bucket, $key, $body, $acl, ['params' => $options]);
|
||||
} catch (S3MultipartUploadException $multipartUploadException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->normalizeResponse($options, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the path contains only directories
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isOnlyDir($path)
|
||||
{
|
||||
return substr($path, -1) === '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options from the config.
|
||||
*
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getOptionsFromConfig(Config $config)
|
||||
{
|
||||
$options = $this->options;
|
||||
|
||||
if ($visibility = $config->get('visibility')) {
|
||||
// For local reference
|
||||
$options['visibility'] = $visibility;
|
||||
// For external reference
|
||||
$options['ACL'] = $visibility === AdapterInterface::VISIBILITY_PUBLIC ? 'public-read' : 'private';
|
||||
}
|
||||
|
||||
if ($mimetype = $config->get('mimetype')) {
|
||||
// For local reference
|
||||
$options['mimetype'] = $mimetype;
|
||||
// For external reference
|
||||
$options['ContentType'] = $mimetype;
|
||||
}
|
||||
|
||||
foreach (static::$metaOptions as $option) {
|
||||
if ( ! $config->has($option)) {
|
||||
continue;
|
||||
}
|
||||
$options[$option] = $config->get($option);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the object result array.
|
||||
*
|
||||
* @param array $response
|
||||
* @param string $path
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function normalizeResponse(array $response, $path = null)
|
||||
{
|
||||
$result = [
|
||||
'path' => $path ?: $this->removePathPrefix(
|
||||
isset($response['Key']) ? $response['Key'] : $response['Prefix']
|
||||
),
|
||||
];
|
||||
$result = array_merge($result, Util::pathinfo($result['path']));
|
||||
|
||||
if (isset($response['LastModified'])) {
|
||||
$result['timestamp'] = strtotime($response['LastModified']);
|
||||
}
|
||||
|
||||
if ($this->isOnlyDir($result['path'])) {
|
||||
$result['type'] = 'dir';
|
||||
$result['path'] = rtrim($result['path'], '/');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return array_merge($result, Util::map($response, static::$resultMap), ['type' => 'file']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $location
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function doesDirectoryExist($location)
|
||||
{
|
||||
// Maybe this isn't an actual key, but a prefix.
|
||||
// Do a prefix listing of objects to determine.
|
||||
$command = $this->s3Client->getCommand(
|
||||
'ListObjectsV2',
|
||||
[
|
||||
'Bucket' => $this->bucket,
|
||||
'Prefix' => rtrim($location, '/') . '/',
|
||||
'MaxKeys' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
try {
|
||||
$result = $this->s3Client->execute($command);
|
||||
|
||||
return $result['Contents'] || $result['CommonPrefixes'];
|
||||
} catch (S3Exception $e) {
|
||||
if (in_array($e->getStatusCode(), [403, 404], true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user