feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)
Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.
Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
- Provider key: s3compatible
- Reads user-configured endpoint URL from settings
- Uses path-style URL access (required by most S3-compatible services)
- Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
- Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
This commit is contained in:
190
vendor/Gcp/google/cloud-storage/src/Acl.php
vendored
Normal file
190
vendor/Gcp/google/cloud-storage/src/Acl.php
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||
use InvalidArgumentException;
|
||||
/**
|
||||
* Google Cloud Storage uses access control lists (ACLs) to manage bucket and
|
||||
* object access. ACLs are the mechanism you use to share objects with other
|
||||
* users and allow other users to access your buckets and objects. For more
|
||||
* information please see the overview on
|
||||
* [access-control](https://cloud.google.com/storage/docs/access-control).
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* use Google\Cloud\Storage\StorageClient;
|
||||
*
|
||||
* $storage = new StorageClient();
|
||||
*
|
||||
* $bucket = $storage->bucket('my-bucket');
|
||||
* $acl = $bucket->acl();
|
||||
* ```
|
||||
*/
|
||||
class Acl
|
||||
{
|
||||
const ROLE_READER = 'READER';
|
||||
const ROLE_WRITER = 'WRITER';
|
||||
const ROLE_OWNER = 'OWNER';
|
||||
/**
|
||||
* @var ConnectionInterface Represents a connection to Cloud Storage.
|
||||
* @internal
|
||||
*/
|
||||
protected $connection;
|
||||
/**
|
||||
* @var array ACL specific options.
|
||||
*/
|
||||
private $aclOptions;
|
||||
/**
|
||||
* @param ConnectionInterface $connection Represents a connection to
|
||||
* Cloud Storage. This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param string $type The type of access control this instance applies to.
|
||||
* @param array $identity Represents which bucket, file, or generation this
|
||||
* instance applies to.
|
||||
* @throws \InvalidArgumentException Thrown when an invalid type is passed in.
|
||||
*/
|
||||
public function __construct(ConnectionInterface $connection, $type, array $identity)
|
||||
{
|
||||
$validTypes = ['bucketAccessControls', 'defaultObjectAccessControls', 'objectAccessControls'];
|
||||
if (!\in_array($type, $validTypes)) {
|
||||
throw new InvalidArgumentException('type must be one of the following: ' . \implode(', ', $validTypes));
|
||||
}
|
||||
$this->connection = $connection;
|
||||
$this->aclOptions = $identity + ['type' => $type];
|
||||
}
|
||||
/**
|
||||
* Delete access controls.
|
||||
*
|
||||
* Delete access controls on a {@see Bucket} or
|
||||
* {@see StorageObject} for a specified entity.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $acl->delete('allAuthenticatedUsers');
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/delete BucketAccessControls delete
|
||||
* API documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls/delete
|
||||
* DefaultObjectAccessControls delete API documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/delete ObjectAccessControls delete
|
||||
* API documentation.
|
||||
*
|
||||
* @param string $entity The entity to delete.
|
||||
* @param array $options [optional] Configuration Options.
|
||||
* @return void
|
||||
*/
|
||||
public function delete($entity, array $options = [])
|
||||
{
|
||||
$aclOptions = $this->aclOptions + ['entity' => $entity];
|
||||
$this->connection->deleteAcl($options + $aclOptions);
|
||||
}
|
||||
/**
|
||||
* Get access controls.
|
||||
*
|
||||
* Get access controls on a {@see Bucket} or
|
||||
* {@see StorageObject}. By default this will return all available
|
||||
* access controls. You may optionally specify a single entity to return
|
||||
* details for as well.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $res = $acl->get(['entity' => 'allAuthenticatedUsers']);
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/get BucketAccessControls get API
|
||||
* documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls/get
|
||||
* DefaultObjectAccessControls get API documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/get ObjectAccessControls get API
|
||||
* documentation.
|
||||
*
|
||||
* @param array $options [optional] {
|
||||
* Configuration options.
|
||||
*
|
||||
* @type string $entity The entity to fetch.
|
||||
* }
|
||||
* @return array
|
||||
*/
|
||||
public function get(array $options = [])
|
||||
{
|
||||
if (isset($options['entity'])) {
|
||||
return $this->connection->getAcl($options + $this->aclOptions);
|
||||
}
|
||||
$response = $this->connection->listAcl($options + $this->aclOptions);
|
||||
return $response['items'];
|
||||
}
|
||||
/**
|
||||
* Add access controls.
|
||||
*
|
||||
* Add access controls on a {@see Bucket} or
|
||||
* {@see StorageObject}.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $acl->add('allAuthenticatedUsers', 'WRITER');
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/insert BucketAccessControls insert
|
||||
* API documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls/insert
|
||||
* DefaultObjectAccessControls insert API documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/insert ObjectAccessControls insert
|
||||
* API documentation.
|
||||
*
|
||||
* @param string $entity The entity to add access controls to.
|
||||
* @param string $role The permissions to add for the specified entity. May
|
||||
* be one of 'OWNER', 'READER', or 'WRITER'.
|
||||
* @param array $options [optional] Configuration Options.
|
||||
* @return array
|
||||
*/
|
||||
public function add($entity, $role, array $options = [])
|
||||
{
|
||||
$aclOptions = $this->aclOptions + ['entity' => $entity, 'role' => $role];
|
||||
return $this->connection->insertAcl($options + $aclOptions);
|
||||
}
|
||||
/**
|
||||
* Update access controls.
|
||||
*
|
||||
* Update access controls on a {@see Bucket} or {@see StorageObject}.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $acl->update('allAuthenticatedUsers', 'READER');
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/patch BucketAccessControls patch API
|
||||
* documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls/patch
|
||||
* DefaultObjectAccessControls patch API documentation.
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/patch ObjectAccessControls patch
|
||||
* API documentation.
|
||||
*
|
||||
* @param string $entity The entity to update access controls for.
|
||||
* @param string $role The permissions to update for the specified entity.
|
||||
* May be one of 'OWNER', 'READER', or 'WRITER'.
|
||||
* @param array $options [optional] Configuration Options.
|
||||
* @return array
|
||||
*/
|
||||
public function update($entity, $role, array $options = [])
|
||||
{
|
||||
$aclOptions = $this->aclOptions + ['entity' => $entity, 'role' => $role];
|
||||
return $this->connection->patchAcl($options + $aclOptions);
|
||||
}
|
||||
}
|
||||
1415
vendor/Gcp/google/cloud-storage/src/Bucket.php
vendored
Normal file
1415
vendor/Gcp/google/cloud-storage/src/Bucket.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
160
vendor/Gcp/google/cloud-storage/src/Connection/ConnectionInterface.php
vendored
Normal file
160
vendor/Gcp/google/cloud-storage/src/Connection/ConnectionInterface.php
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection;
|
||||
|
||||
/**
|
||||
* Represents a connection to
|
||||
* [Cloud Storage](https://cloud.google.com/storage/).
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface ConnectionInterface
|
||||
{
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteAcl(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getAcl(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listAcl(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertAcl(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function patchAcl(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteBucket(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getBucket(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listBuckets(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertBucket(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getBucketIamPolicy(array $args);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function setBucketIamPolicy(array $args);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function testBucketIamPermissions(array $args);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function patchBucket(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function copyObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function rewriteObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function composeObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listObjects(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function patchObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function downloadObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertObject(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getNotification(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteNotification(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertNotification(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listNotifications(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getServiceAccount(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function lockRetentionPolicy(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function createHmacKey(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteHmacKey(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getHmacKey(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function updateHmacKey(array $args = []);
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listHmacKeys(array $args = []);
|
||||
}
|
||||
66
vendor/Gcp/google/cloud-storage/src/Connection/IamBucket.php
vendored
Normal file
66
vendor/Gcp/google/cloud-storage/src/Connection/IamBucket.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Iam\IamConnectionInterface;
|
||||
/**
|
||||
* IAM Implementation for GCS Buckets
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class IamBucket implements IamConnectionInterface
|
||||
{
|
||||
/**
|
||||
* @var ConnectionInterface
|
||||
*/
|
||||
private $connection;
|
||||
/**
|
||||
* @param ConnectionInterface $connection
|
||||
*/
|
||||
public function __construct(ConnectionInterface $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getPolicy(array $args)
|
||||
{
|
||||
if (isset($args['requestedPolicyVersion'])) {
|
||||
$args['optionsRequestedPolicyVersion'] = $args['requestedPolicyVersion'];
|
||||
unset($args['requestedPolicyVersion']);
|
||||
}
|
||||
return $this->connection->getBucketIamPolicy($args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function setPolicy(array $args)
|
||||
{
|
||||
unset($args['resource']);
|
||||
return $this->connection->setBucketIamPolicy($args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function testPermissions(array $args)
|
||||
{
|
||||
unset($args['resource']);
|
||||
return $this->connection->testBucketIamPermissions($args);
|
||||
}
|
||||
}
|
||||
618
vendor/Gcp/google/cloud-storage/src/Connection/Rest.php
vendored
Normal file
618
vendor/Gcp/google/cloud-storage/src/Connection/Rest.php
vendored
Normal file
@@ -0,0 +1,618 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\GetUniverseDomainInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\RequestBuilder;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\RequestWrapper;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\RestTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Retry;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\RetryTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Upload\AbstractUploader;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Upload\MultipartUploader;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Upload\ResumableUploader;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Upload\StreamableUploader;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\UriTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StorageClient;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Exception\RequestException;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\MimeType;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\Request;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\Utils;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\RequestInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\ResponseInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\StreamInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Ramsey\Uuid\Uuid;
|
||||
/**
|
||||
* Implementation of the
|
||||
* [Google Cloud Storage JSON API](https://cloud.google.com/storage/docs/json_api/).
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Rest implements ConnectionInterface
|
||||
{
|
||||
use RestTrait {
|
||||
send as private traitSend;
|
||||
}
|
||||
use RetryTrait;
|
||||
use UriTrait;
|
||||
/**
|
||||
* Header and value that helps us identify a transcoded obj
|
||||
* w/o making a metadata(info) call.
|
||||
*/
|
||||
private const TRANSCODED_OBJ_HEADER_KEY = 'X-Goog-Stored-Content-Encoding';
|
||||
private const TRANSCODED_OBJ_HEADER_VAL = 'gzip';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
const BASE_URI = 'https://storage.googleapis.com/storage/v1/';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
const DEFAULT_API_ENDPOINT = 'https://storage.googleapis.com';
|
||||
const DEFAULT_API_ENDPOINT_TEMPLATE = 'https://storage.UNIVERSE_DOMAIN';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
const UPLOAD_URI = 'https://storage.googleapis.com/upload/storage/v1/b/{bucket}/o{?query*}';
|
||||
const UPLOAD_PATH = 'upload/storage/v1/b/{bucket}/o{?query*}';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
const DOWNLOAD_URI = 'https://storage.googleapis.com/storage/v1/b/{bucket}/o/{object}{?query*}';
|
||||
const DOWNLOAD_PATH = 'storage/v1/b/{bucket}/o/{object}{?query*}';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $projectId;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $apiEndpoint;
|
||||
/**
|
||||
* @var callable
|
||||
* value null accepted
|
||||
*/
|
||||
private $restRetryFunction;
|
||||
/**
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$config += [
|
||||
'serviceDefinitionPath' => __DIR__ . '/ServiceDefinition/storage-v1.json',
|
||||
'componentVersion' => StorageClient::VERSION,
|
||||
'apiEndpoint' => null,
|
||||
// If the user has not supplied a universe domain, use the environment variable if set.
|
||||
// Otherwise, use the default ("googleapis.com").
|
||||
'universeDomain' => \getenv('GOOGLE_CLOUD_UNIVERSE_DOMAIN') ?: GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN,
|
||||
// Cloud Storage needs to provide a default scope because the Storage
|
||||
// API does not accept JWTs with "audience"
|
||||
'scopes' => StorageClient::FULL_CONTROL_SCOPE,
|
||||
];
|
||||
$this->apiEndpoint = $this->getApiEndpoint(null, $config, self::DEFAULT_API_ENDPOINT_TEMPLATE);
|
||||
$this->setRequestWrapper(new RequestWrapper($config));
|
||||
$this->setRequestBuilder(new RequestBuilder($config['serviceDefinitionPath'], $this->apiEndpoint));
|
||||
$this->projectId = $this->pluck('projectId', $config, \false);
|
||||
$this->restRetryFunction = isset($config['restRetryFunction']) ? $config['restRetryFunction'] : null;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function projectId()
|
||||
{
|
||||
return $this->projectId;
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteAcl(array $args = [])
|
||||
{
|
||||
return $this->send($args['type'], 'delete', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getAcl(array $args = [])
|
||||
{
|
||||
return $this->send($args['type'], 'get', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listAcl(array $args = [])
|
||||
{
|
||||
return $this->send($args['type'], 'list', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertAcl(array $args = [])
|
||||
{
|
||||
return $this->send($args['type'], 'insert', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function patchAcl(array $args = [])
|
||||
{
|
||||
return $this->send($args['type'], 'patch', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteBucket(array $args = [])
|
||||
{
|
||||
return $this->send('buckets', 'delete', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getBucket(array $args = [])
|
||||
{
|
||||
return $this->send('buckets', 'get', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listBuckets(array $args = [])
|
||||
{
|
||||
return $this->send('buckets', 'list', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertBucket(array $args = [])
|
||||
{
|
||||
return $this->send('buckets', 'insert', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function patchBucket(array $args = [])
|
||||
{
|
||||
return $this->send('buckets', 'patch', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteObject(array $args = [])
|
||||
{
|
||||
return $this->send('objects', 'delete', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function copyObject(array $args = [])
|
||||
{
|
||||
return $this->send('objects', 'copy', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function rewriteObject(array $args = [])
|
||||
{
|
||||
return $this->send('objects', 'rewrite', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function composeObject(array $args = [])
|
||||
{
|
||||
return $this->send('objects', 'compose', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getObject(array $args = [])
|
||||
{
|
||||
return $this->send('objects', 'get', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listObjects(array $args = [])
|
||||
{
|
||||
return $this->send('objects', 'list', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function patchObject(array $args = [])
|
||||
{
|
||||
return $this->send('objects', 'patch', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function downloadObject(array $args = [])
|
||||
{
|
||||
// This makes sure we honour the range headers specified by the user
|
||||
$requestedBytes = $this->getRequestedBytes($args);
|
||||
$resultStream = Utils::streamFor(null);
|
||||
$transcodedObj = \false;
|
||||
list($request, $requestOptions) = $this->buildDownloadObjectParams($args);
|
||||
$invocationId = Uuid::uuid4()->toString();
|
||||
$requestOptions['retryHeaders'] = self::getRetryHeaders($invocationId, 1);
|
||||
$requestOptions['restRetryFunction'] = $this->getRestRetryFunction('objects', 'get', $requestOptions);
|
||||
// We try to deduce if the object is a transcoded object when we receive the headers.
|
||||
$requestOptions['restOptions']['on_headers'] = function ($response) use(&$transcodedObj) {
|
||||
$header = $response->getHeader(self::TRANSCODED_OBJ_HEADER_KEY);
|
||||
if (\is_array($header) && \in_array(self::TRANSCODED_OBJ_HEADER_VAL, $header)) {
|
||||
$transcodedObj = \true;
|
||||
}
|
||||
};
|
||||
$requestOptions['restRetryListener'] = function (\Exception $e, $retryAttempt, &$arguments) use($resultStream, $requestedBytes, $invocationId) {
|
||||
// if the exception has a response for us to use
|
||||
if ($e instanceof RequestException && $e->hasResponse()) {
|
||||
$msg = (string) $e->getResponse()->getBody();
|
||||
$fetchedStream = Utils::streamFor($msg);
|
||||
// add the partial response to our stream that we will return
|
||||
Utils::copyToStream($fetchedStream, $resultStream);
|
||||
// Start from the byte that was last fetched
|
||||
$startByte = \intval($requestedBytes['startByte']) + $resultStream->getSize();
|
||||
$endByte = $requestedBytes['endByte'];
|
||||
// modify the range headers to fetch the remaining data
|
||||
$arguments[1]['headers']['Range'] = \sprintf('bytes=%s-%s', $startByte, $endByte);
|
||||
$arguments[0] = $this->modifyRequestForRetry($arguments[0], $retryAttempt, $invocationId);
|
||||
}
|
||||
};
|
||||
$fetchedStream = $this->requestWrapper->send($request, $requestOptions)->getBody();
|
||||
// If our object is a transcoded object, then Range headers are not honoured.
|
||||
// That means even if we had a partial download available, the final obj
|
||||
// that was fetched will contain the complete object. So, we don't need to copy
|
||||
// the partial stream, we can just return the stream we fetched.
|
||||
if ($transcodedObj) {
|
||||
return $fetchedStream;
|
||||
}
|
||||
Utils::copyToStream($fetchedStream, $resultStream);
|
||||
$resultStream->seek(0);
|
||||
return $resultStream;
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
* @experimental The experimental flag means that while we believe this method
|
||||
* or class is ready for use, it may change before release in backwards-
|
||||
* incompatible ways. Please use with caution, and test thoroughly when
|
||||
* upgrading.
|
||||
*/
|
||||
public function downloadObjectAsync(array $args = [])
|
||||
{
|
||||
list($request, $requestOptions) = $this->buildDownloadObjectParams($args);
|
||||
return $this->requestWrapper->sendAsync($request, $requestOptions)->then(function (ResponseInterface $response) {
|
||||
return $response->getBody();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertObject(array $args = [])
|
||||
{
|
||||
$args = $this->resolveUploadOptions($args);
|
||||
$uploadType = AbstractUploader::UPLOAD_TYPE_RESUMABLE;
|
||||
if ($args['streamable']) {
|
||||
$uploaderClass = StreamableUploader::class;
|
||||
} elseif ($args['resumable']) {
|
||||
$uploaderClass = ResumableUploader::class;
|
||||
} else {
|
||||
$uploaderClass = MultipartUploader::class;
|
||||
$uploadType = AbstractUploader::UPLOAD_TYPE_MULTIPART;
|
||||
}
|
||||
$uriParams = ['bucket' => $args['bucket'], 'query' => ['predefinedAcl' => $args['predefinedAcl'], 'uploadType' => $uploadType, 'userProject' => $args['userProject']]];
|
||||
// Passing the preconditions we want to extract out of arguments
|
||||
// into our query params.
|
||||
$preconditions = self::$condIdempotentOps['objects.insert'];
|
||||
foreach ($preconditions as $precondition) {
|
||||
if (isset($args[$precondition])) {
|
||||
$uriParams['query'][$precondition] = $args[$precondition];
|
||||
}
|
||||
}
|
||||
return new $uploaderClass($this->requestWrapper, $args['data'], $this->expandUri($this->apiEndpoint . self::UPLOAD_PATH, $uriParams), $args['uploaderOptions']);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
private function resolveUploadOptions(array $args)
|
||||
{
|
||||
$args += ['bucket' => null, 'name' => null, 'validate' => \true, 'resumable' => null, 'streamable' => null, 'predefinedAcl' => null, 'metadata' => [], 'userProject' => null];
|
||||
$args['data'] = Utils::streamFor($args['data']);
|
||||
if ($args['resumable'] === null) {
|
||||
$args['resumable'] = $args['data']->getSize() > AbstractUploader::RESUMABLE_LIMIT;
|
||||
}
|
||||
if (!$args['name']) {
|
||||
$args['name'] = \basename($args['data']->getMetadata('uri'));
|
||||
}
|
||||
$validate = $this->chooseValidationMethod($args);
|
||||
if ($validate === 'md5') {
|
||||
$args['metadata']['md5Hash'] = \base64_encode(Utils::hash($args['data'], 'md5', \true));
|
||||
} elseif ($validate === 'crc32') {
|
||||
$args['metadata']['crc32c'] = $this->crcFromStream($args['data']);
|
||||
}
|
||||
$args['metadata']['name'] = $args['name'];
|
||||
if (isset($args['retention'])) {
|
||||
// during object creation retention properties go into metadata
|
||||
// but not into request body
|
||||
$args['metadata']['retention'] = $args['retention'];
|
||||
unset($args['retention']);
|
||||
}
|
||||
unset($args['name']);
|
||||
$args['contentType'] = $args['metadata']['contentType'] ?? MimeType::fromFilename($args['metadata']['name']);
|
||||
$uploaderOptionKeys = ['restOptions', 'retries', 'requestTimeout', 'chunkSize', 'contentType', 'metadata', 'uploadProgressCallback', 'restDelayFunction', 'restCalcDelayFunction'];
|
||||
$args['uploaderOptions'] = \array_intersect_key($args, \array_flip($uploaderOptionKeys));
|
||||
$args = \array_diff_key($args, \array_flip($uploaderOptionKeys));
|
||||
// Passing on custom retry function to $args['uploaderOptions']
|
||||
$retryFunc = $this->getRestRetryFunction('objects', 'insert', $args);
|
||||
$args['uploaderOptions']['restRetryFunction'] = $retryFunc;
|
||||
$args['uploaderOptions'] = $this->addRetryHeaderLogic($args['uploaderOptions']);
|
||||
return $args;
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getBucketIamPolicy(array $args)
|
||||
{
|
||||
return $this->send('buckets', 'getIamPolicy', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function setBucketIamPolicy(array $args)
|
||||
{
|
||||
return $this->send('buckets', 'setIamPolicy', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function testBucketIamPermissions(array $args)
|
||||
{
|
||||
return $this->send('buckets', 'testIamPermissions', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getNotification(array $args = [])
|
||||
{
|
||||
return $this->send('notifications', 'get', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteNotification(array $args = [])
|
||||
{
|
||||
return $this->send('notifications', 'delete', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function insertNotification(array $args = [])
|
||||
{
|
||||
return $this->send('notifications', 'insert', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listNotifications(array $args = [])
|
||||
{
|
||||
return $this->send('notifications', 'list', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getServiceAccount(array $args = [])
|
||||
{
|
||||
return $this->send('projects.resources.serviceAccount', 'get', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function lockRetentionPolicy(array $args = [])
|
||||
{
|
||||
return $this->send('buckets', 'lockRetentionPolicy', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function createHmacKey(array $args = [])
|
||||
{
|
||||
return $this->send('projects.resources.hmacKeys', 'create', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function deleteHmacKey(array $args = [])
|
||||
{
|
||||
return $this->send('projects.resources.hmacKeys', 'delete', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function getHmacKey(array $args = [])
|
||||
{
|
||||
return $this->send('projects.resources.hmacKeys', 'get', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function updateHmacKey(array $args = [])
|
||||
{
|
||||
return $this->send('projects.resources.hmacKeys', 'update', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
*/
|
||||
public function listHmacKeys(array $args = [])
|
||||
{
|
||||
return $this->send('projects.resources.hmacKeys', 'list', $args);
|
||||
}
|
||||
/**
|
||||
* @param array $args
|
||||
* @return array
|
||||
*/
|
||||
private function buildDownloadObjectParams(array $args)
|
||||
{
|
||||
$args += ['bucket' => null, 'object' => null, 'generation' => null, 'userProject' => null];
|
||||
$requestOptions = \array_intersect_key($args, ['restOptions' => null, 'retries' => null, 'restRetryFunction' => null, 'restCalcDelayFunction' => null, 'restDelayFunction' => null]);
|
||||
$uri = $this->expandUri($this->apiEndpoint . self::DOWNLOAD_PATH, ['bucket' => $args['bucket'], 'object' => $args['object'], 'query' => ['generation' => $args['generation'], 'alt' => 'media', 'userProject' => $args['userProject']]]);
|
||||
return [new Request('GET', Utils::uriFor($uri)), $requestOptions];
|
||||
}
|
||||
/**
|
||||
* Choose a upload validation method based on user input and platform
|
||||
* requirements.
|
||||
*
|
||||
* @param array $args
|
||||
* @return bool|string
|
||||
*/
|
||||
private function chooseValidationMethod(array $args)
|
||||
{
|
||||
// If the user provided a hash, skip hashing.
|
||||
if (isset($args['metadata']['md5Hash']) || isset($args['metadata']['crc32c'])) {
|
||||
return \false;
|
||||
}
|
||||
$validate = $args['validate'];
|
||||
if (\in_array($validate, [\false, 'crc32', 'md5'], \true)) {
|
||||
return $validate;
|
||||
}
|
||||
// not documented, but the feature is called crc32c, so let's accept that as input anyways.
|
||||
if ($validate === 'crc32c') {
|
||||
return 'crc32';
|
||||
}
|
||||
// is the extension loaded?
|
||||
if ($this->crc32cExtensionLoaded()) {
|
||||
return 'crc32';
|
||||
}
|
||||
// is crc32c available in `hash()`?
|
||||
if ($this->supportsBuiltinCrc32c()) {
|
||||
return 'crc32';
|
||||
}
|
||||
return 'md5';
|
||||
}
|
||||
/**
|
||||
* Generate a CRC32c checksum from a stream.
|
||||
*
|
||||
* @param StreamInterface $data
|
||||
* @return string
|
||||
*/
|
||||
private function crcFromStream(StreamInterface $data)
|
||||
{
|
||||
$pos = $data->tell();
|
||||
$data->rewind();
|
||||
$crc32c = \hash_init('crc32c');
|
||||
while (!$data->eof()) {
|
||||
$buffer = $data->read(1048576);
|
||||
\hash_update($crc32c, $buffer);
|
||||
}
|
||||
$data->seek($pos);
|
||||
$hash = \hash_final($crc32c, \true);
|
||||
return \base64_encode($hash);
|
||||
}
|
||||
/**
|
||||
* Check if the crc32c extension is available.
|
||||
*
|
||||
* Protected access for unit testing.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function crc32cExtensionLoaded()
|
||||
{
|
||||
return \extension_loaded('crc32c');
|
||||
}
|
||||
/**
|
||||
* Check if hash() supports crc32c.
|
||||
*
|
||||
* @deprecated
|
||||
* @return bool
|
||||
*/
|
||||
protected function supportsBuiltinCrc32c()
|
||||
{
|
||||
return \extension_loaded('hash') && \in_array('crc32c', \hash_algos());
|
||||
}
|
||||
/**
|
||||
* Add the required retry function and send the request.
|
||||
*
|
||||
* @param string $resource resource name, eg: buckets.
|
||||
* @param string $method method name, eg: get
|
||||
* @param array $options [optional] Options used to build out the request.
|
||||
* @param array $whitelisted [optional]
|
||||
*/
|
||||
public function send($resource, $method, array $options = [], $whitelisted = \false)
|
||||
{
|
||||
$retryMap = ['projects.resources.serviceAccount' => 'serviceaccount', 'projects.resources.hmacKeys' => 'hmacKey', 'bucketAccessControls' => 'bucket_acl', 'defaultObjectAccessControls' => 'default_object_acl', 'objectAccessControls' => 'object_acl'];
|
||||
$retryResource = isset($retryMap[$resource]) ? $retryMap[$resource] : $resource;
|
||||
$options['restRetryFunction'] = $this->restRetryFunction ?? $this->getRestRetryFunction($retryResource, $method, $options);
|
||||
$options = $this->addRetryHeaderLogic($options);
|
||||
return $this->traitSend($resource, $method, $options);
|
||||
}
|
||||
/**
|
||||
* Adds the retry headers to $args which amends retry hash and attempt
|
||||
* count to the required header.
|
||||
* @param array $args
|
||||
* @return array
|
||||
*/
|
||||
private function addRetryHeaderLogic(array $args)
|
||||
{
|
||||
$invocationId = Uuid::uuid4()->toString();
|
||||
$args['retryHeaders'] = self::getRetryHeaders($invocationId, 1);
|
||||
// Adding callback logic to update headers while retrying
|
||||
$args['restRetryListener'] = function (\Exception $e, $retryAttempt, &$arguments) use($invocationId) {
|
||||
$arguments[0] = $this->modifyRequestForRetry($arguments[0], $retryAttempt, $invocationId);
|
||||
};
|
||||
return $args;
|
||||
}
|
||||
private function modifyRequestForRetry(RequestInterface $request, int $retryAttempt, string $invocationId)
|
||||
{
|
||||
$changes = self::getRetryHeaders($invocationId, $retryAttempt + 1);
|
||||
$headerLine = $request->getHeaderLine(Retry::RETRY_HEADER_KEY);
|
||||
// An associative array to contain final header values as
|
||||
// $headerValueKey => $headerValue
|
||||
$headerElements = [];
|
||||
// Adding existing values
|
||||
$headerLineValues = \explode(' ', $headerLine);
|
||||
foreach ($headerLineValues as $value) {
|
||||
$key = \explode('/', $value)[0];
|
||||
$headerElements[$key] = $value;
|
||||
}
|
||||
// Adding changes with replacing value if $key already present
|
||||
foreach ($changes as $change) {
|
||||
$key = \explode('/', $change)[0];
|
||||
$headerElements[$key] = $change;
|
||||
}
|
||||
return $request->withHeader(Retry::RETRY_HEADER_KEY, \implode(' ', $headerElements));
|
||||
}
|
||||
/**
|
||||
* Util function to compute the bytes requested for a download request.
|
||||
*
|
||||
* @param array $options Request options
|
||||
* @return array
|
||||
*/
|
||||
private function getRequestedBytes(array $options)
|
||||
{
|
||||
$startByte = 0;
|
||||
$endByte = '';
|
||||
if (isset($options['restOptions']) && isset($options['restOptions']['headers'])) {
|
||||
$headers = $options['restOptions']['headers'];
|
||||
if (isset($headers['Range']) || isset($headers['range'])) {
|
||||
$header = isset($headers['Range']) ? $headers['Range'] : $headers['range'];
|
||||
$range = \explode('=', $header);
|
||||
$bytes = \explode('-', $range[1]);
|
||||
$startByte = $bytes[0];
|
||||
$endByte = $bytes[1];
|
||||
}
|
||||
}
|
||||
return \compact('startByte', 'endByte');
|
||||
}
|
||||
}
|
||||
173
vendor/Gcp/google/cloud-storage/src/Connection/RetryTrait.php
vendored
Normal file
173
vendor/Gcp/google/cloud-storage/src/Connection/RetryTrait.php
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2022 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StorageClient;
|
||||
/**
|
||||
* Trait which provides helper methods for retry logic.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait RetryTrait
|
||||
{
|
||||
/**
|
||||
* The HTTP codes that will be retried by our custom retry function.
|
||||
* @var array
|
||||
*/
|
||||
private static $httpRetryCodes = [
|
||||
0,
|
||||
// connetion-refused OR connection-reset gives status code of 0
|
||||
200,
|
||||
// partial download cases
|
||||
408,
|
||||
429,
|
||||
500,
|
||||
502,
|
||||
503,
|
||||
504,
|
||||
];
|
||||
/**
|
||||
* The operations which can be retried without any conditions
|
||||
* (Idempotent)
|
||||
* @var array
|
||||
*/
|
||||
private static $idempotentOps = ['bucket_acl.get', 'bucket_acl.list', 'buckets.delete', 'buckets.get', 'buckets.getIamPolicy', 'buckets.insert', 'buckets.list', 'buckets.lockRetentionPolicy', 'buckets.testIamPermissions', 'default_object_acl.get', 'default_object_acl.list', 'hmacKey.delete', 'hmacKey.get', 'hmacKey.list', 'notifications.delete', 'notifications.get', 'notifications.list', 'object_acl.get', 'object_acl.list', 'objects.get', 'objects.list', 'serviceaccount.get'];
|
||||
/**
|
||||
* The operations which can be retried with specific conditions
|
||||
* (Conditionally idempotent)
|
||||
* @var array
|
||||
*/
|
||||
private static $condIdempotentOps = [
|
||||
'buckets.patch' => ['ifMetagenerationMatch', 'etag'],
|
||||
// Currently etag is not supported, so this preCondition never available
|
||||
'buckets.setIamPolicy' => ['etag'],
|
||||
'buckets.update' => ['ifMetagenerationMatch', 'etag'],
|
||||
'hmacKey.update' => ['etag'],
|
||||
'objects.compose' => ['ifGenerationMatch'],
|
||||
'objects.copy' => ['ifGenerationMatch'],
|
||||
'objects.delete' => ['ifGenerationMatch'],
|
||||
'objects.insert' => ['ifGenerationMatch', 'ifGenerationNotMatch'],
|
||||
'objects.patch' => ['ifMetagenerationMatch', 'etag'],
|
||||
'objects.rewrite' => ['ifGenerationMatch'],
|
||||
'objects.update' => ['ifMetagenerationMatch'],
|
||||
];
|
||||
/**
|
||||
* Retry strategies which enforce certain behaviour like:
|
||||
* - Always retrying a call when an exception occurs(within the limits of 'max retries').
|
||||
* - Never retrying a call when an exception occurs.
|
||||
* - Retrying only when the operation is considered idempotent(default).
|
||||
* These configurations are supplied for per api call basis.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Header that identifies a specific request hash. The
|
||||
* hash needs to stay the same for multiple retries.
|
||||
*/
|
||||
private static $INVOCATION_ID_HEADER = 'gccl-invocation-id';
|
||||
/**
|
||||
* Header that identifies the attempt count for a request. The
|
||||
* value will increment by 1 with every retry.
|
||||
*/
|
||||
private static $ATTEMPT_COUNT_HEADER = 'gccl-attempt-count';
|
||||
/**
|
||||
* Return a retry decider function.
|
||||
*
|
||||
* @param string $resource resource name, eg: buckets.
|
||||
* @param string $method method name, eg: get
|
||||
* @param array $args
|
||||
* @return callable
|
||||
*/
|
||||
private function getRestRetryFunction($resource, $method, array $args)
|
||||
{
|
||||
if (isset($args['restRetryFunction'])) {
|
||||
return $args['restRetryFunction'];
|
||||
}
|
||||
$methodName = \sprintf('%s.%s', $resource, $method);
|
||||
$isOpIdempotent = \in_array($methodName, self::$idempotentOps);
|
||||
$preconditionNeeded = \array_key_exists($methodName, self::$condIdempotentOps);
|
||||
$preconditionSupplied = $this->isPreConditionSupplied($methodName, $args);
|
||||
$retryStrategy = isset($args['retryStrategy']) ? $args['retryStrategy'] : StorageClient::RETRY_IDEMPOTENT;
|
||||
return function (\Exception $exception) use($isOpIdempotent, $preconditionNeeded, $preconditionSupplied, $retryStrategy) {
|
||||
return $this->retryDeciderFunction($exception, $isOpIdempotent, $preconditionNeeded, $preconditionSupplied, $retryStrategy);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This function returns true when the user given
|
||||
* precondtions ($preConditions) has values that are present
|
||||
* in the precondition map ($this->condIdempotentMap) for that method.
|
||||
* eg: condIdempotentMap has entry 'objects.copy' => ['ifGenerationMatch'],
|
||||
* if the user has given 'ifGenerationMatch' in the 'objects.copy' operation,
|
||||
* it will be available in the $preConditions
|
||||
* as an array ['ifGenerationMatch']. This makes the array_intersect
|
||||
* function return a non empty result and this function returns true.
|
||||
*
|
||||
* @param string $methodName method name, eg: buckets.get.
|
||||
* @param array $args arguments which include preconditions provided,
|
||||
* eg: ['ifGenerationMatch' => 0].
|
||||
* @return bool
|
||||
*/
|
||||
private function isPreConditionSupplied($methodName, array $args)
|
||||
{
|
||||
if (isset(self::$condIdempotentOps[$methodName])) {
|
||||
// return true if required precondition are given.
|
||||
return !empty(\array_intersect(self::$condIdempotentOps[$methodName], \array_keys($args)));
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Decide whether the op needs to be retried or not.
|
||||
*
|
||||
* @param \Exception $exception The exception object received
|
||||
* while sending the request.
|
||||
* @param int $currentAttempt Current retry attempt.
|
||||
* @param bool $isIdempotent
|
||||
* @param bool $preconditionNeeded
|
||||
* @param bool $preconditionSupplied
|
||||
* @param int $maxRetries
|
||||
* @return bool
|
||||
*/
|
||||
private function retryDeciderFunction(\Exception $exception, $isIdempotent, $preconditionNeeded, $preconditionSupplied, $retryStrategy)
|
||||
{
|
||||
if ($retryStrategy == StorageClient::RETRY_NEVER) {
|
||||
return \false;
|
||||
}
|
||||
$statusCode = $exception->getCode();
|
||||
// Retry if the exception status code matches
|
||||
// with one of the retriable status code and
|
||||
// the operation is either idempotent or conditionally
|
||||
// idempotent with preconditions supplied.
|
||||
if (\in_array($statusCode, self::$httpRetryCodes)) {
|
||||
if ($retryStrategy == StorageClient::RETRY_ALWAYS) {
|
||||
return \true;
|
||||
} elseif ($isIdempotent) {
|
||||
return \true;
|
||||
} elseif ($preconditionNeeded) {
|
||||
return $preconditionSupplied;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Utility func that returns the list of headers that need to be
|
||||
* attached to every request and its retries.
|
||||
*/
|
||||
private static function getRetryHeaders($invocationId, $attemptCount)
|
||||
{
|
||||
return [\sprintf('%s/%s', self::$INVOCATION_ID_HEADER, $invocationId), \sprintf('%s/%d', self::$ATTEMPT_COUNT_HEADER, $attemptCount)];
|
||||
}
|
||||
}
|
||||
5391
vendor/Gcp/google/cloud-storage/src/Connection/ServiceDefinition/storage-v1.json
vendored
Normal file
5391
vendor/Gcp/google/cloud-storage/src/Connection/ServiceDefinition/storage-v1.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
82
vendor/Gcp/google/cloud-storage/src/CreatedHmacKey.php
vendored
Normal file
82
vendor/Gcp/google/cloud-storage/src/CreatedHmacKey.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
/**
|
||||
* Represents a newly created HMAC key. Provides access to the key metadata and
|
||||
* secret.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* use Google\Cloud\Storage\StorageClient;
|
||||
*
|
||||
* $storage = new StorageClient();
|
||||
* $response = $storage->createHmacKey($serviceAccountEmail);
|
||||
* ```
|
||||
*/
|
||||
class CreatedHmacKey
|
||||
{
|
||||
/**
|
||||
* @var HmacKey
|
||||
*/
|
||||
private $hmacKey;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $secret;
|
||||
/**
|
||||
* @param HmacKey $hmacKey The HMAC Key object.
|
||||
* @param string $secret The HMAC key secret.
|
||||
*/
|
||||
public function __construct(HmacKey $hmacKey, $secret)
|
||||
{
|
||||
$this->hmacKey = $hmacKey;
|
||||
$this->secret = $secret;
|
||||
}
|
||||
/**
|
||||
* Get the HMAC key object.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $key = $response->hmacKey();
|
||||
* ```
|
||||
*
|
||||
* @return HmacKey
|
||||
*/
|
||||
public function hmacKey()
|
||||
{
|
||||
return $this->hmacKey;
|
||||
}
|
||||
/**
|
||||
* Get the HMAC key secret.
|
||||
*
|
||||
* This value will never be returned from the API after first creation. Make
|
||||
* sure to record it for later use immediately upon key creation.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $secret = $response->secret();
|
||||
* ```
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function secret()
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
}
|
||||
120
vendor/Gcp/google/cloud-storage/src/EncryptionTrait.php
vendored
Normal file
120
vendor/Gcp/google/cloud-storage/src/EncryptionTrait.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\phpseclib\Crypt\RSA as RSA2;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\phpseclib3\Crypt\RSA as RSA3;
|
||||
/**
|
||||
* Trait which provides helper methods for customer-supplied encryption.
|
||||
*/
|
||||
trait EncryptionTrait
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $copySourceEncryptionHeaderNames = ['algorithm' => 'x-goog-copy-source-encryption-algorithm', 'key' => 'x-goog-copy-source-encryption-key', 'keySHA256' => 'x-goog-copy-source-encryption-key-sha256'];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $encryptionHeaderNames = ['algorithm' => 'x-goog-encryption-algorithm', 'key' => 'x-goog-encryption-key', 'keySHA256' => 'x-goog-encryption-key-sha256'];
|
||||
/**
|
||||
* Formats options for customer-supplied encryption headers.
|
||||
*
|
||||
* @param array $options
|
||||
* @return array
|
||||
* @access private
|
||||
*/
|
||||
public function formatEncryptionHeaders(array $options)
|
||||
{
|
||||
$encryptionHeaders = [];
|
||||
$useCopySourceHeaders = $options['useCopySourceHeaders'] ?? \false;
|
||||
$key = $options['encryptionKey'] ?? null;
|
||||
$keySHA256 = $options['encryptionKeySHA256'] ?? null;
|
||||
$destinationKey = $options['destinationEncryptionKey'] ?? null;
|
||||
$destinationKeySHA256 = $options['destinationEncryptionKeySHA256'] ?? null;
|
||||
unset($options['useCopySourceHeaders']);
|
||||
unset($options['encryptionKey']);
|
||||
unset($options['encryptionKeySHA256']);
|
||||
unset($options['destinationEncryptionKey']);
|
||||
unset($options['destinationEncryptionKeySHA256']);
|
||||
$encryptionHeaders = $this->buildHeaders($key, $keySHA256, $useCopySourceHeaders) + $this->buildHeaders($destinationKey, $destinationKeySHA256, \false);
|
||||
if (!empty($encryptionHeaders)) {
|
||||
if (isset($options['restOptions']['headers'])) {
|
||||
$options['restOptions']['headers'] += $encryptionHeaders;
|
||||
} else {
|
||||
$options['restOptions']['headers'] = $encryptionHeaders;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
/**
|
||||
* Builds out customer-supplied encryption headers.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $keySHA256
|
||||
* @param bool $useCopySourceHeaders
|
||||
* @return array
|
||||
*/
|
||||
private function buildHeaders($key, $keySHA256, $useCopySourceHeaders)
|
||||
{
|
||||
if ($key) {
|
||||
$headerNames = $useCopySourceHeaders ? $this->copySourceEncryptionHeaderNames : $this->encryptionHeaderNames;
|
||||
if (!$keySHA256) {
|
||||
$decodedKey = \base64_decode($key);
|
||||
$keySHA256 = \base64_encode(\hash('SHA256', $decodedKey, \true));
|
||||
}
|
||||
return [$headerNames['algorithm'] => 'AES256', $headerNames['key'] => $key, $headerNames['keySHA256'] => $keySHA256];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* Sign a string using a given private key.
|
||||
*
|
||||
* @deprecated Please use the {@see Google\Auth\SignBlobInterface::signBlob()}
|
||||
* and implementations for signing strings.
|
||||
* This method will be removed in a future release.
|
||||
*
|
||||
* @param string $privateKey The private key to use to sign the data.
|
||||
* @param string $data The data to sign.
|
||||
* @param bool $forceOpenssl If true, OpenSSL will be used regardless of
|
||||
* whether phpseclib is available. **Defaults to** `false`.
|
||||
* @return string The signature
|
||||
*/
|
||||
protected function signString($privateKey, $data, $forceOpenssl = \false)
|
||||
{
|
||||
$signature = '';
|
||||
if (\class_exists(RSA3::class) && !$forceOpenssl) {
|
||||
$rsa = RSA3::loadPrivateKey($privateKey);
|
||||
$rsa = $rsa->withPadding(RSA3::SIGNATURE_PKCS1)->withHash('sha256');
|
||||
$signature = $rsa->sign($data);
|
||||
} elseif (\class_exists(RSA2::class) && !$forceOpenssl) {
|
||||
$rsa = new RSA2();
|
||||
$rsa->loadKey($privateKey);
|
||||
$rsa->setSignatureMode(RSA2::SIGNATURE_PKCS1);
|
||||
$rsa->setHash('sha256');
|
||||
$signature = $rsa->sign($data);
|
||||
} elseif (\extension_loaded('openssl')) {
|
||||
\openssl_sign($data, $signature, $privateKey, 'sha256WithRSAEncryption');
|
||||
} else {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('OpenSSL is not installed.');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
return $signature;
|
||||
}
|
||||
}
|
||||
173
vendor/Gcp/google/cloud-storage/src/HmacKey.php
vendored
Normal file
173
vendor/Gcp/google/cloud-storage/src/HmacKey.php
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||
/**
|
||||
* Represents a Service Account HMAC key.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* use Google\Cloud\Storage\StorageClient;
|
||||
*
|
||||
* $storage = new StorageClient();
|
||||
* $hmacKey = $storage->hmacKey($accessId);
|
||||
* ```
|
||||
*/
|
||||
class HmacKey
|
||||
{
|
||||
/**
|
||||
* @var ConnectionInterface
|
||||
* @internal
|
||||
*/
|
||||
private $connection;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $projectId;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $accessId;
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $info;
|
||||
/**
|
||||
* @param ConnectionInterface $connection A connection to Cloud Storage.
|
||||
* This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param string $projectId The current project ID.
|
||||
* @param string $accessId The key identifier.
|
||||
* @param array|null $info The key metadata.
|
||||
*/
|
||||
public function __construct(ConnectionInterface $connection, $projectId, $accessId, array $info = [])
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->projectId = $projectId;
|
||||
$this->accessId = $accessId;
|
||||
$this->info = $info;
|
||||
}
|
||||
/**
|
||||
* Get the HMAC Key Access ID.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $accessId = $hmacKey->accessId();
|
||||
* ```
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function accessId()
|
||||
{
|
||||
return $this->accessId;
|
||||
}
|
||||
/**
|
||||
* Fetch the key metadata from Cloud Storage.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $keyMetadata = $hmacKey->reload();
|
||||
* ```
|
||||
*
|
||||
* @param array $options {
|
||||
* Configuration Options
|
||||
*
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request. **NOTE**: This option is
|
||||
* currently ignored by Cloud Storage.
|
||||
* }
|
||||
* @return array
|
||||
*/
|
||||
public function reload(array $options = [])
|
||||
{
|
||||
$this->info = $this->connection->getHmacKey(['projectId' => $this->projectId, 'accessId' => $this->accessId] + $options);
|
||||
return $this->info;
|
||||
}
|
||||
/**
|
||||
* Get the HMAC Key Metadata.
|
||||
*
|
||||
* If the metadata is not already available, it will be requested from Cloud
|
||||
* Storage.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $keyMetadata = $hmacKey->info();
|
||||
* ```
|
||||
*
|
||||
* @param array $options {
|
||||
* Configuration Options
|
||||
*
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request. **NOTE**: This option is
|
||||
* currently ignored by Cloud Storage.
|
||||
* }
|
||||
* @return array
|
||||
*/
|
||||
public function info(array $options = [])
|
||||
{
|
||||
return $this->info ?: $this->reload($options);
|
||||
}
|
||||
/**
|
||||
* Update the HMAC Key state.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $hmacKey->update('INACTIVE');
|
||||
* ```
|
||||
*
|
||||
* @param string $state The key state. Either `ACTIVE` or `INACTIVE`.
|
||||
* @param array $options {
|
||||
* Configuration Options
|
||||
*
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request. **NOTE**: This option is
|
||||
* currently ignored by Cloud Storage.
|
||||
* }
|
||||
* @return array
|
||||
*/
|
||||
public function update($state, array $options = [])
|
||||
{
|
||||
$this->info = $this->connection->updateHmacKey(['accessId' => $this->accessId, 'projectId' => $this->projectId, 'state' => $state] + $options);
|
||||
return $this->info;
|
||||
}
|
||||
/**
|
||||
* Delete the HMAC Key.
|
||||
*
|
||||
* Key state must be set to `INACTIVE` prior to deletion. See
|
||||
* {@see HmacKey::update()} for details.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $hmacKey->delete();
|
||||
* ```
|
||||
*
|
||||
* @param array $options {
|
||||
* Configuration Options
|
||||
*
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request. **NOTE**: This option is
|
||||
* currently ignored by Cloud Storage.
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
public function delete(array $options = [])
|
||||
{
|
||||
$this->connection->deleteHmacKey(['accessId' => $this->accessId, 'projectId' => $this->projectId] + $options);
|
||||
}
|
||||
}
|
||||
357
vendor/Gcp/google/cloud-storage/src/Lifecycle.php
vendored
Normal file
357
vendor/Gcp/google/cloud-storage/src/Lifecycle.php
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2018 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Timestamp;
|
||||
/**
|
||||
* Object Lifecycle Management supports common use cases like setting a Time to
|
||||
* Live (TTL) for objects, archiving older versions of objects, or "downgrading"
|
||||
* storage classes of objects to help manage costs.
|
||||
*
|
||||
* This builder does not execute any network requests and is intended to be used
|
||||
* in combination with either
|
||||
* {@see StorageClient::createBucket()}
|
||||
* or {@see Bucket::update()}.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* // Access a builder preconfigured with rules already existing on a given
|
||||
* // bucket.
|
||||
* use Google\Cloud\Storage\StorageClient;
|
||||
*
|
||||
* $storage = new StorageClient();
|
||||
* $bucket = $storage->bucket('my-bucket');
|
||||
* $lifecycle = $bucket->currentLifecycle();
|
||||
* ```
|
||||
*
|
||||
* ```
|
||||
* // Or get a fresh builder by using the static factory method.
|
||||
* use Google\Cloud\Storage\Bucket;
|
||||
*
|
||||
* $lifecycle = Bucket::lifecycle();
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/lifecycle Object Lifecycle Management API Documentation
|
||||
*/
|
||||
class Lifecycle implements \ArrayAccess, \IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $lifecycle;
|
||||
/**
|
||||
* @param array $lifecycle [optional] A lifecycle configuration. Please see
|
||||
* [here](https://cloud.google.com/storage/docs/json_api/v1/buckets#lifecycle)
|
||||
* for the expected structure.
|
||||
*/
|
||||
public function __construct(array $lifecycle = [])
|
||||
{
|
||||
$this->lifecycle = $lifecycle;
|
||||
}
|
||||
/**
|
||||
* Adds an Object Lifecycle Delete Rule.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $lifecycle->addDeleteRule([
|
||||
* 'age' => 50,
|
||||
* 'isLive' => true
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @param array $condition {
|
||||
* The condition(s) where the rule will apply.
|
||||
*
|
||||
* @type int $age Age of an object (in days). This condition is
|
||||
* satisfied when an object reaches the specified age.
|
||||
* @type \DateTimeInterface|string $createdBefore This condition is
|
||||
* satisfied when an object is created before midnight of the
|
||||
* specified date in UTC. If a string is given, it must be a date
|
||||
* in RFC 3339 format with only the date part (for instance,
|
||||
* "2013-01-15").
|
||||
* @type \DateTimeInterface|string $customTimeBefore This condition is
|
||||
* satisfied when the custom time on an object is before this date
|
||||
* in UTC. If a string is given, it must be a date in RFC 3339
|
||||
* format with only the date part (for instance, "2013-01-15").
|
||||
* @type int $daysSinceCustomTime Number of days elapsed since the
|
||||
* user-specified timestamp set on an object. The condition is
|
||||
* satisfied if the days elapsed is at least this number. If no
|
||||
* custom timestamp is specified on an object, the condition does
|
||||
* not apply.
|
||||
* @type int $daysSinceNoncurrentTime Number of days elapsed since the
|
||||
* noncurrent timestamp of an object. The condition is satisfied
|
||||
* if the days elapsed is at least this number. This condition is
|
||||
* relevant only for versioned objects. The value of the field
|
||||
* must be a nonnegative integer. If it's zero, the object version
|
||||
* will become eligible for Lifecycle action as soon as it becomes
|
||||
* noncurrent.
|
||||
* @type bool $isLive Relevant only for versioned objects. If the value
|
||||
* is `true`, this condition matches live objects; if the value is
|
||||
* `false`, it matches archived objects.
|
||||
* @type string[] $matchesStorageClass Objects having any of the storage
|
||||
* classes specified by this condition will be matched. Values
|
||||
* include `"MULTI_REGIONAL"`, `"REGIONAL"`, `"NEARLINE"`,
|
||||
* `"ARCHIVE"`, `"COLDLINE"`, `"STANDARD"`, and
|
||||
* `"DURABLE_REDUCED_AVAILABILITY"`.
|
||||
* @type \DateTimeInterface|string $noncurrentTimeBefore This condition
|
||||
* is satisfied when the noncurrent time on an object is before
|
||||
* this timestamp. This condition is relevant only for versioned
|
||||
* objects. If a string is given, it must be a date in RFC 3339
|
||||
* format with only the date part (for instance, "2013-01-15").
|
||||
* @type int $numNewerVersions Relevant only for versioned objects. If
|
||||
* the value is N, this condition is satisfied when there are at
|
||||
* least N versions (including the live version) newer than this
|
||||
* version of the object.
|
||||
* @type string[] $matchesPrefix Objects having names which start with
|
||||
* values specified by this condition will be matched.
|
||||
* @type string[] $matchesSuffix Objects having names which end with
|
||||
* values specified by this condition will be matched.
|
||||
* }
|
||||
* @return Lifecycle
|
||||
*/
|
||||
public function addDeleteRule(array $condition)
|
||||
{
|
||||
$this->lifecycle['rule'][] = ['action' => ['type' => 'Delete'], 'condition' => $this->formatCondition($condition)];
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Adds an Object Lifecycle Set Storage Class Rule.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $lifecycle->addSetStorageClassRule('COLDLINE', [
|
||||
* 'age' => 50,
|
||||
* 'isLive' => true
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* ```
|
||||
* // Using customTimeBefore rule with an object's custom time setting.
|
||||
* $lifecycle->addSetStorageClassRule('NEARLINE', [
|
||||
* 'customTimeBefore' => (new \DateTime())->add(
|
||||
* \DateInterval::createFromDateString('+10 days')
|
||||
* )
|
||||
* ]);
|
||||
*
|
||||
* $bucket->update(['lifecycle' => $lifecycle]);
|
||||
*
|
||||
* $object = $bucket->object($objectName);
|
||||
* $object->update([
|
||||
* 'metadata' => [
|
||||
* 'customTime' => '2020-08-17'
|
||||
* ]
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @param string $storageClass The target storage class. Values include
|
||||
* `"MULTI_REGIONAL"`, `"REGIONAL"`, `"NEARLINE"`, `"COLDLINE"`,
|
||||
* `"STANDARD"`, and `"DURABLE_REDUCED_AVAILABILITY"`.
|
||||
* @param array $condition {
|
||||
* The condition(s) where the rule will apply.
|
||||
*
|
||||
* @type int $age Age of an object (in days). This condition is
|
||||
* satisfied when an object reaches the specified age.
|
||||
* @type \DateTimeInterface|string $createdBefore This condition is
|
||||
* satisfied when an object is created before midnight of the
|
||||
* specified date in UTC. If a string is given, it must be a date
|
||||
* in RFC 3339 format with only the date part (for instance,
|
||||
* "2013-01-15").
|
||||
* @type \DateTimeInterface|string $customTimeBefore This condition is
|
||||
* satisfied when the custom time on an object is before this date
|
||||
* in UTC. If a string is given, it must be a date in RFC 3339
|
||||
* format with only the date part (for instance, "2013-01-15").
|
||||
* @type int $daysSinceCustomTime Number of days elapsed since the
|
||||
* user-specified timestamp set on an object. The condition is
|
||||
* satisfied if the days elapsed is at least this number. If no
|
||||
* custom timestamp is specified on an object, the condition does
|
||||
* not apply.
|
||||
* @type int $daysSinceNoncurrentTime Number of days elapsed since the
|
||||
* noncurrent timestamp of an object. The condition is satisfied
|
||||
* if the days elapsed is at least this number. This condition is
|
||||
* relevant only for versioned objects. The value of the field
|
||||
* must be a nonnegative integer. If it's zero, the object version
|
||||
* will become eligible for Lifecycle action as soon as it becomes
|
||||
* noncurrent.
|
||||
* @type bool $isLive Relevant only for versioned objects. If the value
|
||||
* is `true`, this condition matches live objects; if the value is
|
||||
* `false`, it matches archived objects.
|
||||
* @type string[] $matchesStorageClass Objects having any of the storage
|
||||
* classes specified by this condition will be matched. Values
|
||||
* include `"MULTI_REGIONAL"`, `"REGIONAL"`, `"NEARLINE"`,
|
||||
* `"ARCHIVE"`, `"COLDLINE"`, `"STANDARD"`, and
|
||||
* `"DURABLE_REDUCED_AVAILABILITY"`.
|
||||
* @type \DateTimeInterface|string $noncurrentTimeBefore This condition
|
||||
* is satisfied when the noncurrent time on an object is before
|
||||
* this timestamp. This condition is relevant only for versioned
|
||||
* objects. If a string is given, it must be a date in RFC 3339
|
||||
* format with only the date part (for instance, "2013-01-15").
|
||||
* @type int $numNewerVersions Relevant only for versioned objects. If
|
||||
* the value is N, this condition is satisfied when there are at
|
||||
* least N versions (including the live version) newer than this
|
||||
* version of the object.
|
||||
* @type string[] $matchesPrefix Objects having names which start with
|
||||
* values specified by this condition will be matched.
|
||||
* @type string[] $matchesSuffix Objects having names which end with
|
||||
* values specified by this condition will be matched.
|
||||
* }
|
||||
* @return Lifecycle
|
||||
*/
|
||||
public function addSetStorageClassRule($storageClass, array $condition)
|
||||
{
|
||||
$this->lifecycle['rule'][] = ['action' => ['type' => 'SetStorageClass', 'storageClass' => $storageClass], 'condition' => $this->formatCondition($condition)];
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Clear all Object Lifecycle rules or rules of a certain action type.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* // Remove all rules.
|
||||
* $lifecycle->clearRules();
|
||||
* ```
|
||||
*
|
||||
* ```
|
||||
* // Remove all "Delete" based rules.
|
||||
* $lifecycle->clearRules('Delete');
|
||||
* ```
|
||||
*
|
||||
* ```
|
||||
* // Clear any rules which have an age equal to 50.
|
||||
* $lifecycle->clearRules(function (array $rule) {
|
||||
* return $rule['condition']['age'] === 50
|
||||
* ? false
|
||||
* : true;
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param string|callable $action [optional] If a string is provided, it
|
||||
* must be the name of the type of rule to remove (`SetStorageClass`
|
||||
* or `Delete`). All rules of this type will then be cleared. When
|
||||
* providing a callable you may define a custom route for how you
|
||||
* would like to remove rules. The provided callable will be run
|
||||
* through
|
||||
* [array_filter](http://php.net/manual/en/function.array-filter.php).
|
||||
* The callable's argument will be a single lifecycle rule as an
|
||||
* associative array. When returning true from the callable the rule
|
||||
* will be preserved, and if false it will be removed.
|
||||
* **Defaults to** `null`, clearing all assigned rules.
|
||||
* @return Lifecycle
|
||||
* @throws \InvalidArgumentException If a type other than a string or
|
||||
* callabe is provided.
|
||||
*/
|
||||
public function clearRules($action = null)
|
||||
{
|
||||
if (!$action) {
|
||||
$this->lifecycle = [];
|
||||
return $this;
|
||||
}
|
||||
if (!\is_string($action) && !\is_callable($action)) {
|
||||
throw new \InvalidArgumentException(\sprintf('Expected either a string or callable, instead got \'%s\'.', \gettype($action)));
|
||||
}
|
||||
if (isset($this->lifecycle['rule'])) {
|
||||
if (\is_string($action)) {
|
||||
$action = function ($rule) use($action) {
|
||||
return $rule['action']['type'] !== $action;
|
||||
};
|
||||
}
|
||||
$this->lifecycle['rule'] = \array_filter($this->lifecycle['rule'], $action);
|
||||
if (!$this->lifecycle['rule']) {
|
||||
$this->lifecycle = [];
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @access private
|
||||
* @return \Generator
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
if (!isset($this->lifecycle['rule'])) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->lifecycle['rule'] as $rule) {
|
||||
(yield $rule);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->lifecycle;
|
||||
}
|
||||
/**
|
||||
* @access private
|
||||
* @param string $offset
|
||||
* @param mixed $value
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->lifecycle['rule'][$offset] = $value;
|
||||
}
|
||||
/**
|
||||
* @access private
|
||||
* @param string $offset
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->lifecycle['rule'][$offset]);
|
||||
}
|
||||
/**
|
||||
* @access private
|
||||
* @param string $offset
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->lifecycle['rule'][$offset]);
|
||||
}
|
||||
/**
|
||||
* @access private
|
||||
* @param string $offset
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return isset($this->lifecycle['rule'][$offset]) ? $this->lifecycle['rule'][$offset] : null;
|
||||
}
|
||||
/**
|
||||
* Apply condition-specific formatting rules (such as date formatting) to
|
||||
* conditions.
|
||||
*
|
||||
* @param array $condition
|
||||
* @return array
|
||||
*/
|
||||
private function formatCondition(array $condition)
|
||||
{
|
||||
$rfc339DateFields = ['createdBefore', 'customTimeBefore', 'noncurrentTimeBefore'];
|
||||
foreach ($rfc339DateFields as $field) {
|
||||
if (isset($condition[$field]) && $condition[$field] instanceof \DateTimeInterface) {
|
||||
$condition[$field] = $condition[$field]->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
return $condition;
|
||||
}
|
||||
}
|
||||
190
vendor/Gcp/google/cloud-storage/src/Notification.php
vendored
Normal file
190
vendor/Gcp/google/cloud-storage/src/Notification.php
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\ArrayTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Exception\NotFoundException;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||
/**
|
||||
* Cloud Pub/Sub Notifications sends information about changes to objects in
|
||||
* your buckets to Google Cloud Pub/Sub, where the information is added to a
|
||||
* Cloud Pub/Sub topic of your choice in the form of messages. For example,
|
||||
* you can track objects that are created and deleted in your bucket. Each
|
||||
* notification contains information describing both the event that triggered it
|
||||
* and the object that changed.
|
||||
*
|
||||
* To utilize this class and see more examples, please see the relevant
|
||||
* notifications based methods exposed on {@see Bucket}.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* use Google\Cloud\Storage\StorageClient;
|
||||
*
|
||||
* $storage = new StorageClient();
|
||||
*
|
||||
* // Fetch an existing notification by ID.
|
||||
* $bucket = $storage->bucket('my-bucket');
|
||||
* $notification = $bucket->notification('2482');
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/pubsub-notifications
|
||||
* @experimental The experimental flag means that while we believe this method
|
||||
* or class is ready for use, it may change before release in backwards-
|
||||
* incompatible ways. Please use with caution, and test thoroughly when
|
||||
* upgrading.
|
||||
*/
|
||||
class Notification
|
||||
{
|
||||
use ArrayTrait;
|
||||
/**
|
||||
* @var ConnectionInterface Represents a connection to Cloud Storage.
|
||||
* @internal
|
||||
*/
|
||||
private $connection;
|
||||
/**
|
||||
* @var array The notification's identity.
|
||||
*/
|
||||
private $identity;
|
||||
/**
|
||||
* @var array The notification's metadata.
|
||||
*/
|
||||
private $info;
|
||||
/**
|
||||
* @param ConnectionInterface $connection Represents a connection to Cloud
|
||||
* Storage. This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param string $id The notification's ID.
|
||||
* @param string $bucket The name of the bucket associated with this
|
||||
* notification.
|
||||
* @param array $info [optional] The notification's metadata.
|
||||
*/
|
||||
public function __construct(ConnectionInterface $connection, $id, $bucket, array $info = [])
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->identity = ['bucket' => $bucket, 'notification' => $id, 'userProject' => $this->pluck('requesterProjectId', $info, \false)];
|
||||
$this->info = $info;
|
||||
}
|
||||
/**
|
||||
* Check whether or not the notification exists.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* if ($notification->exists()) {
|
||||
* echo 'Notification exists!';
|
||||
* }
|
||||
* ```
|
||||
* @param array $options [optional] {
|
||||
* Configuration options.
|
||||
* }
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(array $options = [])
|
||||
{
|
||||
try {
|
||||
$this->connection->getNotification($options + $this->identity + ['fields' => 'id']);
|
||||
} catch (NotFoundException $ex) {
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Delete the notification.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $notification->delete();
|
||||
* ```
|
||||
*
|
||||
* @codingStandardsIgnoreStart
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/notifications/delete Notifications delete API documentation.
|
||||
* @codingStandardsIgnoreEnd
|
||||
*
|
||||
* @param array $options [optional]
|
||||
* @return void
|
||||
*/
|
||||
public function delete(array $options = [])
|
||||
{
|
||||
$this->connection->deleteNotification($options + $this->identity);
|
||||
}
|
||||
/**
|
||||
* Retrieves the notification's details. If no notification data is cached a
|
||||
* network request will be made to retrieve it.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $info = $notification->info();
|
||||
* echo $info['topic'];
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/notifications/get Notifications get API documentation.
|
||||
*
|
||||
* @param array $options [optional]
|
||||
* @return array
|
||||
*/
|
||||
public function info(array $options = [])
|
||||
{
|
||||
return $this->info ?: $this->reload($options);
|
||||
}
|
||||
/**
|
||||
* Triggers a network request to reload the notification's details.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $notification->reload();
|
||||
* $info = $notification->info();
|
||||
* echo $info['topic'];
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/notifications/get Notifications get API documentation.
|
||||
*
|
||||
* @param array $options [optional]
|
||||
* @return array
|
||||
*/
|
||||
public function reload(array $options = [])
|
||||
{
|
||||
return $this->info = $this->connection->getNotification($options + $this->identity);
|
||||
}
|
||||
/**
|
||||
* Retrieves the notification's ID.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* echo $notification->id();
|
||||
* ```
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id()
|
||||
{
|
||||
return $this->identity['notification'];
|
||||
}
|
||||
/**
|
||||
* Retrieves the notification's identity.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* echo $notification->identity()['bucket'];
|
||||
* ```
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function identity()
|
||||
{
|
||||
return $this->identity;
|
||||
}
|
||||
}
|
||||
39
vendor/Gcp/google/cloud-storage/src/ObjectIterator.php
vendored
Normal file
39
vendor/Gcp/google/cloud-storage/src/ObjectIterator.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Iterator\ItemIteratorTrait;
|
||||
/**
|
||||
* ObjectIterator
|
||||
*
|
||||
* Iterates over a set of {@see StorageObject} items.
|
||||
*/
|
||||
class ObjectIterator implements \Iterator
|
||||
{
|
||||
use ItemIteratorTrait;
|
||||
/**
|
||||
* Gets a list of prefixes of objects matching-but-not-listed up to and
|
||||
* including the requested delimiter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prefixes()
|
||||
{
|
||||
return \method_exists($this->pageIterator, 'prefixes') ? $this->pageIterator->prefixes() : [];
|
||||
}
|
||||
}
|
||||
73
vendor/Gcp/google/cloud-storage/src/ObjectPageIterator.php
vendored
Normal file
73
vendor/Gcp/google/cloud-storage/src/ObjectPageIterator.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Iterator\PageIteratorTrait;
|
||||
/**
|
||||
* ObjectPageIterator
|
||||
*
|
||||
* Iterates over a set of pages containing
|
||||
* {@see StorageObject} items.
|
||||
*/
|
||||
class ObjectPageIterator implements \Iterator
|
||||
{
|
||||
use PageIteratorTrait;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $prefixes = [];
|
||||
/**
|
||||
* Gets a list of prefixes of objects matching-but-not-listed up to and
|
||||
* including the requested delimiter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prefixes()
|
||||
{
|
||||
return $this->prefixes;
|
||||
}
|
||||
/**
|
||||
* Get the current page.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
{
|
||||
if (!$this->page) {
|
||||
$this->page = $this->executeCall();
|
||||
}
|
||||
if (isset($this->page['prefixes'])) {
|
||||
$this->updatePrefixes();
|
||||
}
|
||||
return $this->get($this->itemsPath, $this->page);
|
||||
}
|
||||
/**
|
||||
* Add new prefixes to the list.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function updatePrefixes()
|
||||
{
|
||||
foreach ($this->page['prefixes'] as $prefix) {
|
||||
if (!\in_array($prefix, $this->prefixes)) {
|
||||
$this->prefixes[] = $prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
vendor/Gcp/google/cloud-storage/src/ReadStream.php
vendored
Normal file
86
vendor/Gcp/google/cloud-storage/src/ReadStream.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\StreamInterface;
|
||||
/**
|
||||
* A Stream implementation that wraps a GuzzleHttp download stream to
|
||||
* provide `getSize()` from the response headers.
|
||||
*/
|
||||
class ReadStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
private $stream;
|
||||
/**
|
||||
* Create a new ReadStream.
|
||||
*
|
||||
* @param StreamInterface $stream The stream interface to wrap
|
||||
*/
|
||||
public function __construct(StreamInterface $stream)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
}
|
||||
/**
|
||||
* Return the full size of the buffer. If the underlying stream does
|
||||
* not report it's size, try to fetch the size from the Content-Length
|
||||
* response header.
|
||||
*
|
||||
* @return int The size of the stream.
|
||||
*/
|
||||
public function getSize() : ?int
|
||||
{
|
||||
return $this->stream->getSize() ?: $this->getSizeFromMetadata();
|
||||
}
|
||||
/**
|
||||
* Attempt to fetch the size from the Content-Length response header.
|
||||
* If we cannot, return 0.
|
||||
*
|
||||
* @return int The Size of the stream
|
||||
*/
|
||||
private function getSizeFromMetadata() : int
|
||||
{
|
||||
foreach ($this->stream->getMetadata('wrapper_data') as $value) {
|
||||
if (\substr($value, 0, 15) == "Content-Length:") {
|
||||
return (int) \substr($value, 16);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Read bytes from the underlying buffer, retrying until we have read
|
||||
* enough bytes or we cannot read any more. We do this because the
|
||||
* internal C code for filling a buffer does not account for when
|
||||
* we try to read large chunks from a user-land stream that does not
|
||||
* return enough bytes.
|
||||
*
|
||||
* @param int $length The number of bytes to read.
|
||||
* @return string Read bytes from the underlying stream.
|
||||
*/
|
||||
public function read($length) : string
|
||||
{
|
||||
$data = '';
|
||||
do {
|
||||
$moreData = $this->stream->read($length);
|
||||
$data .= $moreData;
|
||||
$readLength = \strlen($moreData);
|
||||
$length -= $readLength;
|
||||
} while ($length > 0 && $readLength > 0);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
622
vendor/Gcp/google/cloud-storage/src/SigningHelper.php
vendored
Normal file
622
vendor/Gcp/google/cloud-storage/src/SigningHelper.php
vendored
Normal file
@@ -0,0 +1,622 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\CredentialsLoader;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\SignBlobInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\ArrayTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\JsonTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Timestamp;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||
/**
|
||||
* Provides common methods for signing storage URLs.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SigningHelper
|
||||
{
|
||||
use ArrayTrait;
|
||||
use JsonTrait;
|
||||
const DEFAULT_URL_SIGNING_VERSION = 'v2';
|
||||
const DEFAULT_DOWNLOAD_HOST = 'storage.googleapis.com';
|
||||
const V4_ALGO_NAME = 'GOOG4-RSA-SHA256';
|
||||
const V4_TIMESTAMP_FORMAT = 'DeliciousBrains\\WP_Offload_Media\\Gcp\\Ymd\\THis\\Z';
|
||||
const V4_DATESTAMP_FORMAT = 'Ymd';
|
||||
/**
|
||||
* Create or fetch a SigningHelper instance.
|
||||
*
|
||||
* @return SigningHelper
|
||||
*/
|
||||
public static function getHelper()
|
||||
{
|
||||
static $helper;
|
||||
if (!$helper) {
|
||||
$helper = new static();
|
||||
}
|
||||
return $helper;
|
||||
}
|
||||
/**
|
||||
* Sign using the version inferred from `$options.version`.
|
||||
*
|
||||
* @param ConnectionInterface $connection A connection to the Cloud Storage
|
||||
* API. This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param Timestamp|\DateTimeInterface|int $expires The signed URL
|
||||
* expiration.
|
||||
* @param string $resource The URI to the storage resource, preceded by a
|
||||
* leading slash.
|
||||
* @param int|null $generation The resource generation.
|
||||
* @param array $options Configuration options. See
|
||||
* {@see StorageObject::signedUrl()} for
|
||||
* details.
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException If required data could not be gathered from
|
||||
* credentials.
|
||||
* @throws \RuntimeException If OpenSSL signing is required by user input
|
||||
* and OpenSSL is not available.
|
||||
*/
|
||||
public function sign(ConnectionInterface $connection, $expires, $resource, $generation, array $options)
|
||||
{
|
||||
$version = $options['version'] ?? self::DEFAULT_URL_SIGNING_VERSION;
|
||||
unset($options['version']);
|
||||
switch (\strtolower($version)) {
|
||||
case 'v2':
|
||||
$method = 'v2Sign';
|
||||
break;
|
||||
case 'v4':
|
||||
$method = 'v4Sign';
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException('Invalid signing version.');
|
||||
}
|
||||
return \call_user_func_array([$this, $method], [$connection, $expires, $resource, $generation, $options]);
|
||||
}
|
||||
/**
|
||||
* Sign a URL using Google Signed URLs v2.
|
||||
*
|
||||
* This method will be deprecated in the future.
|
||||
*
|
||||
* @param ConnectionInterface $connection A connection to the Cloud Storage
|
||||
* API. This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param Timestamp|\DateTimeInterface|int $expires The signed URL
|
||||
* expiration.
|
||||
* @param string $resource The URI to the storage resource, preceded by a
|
||||
* leading slash.
|
||||
* @param int|null $generation The resource generation.
|
||||
* @param array $options Configuration options. See
|
||||
* {@see StorageObject::signedUrl()} for
|
||||
* details.
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException If required data could not be gathered from
|
||||
* credentials.
|
||||
* @throws \RuntimeException If OpenSSL signing is required by user input
|
||||
* and OpenSSL is not available.
|
||||
*/
|
||||
public function v2Sign(ConnectionInterface $connection, $expires, $resource, $generation, array $options)
|
||||
{
|
||||
list($credentials, $options) = $this->getSigningCredentials($connection, $options);
|
||||
$expires = $this->normalizeExpiration($expires);
|
||||
list($resource, $bucket) = $this->normalizeResource($resource);
|
||||
$options = $this->normalizeOptions($options);
|
||||
$headers = $this->normalizeHeaders($options['headers']);
|
||||
if ($options['virtualHostedStyle']) {
|
||||
$options['bucketBoundHostname'] = \sprintf('%s.storage.googleapis.com', $bucket);
|
||||
}
|
||||
// Make sure disallowed headers are not included.
|
||||
$illegalHeaders = ['x-goog-encryption-key', 'x-goog-encryption-key-sha256'];
|
||||
if ($illegal = \array_intersect_key(\array_flip($illegalHeaders), $headers)) {
|
||||
throw new \InvalidArgumentException(\sprintf('%s %s not allowed in Signed URL headers.', \implode(' and ', \array_keys($illegal)), \count($illegal) === 1 ? 'is' : 'are'));
|
||||
}
|
||||
// Sort headers by name.
|
||||
\ksort($headers);
|
||||
$toSign = [$options['method'], $options['contentMd5'], $options['contentType'], $expires];
|
||||
$signedHeaders = [];
|
||||
foreach ($headers as $name => $value) {
|
||||
$signedHeaders[] = $name . ':' . $value;
|
||||
}
|
||||
// Push the headers onto the end of the signing string.
|
||||
if ($signedHeaders) {
|
||||
$toSign = \array_merge($toSign, $signedHeaders);
|
||||
}
|
||||
$toSign[] = $resource;
|
||||
$stringToSign = $this->createV2CanonicalRequest($toSign);
|
||||
$signature = $credentials->signBlob($stringToSign, ['forceOpenssl' => $options['forceOpenssl']]);
|
||||
// Start with user-provided query params and add required parameters.
|
||||
$params = $options['queryParams'];
|
||||
$params['GoogleAccessId'] = $credentials->getClientName();
|
||||
$params['Expires'] = $expires;
|
||||
$params['Signature'] = $signature;
|
||||
// urlencode parameter values
|
||||
foreach ($params as &$value) {
|
||||
$value = \rawurlencode($value);
|
||||
}
|
||||
$params = $this->addCommonParams($generation, $params, $options);
|
||||
$queryString = $this->buildQueryString($params);
|
||||
$resource = $this->normalizeUriPath($options['bucketBoundHostname'], $resource);
|
||||
return 'https://' . $options['bucketBoundHostname'] . $resource . '?' . $queryString;
|
||||
}
|
||||
/**
|
||||
* Sign a storage URL using Google Signed URLs v4.
|
||||
*
|
||||
* @param ConnectionInterface $connection A connection to the Cloud Storage
|
||||
* API. This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param Timestamp|\DateTimeInterface|int $expires The signed URL
|
||||
* expiration.
|
||||
* @param string $resource The URI to the storage resource, preceded by a
|
||||
* leading slash.
|
||||
* @param int|null $generation The resource generation.
|
||||
* @param array $options Configuration options. See
|
||||
* {@see StorageObject::signedUrl()} for
|
||||
* details.
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException If required data could not be gathered from
|
||||
* credentials.
|
||||
* @throws \RuntimeException If OpenSSL signing is required by user input
|
||||
* and OpenSSL is not available.
|
||||
*/
|
||||
public function v4Sign(ConnectionInterface $connection, $expires, $resource, $generation, array $options)
|
||||
{
|
||||
list($credentials, $options) = $this->getSigningCredentials($connection, $options);
|
||||
$expires = $this->normalizeExpiration($expires);
|
||||
list($resource, $bucket) = $this->normalizeResource($resource);
|
||||
$options = $this->normalizeOptions($options);
|
||||
$time = $options['timestamp'];
|
||||
$requestTimestamp = $time->format(self::V4_TIMESTAMP_FORMAT);
|
||||
$requestDatestamp = $time->format(self::V4_DATESTAMP_FORMAT);
|
||||
$timeSeconds = $time->format('U');
|
||||
$expireLimit = $timeSeconds + 604800;
|
||||
if ($expires > $expireLimit) {
|
||||
throw new \InvalidArgumentException('V4 Signed URLs may not have an expiration greater than seven days in the future.');
|
||||
}
|
||||
$clientEmail = $credentials->getClientName();
|
||||
$credentialScope = \sprintf('%s/auto/storage/goog4_request', $requestDatestamp);
|
||||
$credential = \sprintf('%s/%s', $clientEmail, $credentialScope);
|
||||
if ($options['virtualHostedStyle']) {
|
||||
$options['bucketBoundHostname'] = \sprintf('%s.storage.googleapis.com', $bucket);
|
||||
}
|
||||
// Add headers and query params based on provided options.
|
||||
$params = $options['queryParams'];
|
||||
$headers = $options['headers'] + ['host' => $options['bucketBoundHostname']];
|
||||
if ($options['contentType']) {
|
||||
$headers['content-type'] = $options['contentType'];
|
||||
}
|
||||
if ($options['contentMd5']) {
|
||||
$headers['content-md5'] = $options['contentMd5'];
|
||||
}
|
||||
$params = $this->addCommonParams($generation, $params, $options);
|
||||
$headers = $this->normalizeHeaders($headers);
|
||||
// sort headers by name
|
||||
\ksort($headers, \SORT_NATURAL | \SORT_FLAG_CASE);
|
||||
// Canonical headers are a list, newline separated, of keys and values,
|
||||
// comma separated.
|
||||
// Signed headers are a list of keys, separated by a semicolon.
|
||||
$canonicalHeaders = [];
|
||||
$signedHeaders = [];
|
||||
foreach ($headers as $key => $val) {
|
||||
$canonicalHeaders[] = \sprintf('%s:%s', $key, $val);
|
||||
$signedHeaders[] = $key;
|
||||
}
|
||||
$canonicalHeaders = \implode("\n", $canonicalHeaders) . "\n";
|
||||
$signedHeaders = \implode(';', $signedHeaders);
|
||||
// Add required query parameters.
|
||||
$params = ['X-Goog-Algorithm' => self::V4_ALGO_NAME, 'X-Goog-Credential' => $credential, 'X-Goog-Date' => $requestTimestamp, 'X-Goog-Expires' => $expires - $timeSeconds, 'X-Goog-SignedHeaders' => $signedHeaders] + $params;
|
||||
$paramNames = [];
|
||||
foreach ($params as $key => $val) {
|
||||
$paramNames[] = $key;
|
||||
}
|
||||
\sort($paramNames, \SORT_REGULAR);
|
||||
$sortedParams = [];
|
||||
foreach ($paramNames as $name) {
|
||||
$sortedParams[\rawurlencode($name)] = \rawurlencode($params[$name]);
|
||||
}
|
||||
$canonicalQueryString = $this->buildQueryString($sortedParams);
|
||||
$canonicalResource = $this->normalizeCanonicalRequestResource($resource, $options['bucketBoundHostname'], $options['virtualHostedStyle']);
|
||||
$canonicalRequest = [$options['method'], $canonicalResource, $canonicalQueryString, $canonicalHeaders, $signedHeaders, $this->getPayloadHash($headers)];
|
||||
$requestHash = $this->createV4CanonicalRequest($canonicalRequest);
|
||||
// Construct the string to sign.
|
||||
$stringToSign = \implode("\n", [self::V4_ALGO_NAME, $requestTimestamp, $credentialScope, $requestHash]);
|
||||
$signature = \bin2hex(\base64_decode($credentials->signBlob($stringToSign, ['forceOpenssl' => $options['forceOpenssl']])));
|
||||
// Construct the modified resource name. If a custom hostname is provided,
|
||||
// this will remove the bucket name from the resource.
|
||||
$resource = $this->normalizeUriPath($options['bucketBoundHostname'], $resource);
|
||||
$scheme = $this->chooseScheme($options['scheme'], $options['bucketBoundHostname'], $options['virtualHostedStyle']);
|
||||
return \sprintf('%s://%s%s?%s&X-Goog-Signature=%s', $scheme, $options['bucketBoundHostname'], $resource, $canonicalQueryString, $signature);
|
||||
}
|
||||
/**
|
||||
* Create an HTTP POST policy using v4 signing.
|
||||
*
|
||||
* @param ConnectionInterface $connection A Connection to Google Cloud Storage.
|
||||
* This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param Timestamp|\DateTimeInterface|int $expires The signed URL
|
||||
* expiration.
|
||||
* @param string $resource The URI to the storage resource, preceded by a
|
||||
* leading slash.
|
||||
* @param array $options Configuration options. See
|
||||
* {@see Bucket::generateSignedPostPolicyV4()} for details.
|
||||
* @return array An associative array, containing (string) `uri` and
|
||||
* (array) `fields` keys.
|
||||
*/
|
||||
public function v4PostPolicy(ConnectionInterface $connection, $expires, $resource, array $options = [])
|
||||
{
|
||||
list($credentials, $options) = $this->getSigningCredentials($connection, $options);
|
||||
$expires = $this->normalizeExpiration($expires);
|
||||
list($resource, $bucket, $object) = $this->normalizeResource($resource, \false);
|
||||
$object = \trim($object, '/');
|
||||
$options = $this->normalizeOptions($options) + ['fields' => [], 'conditions' => [], 'successActionRedirect' => null, 'successActionStatus' => null];
|
||||
$time = $options['timestamp'];
|
||||
$requestTimestamp = $time->format(self::V4_TIMESTAMP_FORMAT);
|
||||
$requestDatestamp = $time->format(self::V4_DATESTAMP_FORMAT);
|
||||
$expiration = \DateTimeImmutable::createFromFormat('U', (string) $expires);
|
||||
$expirationTimestamp = \str_replace('+00:00', 'Z', $expiration->format(\DateTime::RFC3339));
|
||||
$clientEmail = $credentials->getClientName();
|
||||
$credentialScope = \sprintf('%s/auto/storage/goog4_request', $requestDatestamp);
|
||||
$credential = \sprintf('%s/%s', $clientEmail, $credentialScope);
|
||||
if ($options['virtualHostedStyle']) {
|
||||
$options['bucketBoundHostname'] = \sprintf('%s.storage.googleapis.com', $bucket);
|
||||
}
|
||||
$fields = \array_merge($options['fields'], ['key' => $object, 'x-goog-algorithm' => self::V4_ALGO_NAME, 'x-goog-credential' => $credential, 'x-goog-date' => $requestTimestamp]);
|
||||
$conditions = $options['conditions'];
|
||||
foreach ($options['fields'] as $key => $value) {
|
||||
$conditions[] = [$key => $value];
|
||||
}
|
||||
foreach ($conditions as $key => $value) {
|
||||
$key = $key;
|
||||
$value = $value;
|
||||
$conditions[$key] = $value;
|
||||
}
|
||||
$conditions = \array_merge($conditions, [['bucket' => $bucket], ['key' => $object], ['x-goog-date' => $requestTimestamp], ['x-goog-credential' => $credential], ['x-goog-algorithm' => self::V4_ALGO_NAME]]);
|
||||
$policy = ['conditions' => $conditions, 'expiration' => $expirationTimestamp];
|
||||
$json = \str_replace('\\\\u', '\\u', \json_encode($policy, \JSON_UNESCAPED_SLASHES));
|
||||
$stringToSign = \base64_encode($json);
|
||||
$signature = \bin2hex(\base64_decode($credentials->signBlob($stringToSign, ['forceOpenssl' => $options['forceOpenssl']])));
|
||||
$fields['x-goog-signature'] = $signature;
|
||||
$fields['policy'] = $stringToSign;
|
||||
// Construct the modified resource name. If a custom hostname is provided,
|
||||
// this will remove the bucket name from the resource.
|
||||
$resource = $this->normalizeUriPath($options['bucketBoundHostname'], '/' . $bucket, \true);
|
||||
$scheme = $this->chooseScheme($options['scheme'], $options['bucketBoundHostname'], $options['virtualHostedStyle']);
|
||||
return ['url' => \sprintf('%s://%s%s', $scheme, $options['bucketBoundHostname'], $resource), 'fields' => $fields];
|
||||
}
|
||||
/**
|
||||
* Creates a canonical request hash for a V4 Signed URL.
|
||||
*
|
||||
* NOTE: While in most cases `PHP_EOL` is preferable to a system-specific
|
||||
* character, in this case `\n` is required.
|
||||
*
|
||||
* @param array $canonicalRequest The canonical request, with each element
|
||||
* representing a line in the request.
|
||||
* @return string
|
||||
*/
|
||||
private function createV4CanonicalRequest(array $canonicalRequest)
|
||||
{
|
||||
$canonicalRequestString = \implode("\n", $canonicalRequest);
|
||||
return \bin2hex(\hash('sha256', $canonicalRequestString, \true));
|
||||
}
|
||||
/**
|
||||
* Creates a canonical request for a V2 Signed URL.
|
||||
*
|
||||
* NOTE: While in most cases `PHP_EOL` is preferable to a system-specific
|
||||
* character, in this case `\n` is required.
|
||||
*
|
||||
* @param array $canonicalRequest The canonical request, with each element
|
||||
* representing a line in the request.
|
||||
* @return string
|
||||
*/
|
||||
private function createV2CanonicalRequest(array $canonicalRequest)
|
||||
{
|
||||
return \implode("\n", $canonicalRequest);
|
||||
}
|
||||
/**
|
||||
* Choose the correct URL scheme.
|
||||
*
|
||||
* @param string $scheme The scheme provided by the user or defaults.
|
||||
* @param string $bucketBoundHostname The bucketBoundHostname provided by the user or defaults.
|
||||
* @param bool $virtualHostedStyle Whether virtual host style is enabled.
|
||||
* @return string
|
||||
*/
|
||||
private function chooseScheme($scheme, $bucketBoundHostname, $virtualHostedStyle = \false)
|
||||
{
|
||||
// bucketBoundHostname not used -- always https.
|
||||
if ($bucketBoundHostname === self::DEFAULT_DOWNLOAD_HOST) {
|
||||
return 'https';
|
||||
}
|
||||
// virtualHostedStyle enabled -- always https.
|
||||
if ($virtualHostedStyle) {
|
||||
return 'https';
|
||||
}
|
||||
// not virtual hosted style, and custom hostname -- use default (http) or user choice.
|
||||
return $scheme;
|
||||
}
|
||||
/**
|
||||
* If `X-Goog-Content-SHA256` header is provided, use that as the payload.
|
||||
* Otherwise, `UNSIGNED-PAYLOAD`.
|
||||
*
|
||||
* @param array $headers
|
||||
* @return string
|
||||
*/
|
||||
private function getPayloadHash(array $headers)
|
||||
{
|
||||
if (!isset($headers['x-goog-content-sha256'])) {
|
||||
return 'UNSIGNED-PAYLOAD';
|
||||
}
|
||||
return $headers['x-goog-content-sha256'];
|
||||
}
|
||||
/**
|
||||
* Normalizes and validates an expiration.
|
||||
*
|
||||
* @param Timestamp|\DateTimeInterface|int $expires The expiration
|
||||
* @return int
|
||||
* @throws \InvalidArgumentException If an invalid value is given.
|
||||
*/
|
||||
private function normalizeExpiration($expires)
|
||||
{
|
||||
if ($expires instanceof Timestamp) {
|
||||
$seconds = $expires->get()->format('U');
|
||||
} elseif ($expires instanceof \DateTimeInterface) {
|
||||
$seconds = $expires->format('U');
|
||||
} elseif (\is_numeric($expires)) {
|
||||
$seconds = (int) $expires;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Invalid expiration.');
|
||||
}
|
||||
return $seconds;
|
||||
}
|
||||
/**
|
||||
* Normalizes and encodes the resource identifier.
|
||||
*
|
||||
* @param string $resource The resource identifier. In form
|
||||
* `[/]$bucket/$object`.
|
||||
* @return array A list, where index 0 is the resource path, with pieces
|
||||
* encoded and prefixed with a forward slash, index 1 is the bucket
|
||||
* name, and index 2 is the object name, relative to the bucket.
|
||||
*/
|
||||
private function normalizeResource($resource, $urlencode = \true)
|
||||
{
|
||||
$pieces = \explode('/', \trim($resource, '/'));
|
||||
if ($urlencode) {
|
||||
\array_walk($pieces, function (&$piece) {
|
||||
$piece = \rawurlencode($piece);
|
||||
});
|
||||
}
|
||||
$bucket = $pieces[0];
|
||||
$relative = $pieces;
|
||||
\array_shift($relative);
|
||||
return ['/' . \implode('/', $pieces), $bucket, '/' . \implode('/', $relative)];
|
||||
}
|
||||
/**
|
||||
* Fixes the user input options, filters and validates data.
|
||||
*
|
||||
* @param array $options Signed URL configuration options.
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function normalizeOptions(array $options)
|
||||
{
|
||||
$options += [
|
||||
'allowPost' => \false,
|
||||
'cname' => null,
|
||||
//@deprecated
|
||||
'bucketBoundHostname' => self::DEFAULT_DOWNLOAD_HOST,
|
||||
'contentMd5' => null,
|
||||
'contentType' => null,
|
||||
'forceOpenssl' => \false,
|
||||
'headers' => [],
|
||||
'keyFile' => null,
|
||||
'keyFilePath' => null,
|
||||
'method' => 'GET',
|
||||
'queryParams' => [],
|
||||
'responseDisposition' => null,
|
||||
'responseType' => null,
|
||||
'saveAsName' => null,
|
||||
// note that in almost every case this default will be overridden.
|
||||
'scheme' => 'http',
|
||||
'timestamp' => null,
|
||||
'virtualHostedStyle' => \false,
|
||||
];
|
||||
$allowedMethods = ['GET', 'PUT', 'POST', 'DELETE'];
|
||||
$options['method'] = \strtoupper($options['method']);
|
||||
if (!\in_array($options['method'], $allowedMethods)) {
|
||||
throw new \InvalidArgumentException('$options.method must be one of `GET`, `PUT` or `DELETE`.');
|
||||
}
|
||||
if ($options['method'] === 'POST' && !$options['allowPost']) {
|
||||
throw new \InvalidArgumentException('Invalid method. To create an upload URI, use StorageObject::signedUploadUrl().');
|
||||
}
|
||||
// Rewrite deprecated `cname` to new `bucketBoundHostname`.
|
||||
if ($options['cname'] && $options['bucketBoundHostname'] === self::DEFAULT_DOWNLOAD_HOST) {
|
||||
$options['bucketBoundHostname'] = $options['cname'];
|
||||
}
|
||||
// strip protocol from hostname.
|
||||
$hostnameParts = \explode('//', $options['bucketBoundHostname']);
|
||||
if (\count($hostnameParts) > 1) {
|
||||
$options['bucketBoundHostname'] = $hostnameParts[1];
|
||||
}
|
||||
$options['bucketBoundHostname'] = \trim($options['bucketBoundHostname'], '/');
|
||||
// If a timestamp is provided, use it in place of `now` for v4 URLs only..
|
||||
// This option exists for testing purposes, and should not generally be provided by users.
|
||||
if ($options['timestamp']) {
|
||||
if (!$options['timestamp'] instanceof \DateTimeInterface) {
|
||||
if (!\is_string($options['timestamp'])) {
|
||||
throw new \InvalidArgumentException('User-provided timestamps must be a string or instance of `\\DateTimeInterface`.');
|
||||
}
|
||||
$options['timestamp'] = \DateTimeImmutable::createFromFormat(\DateTime::RFC3339, $options['timestamp'], new \DateTimeZone('UTC'));
|
||||
if (!$options['timestamp']) {
|
||||
throw new \InvalidArgumentException('Given timestamp string is in an invalid format. Provide timestamp formatted as follows: `' . \DateTime::RFC3339 . '`. Note that timestamps MUST be in UTC.');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$options['timestamp'] = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
|
||||
}
|
||||
unset($options['cname'], $options['allowPost']);
|
||||
return $options;
|
||||
}
|
||||
/**
|
||||
* Cleans and normalizes header values.
|
||||
*
|
||||
* Arrays of values are collapsed into a comma-separated list, trailing and
|
||||
* leading spaces are removed, newlines are replaced by empty strings, and
|
||||
* multiple whitespace chars are replaced by a single space.
|
||||
*
|
||||
* @param array $headers Input headers
|
||||
* @return array
|
||||
*/
|
||||
private function normalizeHeaders(array $headers)
|
||||
{
|
||||
$out = [];
|
||||
foreach ($headers as $name => $value) {
|
||||
$name = \strtolower(\trim($name));
|
||||
// collapse arrays of values into a comma-separated list.
|
||||
if (!\is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
foreach ($value as &$headerValue) {
|
||||
// strip trailing and leading spaces.
|
||||
$headerValue = \trim($headerValue);
|
||||
// replace newlines with empty strings.
|
||||
$headerValue = \str_replace(\PHP_EOL, '', $headerValue);
|
||||
// collapse multiple whitespace chars to a single space.
|
||||
$headerValue = \preg_replace('/[\\s]+/', ' ', $headerValue);
|
||||
}
|
||||
$out[$name] = \implode(', ', $value);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
/**
|
||||
* Returns a resource formatted for use in a URI.
|
||||
*
|
||||
* If the bucketBoundHostname is other than the default, will omit the bucket name.
|
||||
*
|
||||
* @param string $bucketBoundHostname The bucketBoundHostname provided by the user, or the default
|
||||
* value.
|
||||
* @param string $resource The GCS resource path (i.e. /bucket/object).
|
||||
* @return string
|
||||
*/
|
||||
private function normalizeUriPath($bucketBoundHostname, $resource, $withTrailingSlash = \false)
|
||||
{
|
||||
if ($bucketBoundHostname !== self::DEFAULT_DOWNLOAD_HOST) {
|
||||
$resourceParts = \explode('/', \trim($resource, '/'));
|
||||
\array_shift($resourceParts);
|
||||
// Resource is a Bucket.
|
||||
if (empty($resourceParts)) {
|
||||
$resource = '/';
|
||||
} else {
|
||||
$resource = '/' . \implode('/', $resourceParts);
|
||||
}
|
||||
}
|
||||
$resource = \rtrim($resource, '/');
|
||||
return $withTrailingSlash ? $resource . '/' : $resource;
|
||||
}
|
||||
/**
|
||||
* Normalize the resource provided to the canonical request string.
|
||||
*
|
||||
* @param string $resource
|
||||
* @param string $bucketBoundHostname
|
||||
* @param boolean $virtualHostedStyle
|
||||
* @return string
|
||||
*/
|
||||
private function normalizeCanonicalRequestResource($resource, $bucketBoundHostname, $virtualHostedStyle = \false)
|
||||
{
|
||||
if ($bucketBoundHostname === self::DEFAULT_DOWNLOAD_HOST && !$virtualHostedStyle) {
|
||||
return $resource;
|
||||
}
|
||||
$pieces = \explode('/', \trim($resource, '/'));
|
||||
\array_shift($pieces);
|
||||
return '/' . \implode('/', $pieces);
|
||||
}
|
||||
/**
|
||||
* Get the credentials for use with signing.
|
||||
*
|
||||
* @param ConnectionInterface $connection A Storage connection object.
|
||||
* This object is created by StorageClient,
|
||||
* and should not be instantiated outside of this client.
|
||||
* @param array $options Configuration options.
|
||||
* @return array A list containing a credentials object at index 0 and the
|
||||
* modified options at index 1.
|
||||
* @throws \RuntimeException If the credentials type is not valid for signing.
|
||||
* @throws \InvalidArgumentException If a keyfile is given and is not valid.
|
||||
*/
|
||||
private function getSigningCredentials(ConnectionInterface $connection, array $options)
|
||||
{
|
||||
$keyFilePath = $options['keyFilePath'] ?? null;
|
||||
if ($keyFilePath) {
|
||||
if (!\file_exists($keyFilePath)) {
|
||||
throw new \InvalidArgumentException(\sprintf('Keyfile path %s does not exist.', $keyFilePath));
|
||||
}
|
||||
$options['keyFile'] = self::jsonDecode(\file_get_contents($keyFilePath), \true);
|
||||
}
|
||||
$rw = $connection->requestWrapper();
|
||||
$keyFile = $options['keyFile'] ?? null;
|
||||
if ($keyFile) {
|
||||
$scopes = $options['scopes'] ?? $rw->scopes();
|
||||
$credentials = CredentialsLoader::makeCredentials($scopes, $keyFile);
|
||||
} else {
|
||||
$credentials = $rw->getCredentialsFetcher();
|
||||
}
|
||||
//@codeCoverageIgnoreStart
|
||||
if (!$credentials instanceof SignBlobInterface) {
|
||||
throw new \RuntimeException(\sprintf('Credentials object is of type `%s` and is not valid for signing.', \get_class($credentials)));
|
||||
}
|
||||
//@codeCoverageIgnoreEnd
|
||||
unset($options['keyFilePath'], $options['keyFile'], $options['scopes']);
|
||||
return [$credentials, $options];
|
||||
}
|
||||
/**
|
||||
* Add parameters common to all signed URL versions.
|
||||
*
|
||||
* @param int|null $generation
|
||||
* @param array $params
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
private function addCommonParams($generation, array $params, array $options)
|
||||
{
|
||||
if ($options['responseType']) {
|
||||
$params['response-content-type'] = $options['responseType'];
|
||||
}
|
||||
if ($options['responseDisposition']) {
|
||||
$params['response-content-disposition'] = $options['responseDisposition'];
|
||||
} elseif ($options['saveAsName']) {
|
||||
$params['response-content-disposition'] = 'attachment; filename=' . '"' . $options['saveAsName'] . '"';
|
||||
}
|
||||
if ($generation) {
|
||||
$params['generation'] = $generation;
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
/**
|
||||
* Create a query string from an array.
|
||||
*
|
||||
* Note that this method does NOT urlencode keys or values.
|
||||
*
|
||||
* @param array $input
|
||||
* @return string
|
||||
*/
|
||||
private function buildQueryString(array $input)
|
||||
{
|
||||
$q = [];
|
||||
foreach ($input as $key => $val) {
|
||||
$q[] = $key . '=' . $val;
|
||||
}
|
||||
return \implode('&', $q);
|
||||
}
|
||||
}
|
||||
528
vendor/Gcp/google/cloud-storage/src/StorageClient.php
vendored
Normal file
528
vendor/Gcp/google/cloud-storage/src/StorageClient.php
vendored
Normal file
@@ -0,0 +1,528 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\FetchAuthTokenInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\ArrayTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\ClientTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Exception\GoogleException;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Iterator\ItemIterator;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Iterator\PageIterator;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Timestamp;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Upload\SignedUrlUploader;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Connection\Rest;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Cache\CacheItemPoolInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\StreamInterface;
|
||||
/**
|
||||
* Google Cloud Storage allows you to store and retrieve data on Google's
|
||||
* infrastructure. Find more information at the
|
||||
* [Google Cloud Storage API docs](https://developers.google.com/storage).
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* use Google\Cloud\Storage\StorageClient;
|
||||
*
|
||||
* $storage = new StorageClient();
|
||||
* ```
|
||||
*/
|
||||
class StorageClient
|
||||
{
|
||||
use ArrayTrait;
|
||||
use ClientTrait;
|
||||
const VERSION = '1.39.0';
|
||||
const FULL_CONTROL_SCOPE = 'https://www.googleapis.com/auth/devstorage.full_control';
|
||||
const READ_ONLY_SCOPE = 'https://www.googleapis.com/auth/devstorage.read_only';
|
||||
const READ_WRITE_SCOPE = 'https://www.googleapis.com/auth/devstorage.read_write';
|
||||
/**
|
||||
* Retry strategy to signify that we never want to retry an operation
|
||||
* even if the error is retryable.
|
||||
*
|
||||
* We can set $options['retryStrategy'] to one of "always", "never" and
|
||||
* "idempotent".
|
||||
*/
|
||||
const RETRY_NEVER = 'never';
|
||||
/**
|
||||
* Retry strategy to signify that we always want to retry an operation.
|
||||
*/
|
||||
const RETRY_ALWAYS = 'always';
|
||||
/**
|
||||
* This is the default. This signifies that we want to retry an operation
|
||||
* only if it is retryable and the error is retryable.
|
||||
*/
|
||||
const RETRY_IDEMPOTENT = 'idempotent';
|
||||
/**
|
||||
* @var ConnectionInterface Represents a connection to Storage.
|
||||
* @internal
|
||||
*/
|
||||
protected $connection;
|
||||
/**
|
||||
* Create a Storage client.
|
||||
*
|
||||
* @param array $config [optional] {
|
||||
* Configuration options.
|
||||
*
|
||||
* @type string $apiEndpoint The hostname with optional port to use in
|
||||
* place of the default service endpoint. Example:
|
||||
* `foobar.com` or `foobar.com:1234`.
|
||||
* @type string $projectId The project ID from the Google Developer's
|
||||
* Console.
|
||||
* @type CacheItemPoolInterface $authCache A cache used storing access
|
||||
* tokens. **Defaults to** a simple in memory implementation.
|
||||
* @type array $authCacheOptions Cache configuration options.
|
||||
* @type callable $authHttpHandler A handler used to deliver Psr7
|
||||
* requests specifically for authentication.
|
||||
* @type FetchAuthTokenInterface $credentialsFetcher A credentials
|
||||
* fetcher instance.
|
||||
* @type callable $httpHandler A handler used to deliver Psr7 requests.
|
||||
* Only valid for requests sent over REST.
|
||||
* @type array $keyFile The contents of the service account credentials
|
||||
* .json file retrieved from the Google Developer's Console.
|
||||
* Ex: `json_decode(file_get_contents($path), true)`.
|
||||
* @type string $keyFilePath The full path to your service account
|
||||
* credentials .json file retrieved from the Google Developers
|
||||
* Console.
|
||||
* @type float $requestTimeout Seconds to wait before timing out the
|
||||
* request. **Defaults to** `0` with REST and `60` with gRPC.
|
||||
* @type int $retries Number of retries for a failed request.
|
||||
* **Defaults to** `3`.
|
||||
* @type array $scopes Scopes to be used for the request.
|
||||
* @type string $quotaProject Specifies a user project to bill for
|
||||
* access charges associated with the request.
|
||||
* }
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
if (!isset($config['scopes'])) {
|
||||
$config['scopes'] = ['https://www.googleapis.com/auth/iam', self::FULL_CONTROL_SCOPE];
|
||||
}
|
||||
$this->connection = new Rest($this->configureAuthentication($config) + ['projectId' => $this->projectId]);
|
||||
}
|
||||
/**
|
||||
* Lazily instantiates a bucket.
|
||||
*
|
||||
* There are no network requests made at this point. To see the operations
|
||||
* that can be performed on a bucket please see {@see Bucket}.
|
||||
*
|
||||
* If `$userProject` is set to true, the current project ID (used to
|
||||
* instantiate the client) will be billed for all requests. If
|
||||
* `$userProject` is a project ID, given as a string, that project
|
||||
* will be billed for all requests. This only has an effect when the bucket
|
||||
* is not owned by the current or given project ID.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $bucket = $storage->bucket('my-bucket');
|
||||
* ```
|
||||
*
|
||||
* @param string $name The name of the bucket to request.
|
||||
* @param string|bool $userProject If true, the current Project ID
|
||||
* will be used. If a string, that string will be used as the
|
||||
* userProject argument, and that project will be billed for the
|
||||
* request. **Defaults to** `false`.
|
||||
* @return Bucket
|
||||
*/
|
||||
public function bucket($name, $userProject = \false)
|
||||
{
|
||||
if (!$userProject) {
|
||||
$userProject = null;
|
||||
} elseif (!\is_string($userProject)) {
|
||||
$userProject = $this->projectId;
|
||||
}
|
||||
return new Bucket($this->connection, $name, ['requesterProjectId' => $userProject]);
|
||||
}
|
||||
/**
|
||||
* Fetches all buckets in the project.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $buckets = $storage->buckets();
|
||||
* ```
|
||||
*
|
||||
* ```
|
||||
* // Get all buckets beginning with the prefix 'album'.
|
||||
* $buckets = $storage->buckets([
|
||||
* 'prefix' => 'album'
|
||||
* ]);
|
||||
*
|
||||
* foreach ($buckets as $bucket) {
|
||||
* echo $bucket->name() . PHP_EOL;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/list Buckets list API documentation.
|
||||
*
|
||||
* @param array $options [optional] {
|
||||
* Configuration options.
|
||||
*
|
||||
* @type int $maxResults Maximum number of results to return per
|
||||
* requested page.
|
||||
* @type int $resultLimit Limit the number of results returned in total.
|
||||
* **Defaults to** `0` (return all results).
|
||||
* @type string $pageToken A previously-returned page token used to
|
||||
* resume the loading of results from a specific point.
|
||||
* @type string $prefix Filter results with this prefix.
|
||||
* @type string $projection Determines which properties to return. May
|
||||
* be either 'full' or 'noAcl'.
|
||||
* @type string $fields Selector which will cause the response to only
|
||||
* return the specified fields.
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request.
|
||||
* @type bool $bucketUserProject If true, each returned instance will
|
||||
* have `$userProject` set to the value of `$options.userProject`.
|
||||
* If false, `$options.userProject` will be used ONLY for the
|
||||
* listBuckets operation. If `$options.userProject` is not set,
|
||||
* this option has no effect. **Defaults to** `true`.
|
||||
* }
|
||||
* @return ItemIterator<Bucket>
|
||||
* @throws GoogleException When a project ID has not been detected.
|
||||
*/
|
||||
public function buckets(array $options = [])
|
||||
{
|
||||
$this->requireProjectId();
|
||||
$resultLimit = $this->pluck('resultLimit', $options, \false);
|
||||
$bucketUserProject = $this->pluck('bucketUserProject', $options, \false);
|
||||
$bucketUserProject = !\is_null($bucketUserProject) ? $bucketUserProject : \true;
|
||||
$userProject = isset($options['userProject']) && $bucketUserProject ? $options['userProject'] : null;
|
||||
return new ItemIterator(new PageIterator(function (array $bucket) use($userProject) {
|
||||
return new Bucket($this->connection, $bucket['name'], $bucket + ['requesterProjectId' => $userProject]);
|
||||
}, [$this->connection, 'listBuckets'], $options + ['project' => $this->projectId], ['resultLimit' => $resultLimit]));
|
||||
}
|
||||
/**
|
||||
* Create a bucket. Bucket names must be unique as Cloud Storage uses a flat
|
||||
* namespace. For more information please see
|
||||
* [bucket name requirements](https://cloud.google.com/storage/docs/naming#requirements)
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $bucket = $storage->createBucket('bucket');
|
||||
* ```
|
||||
*
|
||||
* ```
|
||||
* // Create a bucket with logging enabled.
|
||||
* $bucket = $storage->createBucket('myBeautifulBucket', [
|
||||
* 'logging' => [
|
||||
* 'logBucket' => 'bucketToLogTo',
|
||||
* 'logObjectPrefix' => 'myPrefix'
|
||||
* ]
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/insert Buckets insert API documentation.
|
||||
*
|
||||
* @param string $name Name of the bucket to be created.
|
||||
* @codingStandardsIgnoreStart
|
||||
* @param array $options [optional] {
|
||||
* Configuration options.
|
||||
*
|
||||
* @type string $predefinedAcl Predefined ACL to apply to the bucket.
|
||||
* Acceptable values include, `"authenticatedRead"`,
|
||||
* `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
|
||||
* `"projectPrivate"`, and `"publicRead"`.
|
||||
* @type string $predefinedDefaultObjectAcl Apply a predefined set of
|
||||
* default object access controls to this bucket.
|
||||
* @type bool $enableObjectRetention Whether object retention should
|
||||
* be enabled on this bucket. For more information, refer to the
|
||||
* [Object Retention Lock](https://cloud.google.com/storage/docs/object-lock)
|
||||
* documentation.
|
||||
* @type string $projection Determines which properties to return. May
|
||||
* be either `"full"` or `"noAcl"`. **Defaults to** `"noAcl"`,
|
||||
* unless the bucket resource specifies acl or defaultObjectAcl
|
||||
* properties, when it defaults to `"full"`.
|
||||
* @type string $fields Selector which will cause the response to only
|
||||
* return the specified fields.
|
||||
* @type array $acl Access controls on the bucket.
|
||||
* @type array $cors The bucket's Cross-Origin Resource Sharing (CORS)
|
||||
* configuration.
|
||||
* @type array $defaultObjectAcl Default access controls to apply to new
|
||||
* objects when no ACL is provided.
|
||||
* @type array|Lifecycle $lifecycle The bucket's lifecycle configuration.
|
||||
* @type string $location The location of the bucket. If specifying
|
||||
* a dual-region, the `customPlacementConfig` property should be
|
||||
* set in conjunction. For more information, see
|
||||
* [Bucket Locations](https://cloud.google.com/storage/docs/locations).
|
||||
* **Defaults to** `"US"`.
|
||||
* @type array $customPlacementConfig The bucket's dual regions. For more
|
||||
* information, see
|
||||
* [Bucket Locations](https://cloud.google.com/storage/docs/locations).
|
||||
* @type array $logging The bucket's logging configuration, which
|
||||
* defines the destination bucket and optional name prefix for the
|
||||
* current bucket's logs.
|
||||
* @type string $storageClass The bucket's storage class. This defines
|
||||
* how objects in the bucket are stored and determines the SLA and
|
||||
* the cost of storage. Acceptable values include the following
|
||||
* strings: `"STANDARD"`, `"NEARLINE"`, `"COLDLINE"` and
|
||||
* `"ARCHIVE"`. Legacy values including `"MULTI_REGIONAL"`,
|
||||
* `"REGIONAL"` and `"DURABLE_REDUCED_AVAILABILITY"` are also
|
||||
* available, but should be avoided for new implementations. For
|
||||
* more information, refer to the
|
||||
* [Storage Classes](https://cloud.google.com/storage/docs/storage-classes)
|
||||
* documentation. **Defaults to** `"STANDARD"`.
|
||||
* @type array $autoclass The bucket's autoclass configuration.
|
||||
* Buckets can have either StorageClass OLM rules or Autoclass,
|
||||
* but not both. When Autoclass is enabled on a bucket, adding
|
||||
* StorageClass OLM rules will result in failure.
|
||||
* For more information, refer to
|
||||
* [Storage Autoclass](https://cloud.google.com/storage/docs/autoclass)
|
||||
* @type array $versioning The bucket's versioning configuration.
|
||||
* @type array $website The bucket's website configuration.
|
||||
* @type array $billing The bucket's billing configuration.
|
||||
* @type bool $billing.requesterPays When `true`, requests to this bucket
|
||||
* and objects within it must provide a project ID to which the
|
||||
* request will be billed.
|
||||
* @type array $labels The Bucket labels. Labels are represented as an
|
||||
* array of keys and values. To remove an existing label, set its
|
||||
* value to `null`.
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request.
|
||||
* @type bool $bucketUserProject If true, the returned instance will
|
||||
* have `$userProject` set to the value of `$options.userProject`.
|
||||
* If false, `$options.userProject` will be used ONLY for the
|
||||
* createBucket operation. If `$options.userProject` is not set,
|
||||
* this option has no effect. **Defaults to** `true`.
|
||||
* @type array $encryption Encryption configuration used by default for
|
||||
* newly inserted objects.
|
||||
* @type string $encryption.defaultKmsKeyName A Cloud KMS Key used to
|
||||
* encrypt objects uploaded into this bucket. Should be in the
|
||||
* format
|
||||
* `projects/my-project/locations/kr-location/keyRings/my-kr/cryptoKeys/my-key`.
|
||||
* Please note the KMS key ring must use the same location as the
|
||||
* bucket.
|
||||
* @type bool $defaultEventBasedHold When `true`, newly created objects
|
||||
* in this bucket will be retained indefinitely until an event
|
||||
* occurs, signified by the hold's release.
|
||||
* @type array $retentionPolicy Defines the retention policy for a
|
||||
* bucket. In order to lock a retention policy, please see
|
||||
* {@see Bucket::lockRetentionPolicy()}.
|
||||
* @type int $retentionPolicy.retentionPeriod Specifies the retention
|
||||
* period for objects in seconds. During the retention period an
|
||||
* object cannot be overwritten or deleted. Retention period must
|
||||
* be greater than zero and less than 100 years.
|
||||
* @type array $iamConfiguration The bucket's IAM configuration.
|
||||
* @type bool $iamConfiguration.bucketPolicyOnly.enabled this is an alias
|
||||
* for $iamConfiguration.uniformBucketLevelAccess.
|
||||
* @type bool $iamConfiguration.uniformBucketLevelAccess.enabled If set and
|
||||
* true, access checks only use bucket-level IAM policies or
|
||||
* above. When enabled, requests attempting to view or manipulate
|
||||
* ACLs will fail with error code 400. **NOTE**: Before using
|
||||
* Uniform bucket-level access, please review the
|
||||
* [feature documentation](https://cloud.google.com/storage/docs/uniform-bucket-level-access),
|
||||
* as well as
|
||||
* [Should You Use uniform bucket-level access](https://cloud.google.com/storage/docs/uniform-bucket-level-access#should-you-use)
|
||||
* @type string $rpo Specifies the Turbo Replication setting for a dual-region bucket.
|
||||
* The possible values are DEFAULT and ASYNC_TURBO. Trying to set the rpo for a non dual-region
|
||||
* bucket will throw an exception. Non existence of this parameter is equivalent to it being DEFAULT.
|
||||
* }
|
||||
* @codingStandardsIgnoreEnd
|
||||
* @return Bucket
|
||||
* @throws GoogleException When a project ID has not been detected.
|
||||
*/
|
||||
public function createBucket($name, array $options = [])
|
||||
{
|
||||
$this->requireProjectId();
|
||||
if (isset($options['lifecycle']) && $options['lifecycle'] instanceof Lifecycle) {
|
||||
$options['lifecycle'] = $options['lifecycle']->toArray();
|
||||
}
|
||||
$bucketUserProject = $this->pluck('bucketUserProject', $options, \false);
|
||||
$bucketUserProject = !\is_null($bucketUserProject) ? $bucketUserProject : \true;
|
||||
$userProject = isset($options['userProject']) && $bucketUserProject ? $options['userProject'] : null;
|
||||
$response = $this->connection->insertBucket($options + ['name' => $name, 'project' => $this->projectId]);
|
||||
return new Bucket($this->connection, $name, $response + ['requesterProjectId' => $userProject]);
|
||||
}
|
||||
/**
|
||||
* Registers this StorageClient as the handler for stream reading/writing.
|
||||
*
|
||||
* @param string $protocol The name of the protocol to use. **Defaults to** `gs`.
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function registerStreamWrapper($protocol = null)
|
||||
{
|
||||
return StreamWrapper::register($this, $protocol);
|
||||
}
|
||||
/**
|
||||
* Unregisters the SteamWrapper
|
||||
*
|
||||
* @param string $protocol The name of the protocol to unregister. **Defaults to** `gs`.
|
||||
*/
|
||||
public function unregisterStreamWrapper($protocol = null)
|
||||
{
|
||||
StreamWrapper::unregister($protocol);
|
||||
}
|
||||
/**
|
||||
* Create an uploader to handle a Signed URL.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $uploader = $storage->signedUrlUploader($uri, fopen('/path/to/myfile.doc', 'r'));
|
||||
* ```
|
||||
*
|
||||
* @param string $uri The URI to accept an upload request.
|
||||
* @param string|resource|StreamInterface $data The data to be uploaded
|
||||
* @param array $options [optional] Configuration Options. Refer to
|
||||
* {@see \Google\Cloud\Core\Upload\AbstractUploader::__construct()}.
|
||||
* @return SignedUrlUploader
|
||||
*/
|
||||
public function signedUrlUploader($uri, $data, array $options = [])
|
||||
{
|
||||
return new SignedUrlUploader($this->connection->requestWrapper(), $data, $uri, $options);
|
||||
}
|
||||
/**
|
||||
* Create a Timestamp object.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $timestamp = $storage->timestamp(new \DateTime('2003-02-05 11:15:02.421827Z'));
|
||||
* ```
|
||||
*
|
||||
* @param \DateTimeInterface $timestamp The timestamp value.
|
||||
* @param int $nanoSeconds [optional] The number of nanoseconds in the timestamp.
|
||||
* @return Timestamp
|
||||
*/
|
||||
public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null)
|
||||
{
|
||||
return new Timestamp($timestamp, $nanoSeconds);
|
||||
}
|
||||
/**
|
||||
* Get the service account email associated with this client.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $serviceAccount = $storage->getServiceAccount();
|
||||
* ```
|
||||
*
|
||||
* @param array $options [optional] {
|
||||
* Configuration options.
|
||||
*
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request.
|
||||
* }
|
||||
* @return string
|
||||
*/
|
||||
public function getServiceAccount(array $options = [])
|
||||
{
|
||||
$resp = $this->connection->getServiceAccount($options + ['projectId' => $this->projectId]);
|
||||
return $resp['email_address'];
|
||||
}
|
||||
/**
|
||||
* List Service Account HMAC keys in the project.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $hmacKeys = $storage->hmacKeys();
|
||||
* ```
|
||||
*
|
||||
* ```
|
||||
* // Get the HMAC keys associated with a Service Account email
|
||||
* $hmacKeys = $storage->hmacKeys([
|
||||
* 'serviceAccountEmail' => $serviceAccountEmail
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @param array $options {
|
||||
* Configuration Options
|
||||
*
|
||||
* @type string $serviceAccountEmail If present, only keys for the given
|
||||
* service account are returned.
|
||||
* @type bool $showDeletedKeys Whether or not to show keys in the
|
||||
* DELETED state.
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request.
|
||||
* @type string $projectId The project ID to use, if different from that
|
||||
* with which the client was created.
|
||||
* }
|
||||
* @return ItemIterator<HmacKey>
|
||||
*/
|
||||
public function hmacKeys(array $options = [])
|
||||
{
|
||||
$options += ['projectId' => $this->projectId];
|
||||
if (!$options['projectId']) {
|
||||
$this->requireProjectId();
|
||||
}
|
||||
$resultLimit = $this->pluck('resultLimit', $options, \false);
|
||||
return new ItemIterator(new PageIterator(function (array $metadata) use($options) {
|
||||
return $this->hmacKey($metadata['accessId'], $options['projectId'], $metadata);
|
||||
}, [$this->connection, 'listHmacKeys'], $options, ['resultLimit' => $resultLimit]));
|
||||
}
|
||||
/**
|
||||
* Lazily instantiate an HMAC Key instance using an Access ID.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $hmacKey = $storage->hmacKey($accessId);
|
||||
* ```
|
||||
*
|
||||
* @param string $accessId The ID of the HMAC Key.
|
||||
* @param string $projectId [optional] The project ID to use, if different
|
||||
* from that with which the client was created.
|
||||
* @param array $metadata [optional] HMAC key metadata.
|
||||
* @return HmacKey
|
||||
*/
|
||||
public function hmacKey($accessId, $projectId = null, array $metadata = [])
|
||||
{
|
||||
if (!$projectId) {
|
||||
$this->requireProjectId();
|
||||
}
|
||||
return new HmacKey($this->connection, $projectId ?: $this->projectId, $accessId, $metadata);
|
||||
}
|
||||
/**
|
||||
* Creates a new HMAC key for the specified service account.
|
||||
*
|
||||
* Please note that the HMAC secret is only available at creation. Make sure
|
||||
* to note the secret after creation.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* $response = $storage->createHmacKey('account@myProject.iam.gserviceaccount.com');
|
||||
* $secret = $response->secret();
|
||||
* ```
|
||||
*
|
||||
* @param string $serviceAccountEmail Email address of the service account.
|
||||
* @param array $options {
|
||||
* Configuration Options
|
||||
*
|
||||
* @type string $userProject If set, this is the ID of the project which
|
||||
* will be billed for the request. **NOTE**: This option is
|
||||
* currently ignored by Cloud Storage.
|
||||
* @type string $projectId The project ID to use, if different from that
|
||||
* with which the client was created.
|
||||
* }
|
||||
* @return CreatedHmacKey
|
||||
*/
|
||||
public function createHmacKey($serviceAccountEmail, array $options = [])
|
||||
{
|
||||
$options += ['projectId' => $this->projectId];
|
||||
if (!$options['projectId']) {
|
||||
$this->requireProjectId();
|
||||
}
|
||||
$res = $this->connection->createHmacKey(['projectId' => $options['projectId'], 'serviceAccountEmail' => $serviceAccountEmail] + $options);
|
||||
$key = new HmacKey($this->connection, $options['projectId'], $res['metadata']['accessId'], $res['metadata']);
|
||||
return new CreatedHmacKey($key, $res['secret']);
|
||||
}
|
||||
/**
|
||||
* Throw an exception if no project ID available.
|
||||
*
|
||||
* @return void
|
||||
* @throws GoogleException
|
||||
*/
|
||||
private function requireProjectId()
|
||||
{
|
||||
if (!$this->projectId) {
|
||||
throw new GoogleException('No project ID was provided, ' . 'and we were unable to detect a default project ID.');
|
||||
}
|
||||
}
|
||||
}
|
||||
1135
vendor/Gcp/google/cloud-storage/src/StorageObject.php
vendored
Normal file
1135
vendor/Gcp/google/cloud-storage/src/StorageObject.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
687
vendor/Gcp/google/cloud-storage/src/StreamWrapper.php
vendored
Normal file
687
vendor/Gcp/google/cloud-storage/src/StreamWrapper.php
vendored
Normal file
@@ -0,0 +1,687 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Exception\NotFoundException;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Exception\ServiceException;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Bucket;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\CachingStream;
|
||||
/**
|
||||
* A streamWrapper implementation for handling `gs://bucket/path/to/file.jpg`.
|
||||
* Note that you can only open a file with mode 'r', 'rb', 'rt', 'w', 'wb', 'wt', 'a', 'ab', or 'at'.
|
||||
*
|
||||
* See: http://php.net/manual/en/class.streamwrapper.php
|
||||
*/
|
||||
class StreamWrapper
|
||||
{
|
||||
const DEFAULT_PROTOCOL = 'gs';
|
||||
const FILE_WRITABLE_MODE = 33206;
|
||||
// 100666 in octal
|
||||
const FILE_READABLE_MODE = 33060;
|
||||
// 100444 in octal
|
||||
const DIRECTORY_WRITABLE_MODE = 16895;
|
||||
// 40777 in octal
|
||||
const DIRECTORY_READABLE_MODE = 16676;
|
||||
// 40444 in octal
|
||||
const TAIL_NAME_SUFFIX = '~';
|
||||
/**
|
||||
* @var resource|null Must be public according to the PHP documentation.
|
||||
*
|
||||
* Contains array of context options in form ['protocol' => ['option' => value]].
|
||||
* Options used by StreamWrapper:
|
||||
*
|
||||
* flush (bool) `true`: fflush() will flush output buffer; `false`: fflush() will do nothing
|
||||
*/
|
||||
public $context;
|
||||
/**
|
||||
* @var \Psr\Http\Message\StreamInterface
|
||||
*/
|
||||
private $stream;
|
||||
/**
|
||||
* @var string Protocol used to open this stream
|
||||
*/
|
||||
private $protocol;
|
||||
/**
|
||||
* @var Bucket Reference to the bucket the opened file
|
||||
* lives in or will live in.
|
||||
*/
|
||||
private $bucket;
|
||||
/**
|
||||
* @var string Name of the file opened by this stream.
|
||||
*/
|
||||
private $file;
|
||||
/**
|
||||
* @var StorageClient[] $clients The default clients to use if using
|
||||
* global methods such as fopen on a stream wrapper. Keyed by protocol.
|
||||
*/
|
||||
private static $clients = [];
|
||||
/**
|
||||
* @var ObjectIterator Used for iterating through a directory
|
||||
*/
|
||||
private $directoryIterator;
|
||||
/**
|
||||
* @var StorageObject
|
||||
*/
|
||||
private $object;
|
||||
/**
|
||||
* @var array Context options passed to stream_open(), used for append mode and flushing.
|
||||
*/
|
||||
private $options = [];
|
||||
/**
|
||||
* @var bool `true`: fflush() will flush output buffer and redirect output to the "tail" object.
|
||||
*/
|
||||
private $flushing = \false;
|
||||
/**
|
||||
* @var string|null Content type for composed object. Will be filled on first composing.
|
||||
*/
|
||||
private $contentType = null;
|
||||
/**
|
||||
* @var bool `true`: writing the "tail" object, next fflush() or fclose() will compose.
|
||||
*/
|
||||
private $composing = \false;
|
||||
/**
|
||||
* @var bool `true`: data has been written to the stream.
|
||||
*/
|
||||
private $dirty = \false;
|
||||
/**
|
||||
* Ensure we close the stream when this StreamWrapper is destroyed.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->stream_close();
|
||||
}
|
||||
/**
|
||||
* Starting PHP 7.4, this is called when include/require is used on a stream.
|
||||
* Absence of this method presents a warning.
|
||||
* https://www.php.net/manual/en/migration74.incompatible.php
|
||||
*/
|
||||
public function stream_set_option()
|
||||
{
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Register a StreamWrapper for reading and writing to Google Storage
|
||||
*
|
||||
* @param StorageClient $client The StorageClient configuration to use.
|
||||
* @param string $protocol The name of the protocol to use. **Defaults to**
|
||||
* `gs`.
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function register(StorageClient $client, $protocol = null)
|
||||
{
|
||||
$protocol = $protocol ?: self::DEFAULT_PROTOCOL;
|
||||
if (!\in_array($protocol, \stream_get_wrappers())) {
|
||||
if (!\stream_wrapper_register($protocol, StreamWrapper::class, \STREAM_IS_URL)) {
|
||||
throw new \RuntimeException("Failed to register '{$protocol}://' protocol");
|
||||
}
|
||||
self::$clients[$protocol] = $client;
|
||||
return \true;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Unregisters the SteamWrapper
|
||||
*
|
||||
* @param string $protocol The name of the protocol to unregister. **Defaults
|
||||
* to** `gs`.
|
||||
*/
|
||||
public static function unregister($protocol = null)
|
||||
{
|
||||
$protocol = $protocol ?: self::DEFAULT_PROTOCOL;
|
||||
\stream_wrapper_unregister($protocol);
|
||||
unset(self::$clients[$protocol]);
|
||||
}
|
||||
/**
|
||||
* Get the default client to use for streams.
|
||||
*
|
||||
* @param string $protocol The name of the protocol to get the client for.
|
||||
* **Defaults to** `gs`.
|
||||
* @return StorageClient
|
||||
*/
|
||||
public static function getClient($protocol = null)
|
||||
{
|
||||
$protocol = $protocol ?: self::DEFAULT_PROTOCOL;
|
||||
return self::$clients[$protocol];
|
||||
}
|
||||
/**
|
||||
* Callback handler for when a stream is opened. For reads, we need to
|
||||
* download the file to see if it can be opened.
|
||||
*
|
||||
* @param string $path The path of the resource to open
|
||||
* @param string $mode The fopen mode. Currently supports ('r', 'rb', 'rt', 'w', 'wb', 'wt', 'a', 'ab', 'at')
|
||||
* @param int $flags Bitwise options STREAM_USE_PATH|STREAM_REPORT_ERRORS|STREAM_MUST_SEEK
|
||||
* @param string $openedPath Will be set to the path on success if STREAM_USE_PATH option is set
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_open($path, $mode, $flags, &$openedPath)
|
||||
{
|
||||
$client = $this->openPath($path);
|
||||
// strip off 'b' or 't' from the mode
|
||||
$mode = \rtrim($mode, 'bt');
|
||||
$options = [];
|
||||
if ($this->context) {
|
||||
$contextOptions = \stream_context_get_options($this->context);
|
||||
if (\array_key_exists($this->protocol, $contextOptions)) {
|
||||
$options = $contextOptions[$this->protocol] ?: [];
|
||||
}
|
||||
if (isset($options['flush'])) {
|
||||
$this->flushing = (bool) $options['flush'];
|
||||
unset($options['flush']);
|
||||
}
|
||||
$this->options = $options;
|
||||
}
|
||||
if ($mode == 'w') {
|
||||
$this->stream = new WriteStream(null, $options);
|
||||
$this->stream->setUploader($this->bucket->getStreamableUploader($this->stream, $options + ['name' => $this->file]));
|
||||
} elseif ($mode == 'a') {
|
||||
try {
|
||||
$info = $this->bucket->object($this->file)->info();
|
||||
$this->composing = $info['size'] > 0;
|
||||
} catch (NotFoundException $e) {
|
||||
}
|
||||
$this->stream = new WriteStream(null, $options);
|
||||
$name = $this->file;
|
||||
if ($this->composing) {
|
||||
$name .= self::TAIL_NAME_SUFFIX;
|
||||
}
|
||||
$this->stream->setUploader($this->bucket->getStreamableUploader($this->stream, $options + ['name' => $name]));
|
||||
} elseif ($mode == 'r') {
|
||||
try {
|
||||
// Lazy read from the source
|
||||
$options['restOptions']['stream'] = \true;
|
||||
$this->stream = new ReadStream($this->bucket->object($this->file)->downloadAsStream($options));
|
||||
// Wrap the response in a caching stream to make it seekable
|
||||
if (!$this->stream->isSeekable() && $flags & \STREAM_MUST_SEEK) {
|
||||
$this->stream = new CachingStream($this->stream);
|
||||
}
|
||||
} catch (ServiceException $ex) {
|
||||
return $this->returnError($ex->getMessage(), $flags);
|
||||
}
|
||||
} else {
|
||||
return $this->returnError('Unknown stream_open mode.', $flags);
|
||||
}
|
||||
if ($flags & \STREAM_USE_PATH) {
|
||||
$openedPath = $path;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Callback handler for when we try to read a certain number of bytes.
|
||||
*
|
||||
* @param int $count The number of bytes to read.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function stream_read($count)
|
||||
{
|
||||
return $this->stream->read($count);
|
||||
}
|
||||
/**
|
||||
* Callback handler for when we try to write data to the stream.
|
||||
*
|
||||
* @param string $data The data to write
|
||||
*
|
||||
* @return int The number of bytes written.
|
||||
*/
|
||||
public function stream_write($data)
|
||||
{
|
||||
$result = $this->stream->write($data);
|
||||
$this->dirty = $this->dirty || (bool) $result;
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* Callback handler for getting data about the stream.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function stream_stat()
|
||||
{
|
||||
$mode = $this->stream->isWritable() ? self::FILE_WRITABLE_MODE : self::FILE_READABLE_MODE;
|
||||
return $this->makeStatArray(['mode' => $mode, 'size' => $this->stream->getSize()]);
|
||||
}
|
||||
/**
|
||||
* Callback handler for checking to see if the stream is at the end of file.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_eof()
|
||||
{
|
||||
return $this->stream->eof();
|
||||
}
|
||||
/**
|
||||
* Callback handler for trying to close the stream.
|
||||
*/
|
||||
public function stream_close()
|
||||
{
|
||||
if (isset($this->stream)) {
|
||||
$this->stream->close();
|
||||
}
|
||||
if ($this->composing) {
|
||||
if ($this->dirty) {
|
||||
$this->compose();
|
||||
$this->dirty = \false;
|
||||
}
|
||||
try {
|
||||
$this->bucket->object($this->file . self::TAIL_NAME_SUFFIX)->delete();
|
||||
} catch (NotFoundException $e) {
|
||||
}
|
||||
$this->composing = \false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Callback handler for trying to seek to a certain location in the stream.
|
||||
*
|
||||
* @param int $offset The stream offset to seek to
|
||||
* @param int $whence Flag for what the offset is relative to. See:
|
||||
* http://php.net/manual/en/streamwrapper.stream-seek.php
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_seek($offset, $whence = \SEEK_SET)
|
||||
{
|
||||
if ($this->stream->isSeekable()) {
|
||||
$this->stream->seek($offset, $whence);
|
||||
return \true;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Callhack handler for inspecting our current position in the stream
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->stream->tell();
|
||||
}
|
||||
/**
|
||||
* Callback handler for trying to close an opened directory.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_closedir()
|
||||
{
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Callback handler for trying to open a directory.
|
||||
*
|
||||
* @param string $path The url directory to open
|
||||
* @param int $options Whether or not to enforce safe_mode
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_opendir($path, $options)
|
||||
{
|
||||
$this->openPath($path);
|
||||
return $this->dir_rewinddir();
|
||||
}
|
||||
/**
|
||||
* Callback handler for reading an entry from a directory handle.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function dir_readdir()
|
||||
{
|
||||
$name = $this->directoryIterator->current();
|
||||
if ($name) {
|
||||
$this->directoryIterator->next();
|
||||
return $name;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Callback handler for rewind the directory handle.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function dir_rewinddir()
|
||||
{
|
||||
try {
|
||||
$iterator = $this->bucket->objects(['prefix' => $this->file, 'fields' => 'items/name,nextPageToken']);
|
||||
// The delimiter options do not give us what we need, so instead we
|
||||
// list all results matching the given prefix, enumerate the
|
||||
// iterator, filter and transform results, and yield a fresh
|
||||
// generator containing only the directory listing.
|
||||
$this->directoryIterator = \call_user_func(function () use($iterator) {
|
||||
$yielded = [];
|
||||
$pathLen = \strlen($this->makeDirectory($this->file));
|
||||
foreach ($iterator as $object) {
|
||||
$name = \substr($object->name(), $pathLen);
|
||||
$parts = \explode('/', $name);
|
||||
// since the service call returns nested results and we only
|
||||
// want to yield results directly within the requested directory,
|
||||
// check if we've already yielded this value.
|
||||
if ($parts[0] === "" || \in_array($parts[0], $yielded)) {
|
||||
continue;
|
||||
}
|
||||
$yielded[] = $parts[0];
|
||||
(yield $name => $parts[0]);
|
||||
}
|
||||
});
|
||||
} catch (ServiceException $e) {
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Callback handler for trying to create a directory. If no file path is specified,
|
||||
* or STREAM_MKDIR_RECURSIVE option is set, then create the bucket if it does not exist.
|
||||
*
|
||||
* @param string $path The url directory to create
|
||||
* @param int $mode The permissions on the directory
|
||||
* @param int $options Bitwise mask of options. STREAM_MKDIR_RECURSIVE
|
||||
* @return bool
|
||||
*/
|
||||
public function mkdir($path, $mode, $options)
|
||||
{
|
||||
$path = $this->makeDirectory($path);
|
||||
$client = $this->openPath($path);
|
||||
$predefinedAcl = $this->determineAclFromMode($mode);
|
||||
try {
|
||||
if ($options & \STREAM_MKDIR_RECURSIVE || $this->file == '') {
|
||||
if (!$this->bucket->exists()) {
|
||||
$client->createBucket($this->bucket->name(), ['predefinedAcl' => $predefinedAcl, 'predefinedDefaultObjectAcl' => $predefinedAcl]);
|
||||
}
|
||||
}
|
||||
// If the file name is empty, we were trying to create a bucket. In this case,
|
||||
// don't create the placeholder file.
|
||||
if ($this->file != '') {
|
||||
$bucketInfo = $this->bucket->info();
|
||||
$ublEnabled = isset($bucketInfo['iamConfiguration']['uniformBucketLevelAccess']) && $bucketInfo['iamConfiguration']['uniformBucketLevelAccess']['enabled'] === \true;
|
||||
// if bucket has uniform bucket level access enabled, don't set ACLs.
|
||||
$acl = [];
|
||||
if (!$ublEnabled) {
|
||||
$acl = ['predefinedAcl' => $predefinedAcl];
|
||||
}
|
||||
// Fake a directory by creating an empty placeholder file whose name ends in '/'
|
||||
$this->bucket->upload('', ['name' => $this->file] + $acl);
|
||||
}
|
||||
} catch (ServiceException $e) {
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Callback handler for trying to move a file or directory.
|
||||
*
|
||||
* @param string $from The URL to the current file
|
||||
* @param string $to The URL of the new file location
|
||||
* @return bool
|
||||
*/
|
||||
public function rename($from, $to)
|
||||
{
|
||||
$this->openPath($from);
|
||||
$destination = (array) \parse_url($to) + ['path' => '', 'host' => ''];
|
||||
$destinationBucket = $destination['host'];
|
||||
$destinationPath = \substr($destination['path'], 1);
|
||||
// loop through to rename file and children, if given path is a directory.
|
||||
$objects = $this->bucket->objects(['prefix' => $this->file]);
|
||||
foreach ($objects as $obj) {
|
||||
$oldName = $obj->name();
|
||||
$newPath = \str_replace($this->file, $destinationPath, $oldName);
|
||||
try {
|
||||
$obj->rename($newPath, ['destinationBucket' => $destinationBucket]);
|
||||
} catch (ServiceException $e) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Callback handler for trying to remove a directory or a bucket. If the path is empty
|
||||
* or '/', the bucket will be deleted.
|
||||
*
|
||||
* Note that the STREAM_MKDIR_RECURSIVE flag is ignored because the option cannot
|
||||
* be set via the `rmdir()` function.
|
||||
*
|
||||
* @param string $path The URL directory to remove. If the path is empty or is '/',
|
||||
* This will attempt to destroy the bucket.
|
||||
* @param int $options Bitwise mask of options.
|
||||
* @return bool
|
||||
*/
|
||||
public function rmdir($path, $options)
|
||||
{
|
||||
$path = $this->makeDirectory($path);
|
||||
$this->openPath($path);
|
||||
try {
|
||||
if ($this->file == '') {
|
||||
$this->bucket->delete();
|
||||
return \true;
|
||||
} else {
|
||||
return $this->unlink($path);
|
||||
}
|
||||
} catch (ServiceException $e) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Callback handler for retrieving the underlaying resource
|
||||
*
|
||||
* @param int $castAs STREAM_CAST_FOR_SELECT|STREAM_CAST_AS_STREAM
|
||||
* @return resource|bool
|
||||
*/
|
||||
public function stream_cast($castAs)
|
||||
{
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Callback handler for deleting a file
|
||||
*
|
||||
* @param string $path The URL of the file to delete
|
||||
* @return bool
|
||||
*/
|
||||
public function unlink($path)
|
||||
{
|
||||
$client = $this->openPath($path);
|
||||
$object = $this->bucket->object($this->file);
|
||||
try {
|
||||
$object->delete();
|
||||
return \true;
|
||||
} catch (ServiceException $e) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Callback handler for retrieving information about a file
|
||||
*
|
||||
* @param string $path The URI to the file
|
||||
* @param int $flags Bitwise mask of options
|
||||
* @return array|bool
|
||||
*/
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$client = $this->openPath($path);
|
||||
// if directory
|
||||
$dir = $this->getDirectoryInfo($this->file);
|
||||
if ($dir) {
|
||||
return $this->urlStatDirectory($dir);
|
||||
}
|
||||
return $this->urlStatFile();
|
||||
}
|
||||
/**
|
||||
* Callback handler for fflush() function.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_flush()
|
||||
{
|
||||
if (!$this->flushing) {
|
||||
return \false;
|
||||
}
|
||||
if (!$this->dirty) {
|
||||
return \true;
|
||||
}
|
||||
if (isset($this->stream)) {
|
||||
$this->stream->close();
|
||||
}
|
||||
if ($this->composing) {
|
||||
$this->compose();
|
||||
}
|
||||
$options = $this->options;
|
||||
$this->stream = new WriteStream(null, $options);
|
||||
$this->stream->setUploader($this->bucket->getStreamableUploader($this->stream, $options + ['name' => $this->file . self::TAIL_NAME_SUFFIX]));
|
||||
$this->composing = \true;
|
||||
$this->dirty = \false;
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Parse the URL and set protocol, filename and bucket.
|
||||
*
|
||||
* @param string $path URL to open
|
||||
* @return StorageClient
|
||||
*/
|
||||
private function openPath($path)
|
||||
{
|
||||
$url = (array) \parse_url($path) + ['scheme' => '', 'path' => '', 'host' => ''];
|
||||
$this->protocol = $url['scheme'];
|
||||
$this->file = \ltrim($url['path'], '/');
|
||||
$client = self::getClient($this->protocol);
|
||||
$this->bucket = $client->bucket($url['host']);
|
||||
return $client;
|
||||
}
|
||||
/**
|
||||
* Given a path, ensure that we return a path that looks like a directory
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
private function makeDirectory($path)
|
||||
{
|
||||
if ($path == '' or $path == '/') {
|
||||
return '';
|
||||
}
|
||||
if (\substr($path, -1) == '/') {
|
||||
return $path;
|
||||
}
|
||||
return $path . '/';
|
||||
}
|
||||
/**
|
||||
* Calculate the `url_stat` response for a directory
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
private function urlStatDirectory(StorageObject $object)
|
||||
{
|
||||
$stats = [];
|
||||
$info = $object->info();
|
||||
// equivalent to 40777 and 40444 in octal
|
||||
$stats['mode'] = $this->bucket->isWritable() ? self::DIRECTORY_WRITABLE_MODE : self::DIRECTORY_READABLE_MODE;
|
||||
$this->statsFromFileInfo($info, $stats);
|
||||
return $this->makeStatArray($stats);
|
||||
}
|
||||
/**
|
||||
* Calculate the `url_stat` response for a file
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
private function urlStatFile()
|
||||
{
|
||||
try {
|
||||
$this->object = $this->bucket->object($this->file);
|
||||
$info = $this->object->info();
|
||||
} catch (ServiceException $e) {
|
||||
// couldn't stat file
|
||||
return \false;
|
||||
}
|
||||
// equivalent to 100666 and 100444 in octal
|
||||
$stats = array('mode' => $this->bucket->isWritable() ? self::FILE_WRITABLE_MODE : self::FILE_READABLE_MODE);
|
||||
$this->statsFromFileInfo($info, $stats);
|
||||
return $this->makeStatArray($stats);
|
||||
}
|
||||
/**
|
||||
* Given a `StorageObject` info array, extract the available fields into the
|
||||
* provided `$stats` array.
|
||||
*
|
||||
* @param array $info Array provided from a `StorageObject`.
|
||||
* @param array $stats Array to put the calculated stats into.
|
||||
*/
|
||||
private function statsFromFileInfo(array &$info, array &$stats)
|
||||
{
|
||||
$stats['size'] = isset($info['size']) ? (int) $info['size'] : null;
|
||||
$stats['mtime'] = isset($info['updated']) ? \strtotime($info['updated']) : null;
|
||||
$stats['ctime'] = isset($info['timeCreated']) ? \strtotime($info['timeCreated']) : null;
|
||||
}
|
||||
/**
|
||||
* Get the given path as a directory.
|
||||
*
|
||||
* In list objects calls, directories are returned with a trailing slash. By
|
||||
* providing the given path with a trailing slash as a list prefix, we can
|
||||
* check whether the given path exists as a directory.
|
||||
*
|
||||
* If the path does not exist or is not a directory, return null.
|
||||
*
|
||||
* @param string $path
|
||||
* @return StorageObject|null
|
||||
*/
|
||||
private function getDirectoryInfo($path)
|
||||
{
|
||||
$scan = $this->bucket->objects(['prefix' => $this->makeDirectory($path), 'resultLimit' => 1, 'fields' => 'items/name,items/size,items/updated,items/timeCreated,nextPageToken']);
|
||||
return $scan->current();
|
||||
}
|
||||
/**
|
||||
* Returns the associative array that a `stat()` response expects using the
|
||||
* provided stats. Defaults the remaining fields to 0.
|
||||
*
|
||||
* @param array $stats Sparse stats entries to set.
|
||||
* @return array
|
||||
*/
|
||||
private function makeStatArray($stats)
|
||||
{
|
||||
return \array_merge(\array_fill_keys(['dev', 'ino', 'mode', 'nlink', 'uid', 'gid', 'rdev', 'size', 'atime', 'mtime', 'ctime', 'blksize', 'blocks'], 0), $stats);
|
||||
}
|
||||
/**
|
||||
* Helper for whether or not to trigger an error or just return false on an error.
|
||||
*
|
||||
* @param string $message The PHP error message to emit.
|
||||
* @param int $flags Bitwise mask of options (STREAM_REPORT_ERRORS)
|
||||
* @return bool Returns false
|
||||
*/
|
||||
private function returnError($message, $flags)
|
||||
{
|
||||
if ($flags & \STREAM_REPORT_ERRORS) {
|
||||
\trigger_error($message, \E_USER_WARNING);
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Helper for determining which predefinedAcl to use given a mode.
|
||||
*
|
||||
* @param int $mode Decimal representation of the file system permissions
|
||||
* @return string
|
||||
*/
|
||||
private function determineAclFromMode($mode)
|
||||
{
|
||||
if ($mode & 04) {
|
||||
// If any user can read, assume it should be publicRead.
|
||||
return 'publicRead';
|
||||
} elseif ($mode & 040) {
|
||||
// If any group user can read, assume it should be projectPrivate.
|
||||
return 'projectPrivate';
|
||||
}
|
||||
// Otherwise, assume only the project/bucket owner can use the bucket.
|
||||
return 'private';
|
||||
}
|
||||
private function compose()
|
||||
{
|
||||
if (!isset($this->contentType)) {
|
||||
$info = $this->bucket->object($this->file)->info();
|
||||
$this->contentType = $info['contentType'] ?: 'application/octet-stream';
|
||||
}
|
||||
$options = ['destination' => ['contentType' => $this->contentType]];
|
||||
$this->bucket->compose([$this->file, $this->file . self::TAIL_NAME_SUFFIX], $this->file, $options);
|
||||
}
|
||||
}
|
||||
101
vendor/Gcp/google/cloud-storage/src/WriteStream.php
vendored
Normal file
101
vendor/Gcp/google/cloud-storage/src/WriteStream.php
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Upload\AbstractUploader;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\BufferStream;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\StreamInterface;
|
||||
/**
|
||||
* A Stream implementation that uploads in chunks to a provided uploader when
|
||||
* we reach a certain chunkSize. Upon `close`, we will upload the remaining chunk.
|
||||
*/
|
||||
class WriteStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
private $uploader;
|
||||
private $stream;
|
||||
private $chunkSize = 262144;
|
||||
private $hasWritten = \false;
|
||||
/**
|
||||
* Create a new WriteStream instance
|
||||
*
|
||||
* @param AbstractUploader $uploader The uploader to use.
|
||||
* @param array $options [optional] {
|
||||
* Configuration options.
|
||||
*
|
||||
* @type int $chunkSize The size of the buffer above which we attempt to
|
||||
* upload data
|
||||
* }
|
||||
*/
|
||||
public function __construct(AbstractUploader $uploader = null, $options = [])
|
||||
{
|
||||
if ($uploader) {
|
||||
$this->setUploader($uploader);
|
||||
}
|
||||
if (\array_key_exists('chunkSize', $options)) {
|
||||
$this->chunkSize = $options['chunkSize'];
|
||||
}
|
||||
$this->stream = new BufferStream($this->chunkSize);
|
||||
}
|
||||
/**
|
||||
* Close the stream. Uploads any remaining data.
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
if ($this->uploader && $this->hasWritten) {
|
||||
$this->uploader->upload();
|
||||
$this->uploader = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Write to the stream. If we pass the chunkable size, upload the available chunk.
|
||||
*
|
||||
* @param string $data Data to write
|
||||
* @return int The number of bytes written
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function write($data) : int
|
||||
{
|
||||
if (!isset($this->uploader)) {
|
||||
throw new \RuntimeException("No uploader set.");
|
||||
}
|
||||
// Ensure we have a resume uri here because we need to create the streaming
|
||||
// upload before we have data (size of 0).
|
||||
$this->uploader->getResumeUri();
|
||||
$this->hasWritten = \true;
|
||||
if (!$this->stream->write($data)) {
|
||||
$this->uploader->upload($this->getChunkedWriteSize());
|
||||
}
|
||||
return \strlen($data);
|
||||
}
|
||||
/**
|
||||
* Set the uploader for this class. You may need to set this after initialization
|
||||
* if the uploader depends on this stream.
|
||||
*
|
||||
* @param AbstractUploader $uploader The new uploader to use.
|
||||
*/
|
||||
public function setUploader($uploader) : void
|
||||
{
|
||||
$this->uploader = $uploader;
|
||||
}
|
||||
private function getChunkedWriteSize() : int
|
||||
{
|
||||
return (int) \floor($this->getSize() / $this->chunkSize) * $this->chunkSize;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user