<?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 Google\Cloud\Storage;
use Google\Cloud\Core\ArrayTrait;
use Google\Cloud\Core\Exception\GoogleException;
use Google\Cloud\Core\Exception\NotFoundException;
use Google\Cloud\Core\Exception\ServiceException;
use Google\Cloud\Core\Iam\Iam;
use Google\Cloud\Core\Iterator\ItemIterator;
use Google\Cloud\Core\Iterator\PageIterator;
use Google\Cloud\Core\Timestamp;
use Google\Cloud\Core\Upload\ResumableUploader;
use Google\Cloud\Core\Upload\StreamableUploader;
use Google\Cloud\PubSub\Topic;
use Google\Cloud\Storage\Connection\ConnectionInterface;
use Google\Cloud\Storage\Connection\IamBucket;
use Google\Cloud\Storage\SigningHelper;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\MimeType;
use GuzzleHttp\Psr7\Utils;
use Psr\Http\Message\StreamInterface;
/**
* Buckets are the basic containers that hold your data. Everything that you
* store in Google Cloud Storage must be contained in a bucket.
*
* Example:
* ```
* use Google\Cloud\Storage\StorageClient;
*
* $storage = new StorageClient();
*
* $bucket = $storage->bucket('my-bucket');
* ```
*/
class Bucket
{
use ArrayTrait;
use EncryptionTrait;
const NOTIFICATION_TEMPLATE = '//pubsub.googleapis.com/%s';
const TOPIC_TEMPLATE = 'projects/%s/topics/%s';
const TOPIC_REGEX = '/projects\/[^\/]*\/topics\/(.*)/';
/**
* @var Acl ACL for the bucket.
*/
private $acl;
/**
* @var ConnectionInterface Represents a connection to Cloud Storage.
*/
private $connection;
/**
* @var Acl Default ACL for objects created within the bucket.
*/
private $defaultAcl;
/**
* @var array The bucket's identity.
*/
private $identity;
/**
* @var string The project ID.
*/
private $projectId;
/**
* @var array|null The bucket's metadata.
*/
private $info;
/**
* @var Iam|null
*/
private $iam;
/**
* @param ConnectionInterface $connection Represents a connection to Cloud
* Storage.
* @param string $name The bucket's name.
* @param array $info [optional] The bucket's metadata.
*/
public function __construct(ConnectionInterface $connection, $name, array $info = [])
{
$this->connection = $connection;
$this->identity = [
'bucket' => $name,
'userProject' => $this->pluck('requesterProjectId', $info, false)
];
$this->info = $info;
$this->projectId = $this->connection->projectId();
$this->acl = new Acl($this->connection, 'bucketAccessControls', $this->identity);
$this->defaultAcl = new Acl($this->connection, 'defaultObjectAccessControls', $this->identity);
}
/**
* Configure ACL for this bucket.
*
* Example:
* ```
* $acl = $bucket->acl();
* ```
*
* @see https://cloud.google.com/storage/docs/access-control More about Access Control Lists
*
* @return Acl An ACL instance configured to handle the bucket's access
* control policies.
*/
public function acl()
{
return $this->acl;
}
/**
* Configure default object ACL for this bucket.
*
* Example:
* ```
* $acl = $bucket->defaultAcl();
* ```
*
* @see https://cloud.google.com/storage/docs/access-control More about Access Control Lists
* @return Acl An ACL instance configured to handle the bucket's default
* object access control policies.
*/
public function defaultAcl()
{
return $this->defaultAcl;
}
/**
* Check whether or not the bucket exists.
*
* Example:
* ```
* if ($bucket->exists()) {
* echo 'Bucket exists!';
* }
* ```
*
* @param array $options [optional] {
* Configuration options.
* }
* @return bool
*/
public function exists(array $options = [])
{
try {
$this->connection->getBucket($options + $this->identity + ['fields' => 'name']);
} catch (NotFoundException $ex) {
return false;
}
return true;
}
/**
* Upload your data in a simple fashion. Uploads will default to being
* resumable if the file size is greater than 5mb.
*
* Example:
* ```
* $object = $bucket->upload(
* fopen(__DIR__ . '/image.jpg', 'r')
* );
* ```
*
* ```
* // Upload an object in a resumable fashion while setting a new name for
* // the object and including the content language.
* $options = [
* 'resumable' => true,
* 'name' => '/images/new-name.jpg',
* 'metadata' => [
* 'contentLanguage' => 'en'
* ]
* ];
*
* $object = $bucket->upload(
* fopen(__DIR__ . '/image.jpg', 'r'),
* $options
* );
* ```
*
* ```
* // Upload an object with a customer-supplied encryption key.
* $key = base64_encode(openssl_random_pseudo_bytes(32)); // Make sure to remember your key.
*
* $object = $bucket->upload(
* fopen(__DIR__ . '/image.jpg', 'r'),
* ['encryptionKey' => $key]
* );
* ```
*
* ```
* // Upload an object utilizing an encryption key managed by the Cloud Key Management Service (KMS).
* $object = $bucket->upload(
* fopen(__DIR__ . '/image.jpg', 'r'),
* [
* 'metadata' => [
* 'kmsKeyName' => 'projects/my-project/locations/kr-location/keyRings/my-kr/cryptoKeys/my-key'
* ]
* ]
* );
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable Learn more about resumable
* uploads.
* @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
* @see https://cloud.google.com/storage/docs/encryption#customer-supplied Customer-supplied encryption keys.
* @see https://github.com/google/php-crc32 crc32c PHP extension for hardware-accelerated validation hashes.
*
* @param string|resource|StreamInterface|null $data The data to be uploaded.
* @param array $options [optional] {
* Configuration options.
*
* @type string $name The name of the destination. Required when data is
* of type string or null.
* @type bool $resumable Indicates whether or not the upload will be
* performed in a resumable fashion.
* @type bool|string $validate Indicates whether or not validation will
* be applied using md5 or crc32c hashing functionality. If
* enabled, and the calculated hash does not match that of the
* upstream server, the upload will be rejected. Available options
* are `true`, `false`, `md5` and `crc32`. If true, either md5 or
* crc32c will be chosen based on your platform. If false, no
* validation hash will be sent. Choose either `md5` or `crc32` to
* force a hash method regardless of performance implications. In
* PHP versions earlier than 7.4, performance will be very
* adversely impacted by using crc32c unless you install the
* `crc32c` PHP extension. **Defaults to** `true`.
* @type int $chunkSize If provided the upload will be done in chunks.
* The size must be in multiples of 262144 bytes. With chunking
* you have increased reliability at the risk of higher overhead.
* It is recommended to not use chunking.
* @type callable $uploadProgressCallback If provided together with
* $resumable == true the given callable function/method will be
* called after each successfully uploaded chunk. The callable
* function/method will receive the number of uploaded bytes
* after each uploaded chunk as a parameter to this callable.
* It's useful if you want to create a progress bar when using
* resumable upload type together with $chunkSize parameter.
* If $chunkSize is not set the callable function/method will be
* called only once after the successful file upload.
* @type string $predefinedAcl Predefined ACL to apply to the object.
* Acceptable values include, `"authenticatedRead"`,
* `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
* `"projectPrivate"`, and `"publicRead"`.
* @type array $metadata The full list of available options are outlined
* at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
* @type array $metadata.metadata User-provided metadata, in key/value pairs.
* @type string $encryptionKey A base64 encoded AES-256 customer-supplied
* encryption key. If you would prefer to manage encryption
* utilizing the Cloud Key Management Service (KMS) please use the
* `$metadata.kmsKeyName` setting. Please note if using KMS the
* key ring must use the same location as the bucket.
* @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
* customer-supplied encryption key. This value will be calculated
* from the `encryptionKey` on your behalf if not provided, but
* for best performance it is recommended to pass in a cached
* version of the already calculated SHA.
* }
* @return StorageObject
* @throws \InvalidArgumentException
*/
public function upload($data, array $options = [])
{
if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
throw new \InvalidArgumentException('A name is required when data is of type string or null.');
}
$encryptionKey = isset($options['encryptionKey']) ? $options['encryptionKey'] : null;
$encryptionKeySHA256 = isset($options['encryptionKeySHA256']) ? $options['encryptionKeySHA256'] : null;
$response = $this->connection->insertObject(
$this->formatEncryptionHeaders($options) + $this->identity + [
'data' => $data
]
)->upload();
return new StorageObject(
$this->connection,
$response['name'],
$this->identity['bucket'],
$response['generation'],
$response,
$encryptionKey,
$encryptionKeySHA256
);
}
/**
* Asynchronously uploads an object.
*
* Please note this method does not support resumable or streaming uploads.
*
* Example:
* ```
* $promise = $bucket->uploadAsync('Lorem Ipsum', ['name' => 'keyToData']);
* $object = $promise->wait();
* ```
*
* ```
* // Upload multiple objects to a bucket asynchronously.
* $promises = [];
* $objects = ['key1' => 'Lorem', 'key2' => 'Ipsum', 'key3' => 'Gypsum'];
*
* foreach ($objects as $k => $v) {
* $promises[] = $bucket->uploadAsync($v, ['name' => $k])
* ->then(function (StorageObject $object) {
* echo $object->name() . PHP_EOL;
* }, function(\Exception $e) {
* throw new Exception('An error has occurred in the matrix.', null, $e);
* });
* }
*
* foreach ($promises as $promise) {
* $promise->wait();
* }
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
* @see https://cloud.google.com/storage/docs/encryption#customer-supplied Customer-supplied encryption keys.
* @see https://github.com/google/php-crc32 crc32c PHP extension for hardware-accelerated validation hashes.
* @see https://github.com/guzzle/promises Learn more about Guzzle Promises
*
* @param string|resource|StreamInterface|null $data The data to be uploaded.
* @param array $options [optional] {
* Configuration options.
*
* @type string $name The name of the destination. Required when data is
* of type string or null.
* @type bool|string $validate Indicates whether or not validation will
* be applied using md5 or crc32c hashing functionality. If
* enabled, and the calculated hash does not match that of the
* upstream server, the upload will be rejected. Available options
* are `true`, `false`, `md5` and `crc32`. If true, either md5 or
* crc32c will be chosen based on your platform. If false, no
* validation hash will be sent. Choose either `md5` or `crc32` to
* force a hash method regardless of performance implications. In
* PHP versions earlier than 7.4, performance will be very
* adversely impacted by using crc32c unless you install the
* `crc32c` PHP extension. **Defaults to** `true`.ß
* @type string $predefinedAcl Predefined ACL to apply to the object.
* Acceptable values include, `"authenticatedRead"`,
* `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
* `"projectPrivate"`, and `"publicRead"`.
* @type array $metadata The full list of available options are outlined
* at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
* @type array $metadata.metadata User-provided metadata, in key/value pairs.
* @type string $encryptionKey A base64 encoded AES-256 customer-supplied
* encryption key. If you would prefer to manage encryption
* utilizing the Cloud Key Management Service (KMS) please use the
* `$metadata.kmsKeyName` setting. Please note if using KMS the
* key ring must use the same location as the bucket.
* @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
* customer-supplied encryption key. This value will be calculated
* from the `encryptionKey` on your behalf if not provided, but
* for best performance it is recommended to pass in a cached
* version of the already calculated SHA.
* }
* @return PromiseInterface<StorageObject>
* @throws \InvalidArgumentException
* @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 uploadAsync($data, array $options = [])
{
if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
throw new \InvalidArgumentException('A name is required when data is of type string or null.');
}
$encryptionKey = isset($options['encryptionKey']) ? $options['encryptionKey'] : null;
$encryptionKeySHA256 = isset($options['encryptionKeySHA256']) ? $options['encryptionKeySHA256'] : null;
$promise = $this->connection->insertObject(
$this->formatEncryptionHeaders($options) +
$this->identity +
[
'data' => $data,
'resumable' => false
]
)->uploadAsync();
return $promise->then(
function (array $response) use ($encryptionKey, $encryptionKeySHA256) {
return new StorageObject(
$this->connection,
$response['name'],
$this->identity['bucket'],
$response['generation'],
$response,
$encryptionKey,
$encryptionKeySHA256
);
}
);
}
/**
* Get a resumable uploader which can provide greater control over the
* upload process. This is recommended when dealing with large files where
* reliability is key.
*
* Example:
* ```
* $uploader = $bucket->getResumableUploader(
* fopen(__DIR__ . '/image.jpg', 'r')
* );
*
* try {
* $object = $uploader->upload();
* } catch (GoogleException $ex) {
* $resumeUri = $uploader->getResumeUri();
* $object = $uploader->resume($resumeUri);
* }
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable Learn more about resumable
* uploads.
* @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
*
* @param string|resource|StreamInterface|null $data The data to be uploaded.
* @param array $options [optional] {
* Configuration options.
*
* @type string $name The name of the destination. Required when data is
* of type string or null.
* @type bool $validate Indicates whether or not validation will be
* applied using md5 hashing functionality. If true and the
* calculated hash does not match that of the upstream server the
* upload will be rejected.
* @type string $predefinedAcl Predefined ACL to apply to the object.
* Acceptable values include `"authenticatedRead`",
* `"bucketOwnerFullControl`", `"bucketOwnerRead`", `"private`",
* `"projectPrivate`", and `"publicRead"`.
* @type array $metadata The available options for metadata are outlined
* at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
* @type string $encryptionKey A base64 encoded AES-256 customer-supplied
* encryption key. If you would prefer to manage encryption
* utilizing the Cloud Key Management Service (KMS) please use the
* $metadata['kmsKeyName'] setting. Please note if using KMS the
* key ring must use the same location as the bucket.
* @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
* customer-supplied encryption key. This value will be calculated
* from the `encryptionKey` on your behalf if not provided, but
* for best performance it is recommended to pass in a cached
* version of the already calculated SHA.
* @type callable $uploadProgressCallback The given callable
* function/method will be called after each successfully uploaded
* chunk. The callable function/method will receive the number of
* uploaded bytes after each uploaded chunk as a parameter to this
* callable. It's useful if you want to create a progress bar when
* using resumable upload type together with $chunkSize parameter.
* If $chunkSize is not set the callable function/method will be
* called only once after the successful file upload.
* }
* @return ResumableUploader
* @throws \InvalidArgumentException
*/
public function getResumableUploader($data, array $options = [])
{
if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
throw new \InvalidArgumentException('A name is required when data is of type string or null.');
}
return $this->connection->insertObject(
$this->formatEncryptionHeaders($options) + $this->identity + [
'data' => $data,
'resumable' => true
]
);
}
/**
* Get a streamable uploader which can provide greater control over the
* upload process. This is useful for generating large files and uploading
* the contents in chunks.
*
* Example:
* ```
* $uploader = $bucket->getStreamableUploader(
* 'initial contents',
* ['name' => 'data.txt']
* );
*
* // finish uploading the item
* $uploader->upload();
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable Learn more about resumable
* uploads.
* @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
*
* @param string|resource|StreamInterface $data The data to be uploaded.
* @param array $options [optional] {
* Configuration options.
*
* @type string $name The name of the destination. Required when data is
* of type string or null.
* @type bool $validate Indicates whether or not validation will be
* applied using md5 hashing functionality. If true and the
* calculated hash does not match that of the upstream server the
* upload will be rejected.
* @type int $chunkSize If provided the upload will be done in chunks.
* The size must be in multiples of 262144 bytes. With chunking
* you have increased reliability at the risk of higher overhead.
* It is recommended to not use chunking.
* @type string $predefinedAcl Predefined ACL to apply to the object.
* Acceptable values include, `"authenticatedRead"`,
* `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
* `"projectPrivate"`, and `"publicRead"`.
* @type array $metadata The available options for metadata are outlined
* at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
* @type string $encryptionKey A base64 encoded AES-256 customer-supplied
* encryption key. If you would prefer to manage encryption
* utilizing the Cloud Key Management Service (KMS) please use the
* $metadata['kmsKeyName'] setting. Please note if using KMS the
* key ring must use the same location as the bucket.
* @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
* customer-supplied encryption key. This value will be calculated
* from the `encryptionKey` on your behalf if not provided, but
* for best performance it is recommended to pass in a cached
* version of the already calculated SHA.
* }
* @return StreamableUploader
* @throws \InvalidArgumentException
*/
public function getStreamableUploader($data, array $options = [])
{
if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
throw new \InvalidArgumentException('A name is required when data is of type string or null.');
}
return $this->connection->insertObject(
$this->formatEncryptionHeaders($options) + $this->identity + [
'data' => $data,
'streamable' => true,
'validate' => false
]
);
}
/**
* Lazily instantiates an object. There are no network requests made at this
* point. To see the operations that can be performed on an object please
* see {@see Google\Cloud\Storage\StorageObject}.
*
* Example:
* ```
* $object = $bucket->object('file.txt');
* ```
*
* @param string $name The name of the object to request.
* @param array $options [optional] {
* Configuration options.
*
* @type string $generation Request a specific revision of the object.
* @type string $encryptionKey A base64 encoded AES-256 customer-supplied
* encryption key. It will be neccesary to provide this when a key
* was used during the object's creation.
* @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
* customer-supplied encryption key. This value will be calculated
* from the `encryptionKey` on your behalf if not provided, but
* for best performance it is recommended to pass in a cached
* version of the already calculated SHA.
* }
* @return StorageObject
*/
public function object($name, array $options = [])
{
$generation = isset($options['generation']) ? $options['generation'] : null;
$encryptionKey = isset($options['encryptionKey']) ? $options['encryptionKey'] : null;
$encryptionKeySHA256 = isset($options['encryptionKeySHA256']) ? $options['encryptionKeySHA256'] : null;
return new StorageObject(
$this->connection,
$name,
$this->identity['bucket'],
$generation,
array_filter([
'requesterProjectId' => $this->identity['userProject']
]),
$encryptionKey,
$encryptionKeySHA256
);
}
/**
* Fetches all objects in the bucket.
*
* Example:
* ```
* // Get all objects beginning with the prefix 'photo'
* $objects = $bucket->objects([
* 'prefix' => 'photo',
* 'fields' => 'items/name,nextPageToken'
* ]);
*
* foreach ($objects as $object) {
* echo $object->name() . PHP_EOL;
* }
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/objects/list Objects list API documentation.
*
* @param array $options [optional] {
* Configuration options.
*
* @type string $delimiter Returns results in a directory-like mode.
* Results will contain only objects whose names, aside from the
* prefix, do not contain delimiter. Objects whose names, aside
* from the prefix, contain delimiter will have their name,
* truncated after the delimiter, returned in prefixes. Duplicate
* prefixes are omitted.
* @type int $maxResults Maximum number of results to return per
* request. **Defaults to** `1000`.
* @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 bool $versions If true, lists all versions of an object as
* distinct results. **Defaults to** `false`.
* @type string $fields Selector which will cause the response to only
* return the specified fields.
* }
* @return ObjectIterator<StorageObject>
*/
public function objects(array $options = [])
{
$resultLimit = $this->pluck('resultLimit', $options, false);
return new ObjectIterator(
new ObjectPageIterator(
function (array $object) {
return new StorageObject(
$this->connection,
$object['name'],
$this->identity['bucket'],
isset($object['generation']) ? $object['generation'] : null,
$object + array_filter([
'requesterProjectId' => $this->identity['userProject']
])
);
},
[$this->connection, 'listObjects'],
$options + $this->identity,
['resultLimit' => $resultLimit]
)
);
}
/**
* Create a Cloud PubSub notification.
*
* Please note, the desired topic must be given the IAM role of
* "pubsub.publisher" from the service account associated with the project
* which contains the bucket you would like to receive notifications from.
* Please see the example below for a programmatic example of achieving
* this.
*
* Example:
* ```
* // Update the permissions on the desired topic prior to creating the
* // notification.
* use Google\Cloud\Core\Iam\PolicyBuilder;
* use Google\Cloud\PubSub\PubSubClient;
*
* $pubSub = new PubSubClient();
* $topicName = 'my-topic';
* $serviceAccountEmail = $storage->getServiceAccount();
* $topic = $pubSub->topic($topicName);
* $iam = $topic->iam();
* $updatedPolicy = (new PolicyBuilder($iam->policy()))
* ->addBinding('roles/pubsub.publisher', [
* "serviceAccount:$serviceAccountEmail"
* ])
* ->result();
* $iam->setPolicy($updatedPolicy);
*
* $notification = $bucket->createNotification($topicName);
* ```
*
* ```
* // Use a fully qualified topic name.
* $notification = $bucket->createNotification('projects/my-project/topics/my-topic');
* ```
*
* ```
* // Provide a Topic object from the Cloud PubSub component.
* use Google\Cloud\PubSub\PubSubClient;
*
* $pubSub = new PubSubClient();
* $topic = $pubSub->topic('my-topic');
* $notification = $bucket->createNotification($topic);
* ```
*
* ```
* // Supplying event types to trigger the notifications.
* $notification = $bucket->createNotification('my-topic', [
* 'event_types' => [
* 'OBJECT_DELETE',
* 'OBJECT_METADATA_UPDATE'
* ]
* ]);
* ```
*
* @codingStandardsIgnoreStart
* @see https://cloud.google.com/storage/docs/pubsub-notifications Cloud PubSub Notifications.
* @see https://cloud.google.com/storage/docs/json_api/v1/notifications/insert Notifications insert API documentation.
* @see https://cloud.google.com/storage/docs/reporting-changes Registering Object Changes.
* @codingStandardsIgnoreEnd
*
* @param string|Topic $topic The topic used to publish notifications.
* @param array $options [optional] {
* Configuration options.
*
* @type array $custom_attributes An optional list of additional
* attributes to attach to each Cloud PubSub message published for
* this notification subscription.
* @type array $event_types If present, only send notifications about
* listed event types. If empty, sent notifications for all event
* types. Acceptablue values include `"OBJECT_FINALIZE"`,
* `"OBJECT_METADATA_UPDATE"`, `"OBJECT_DELETE"`
* , `"OBJECT_ARCHIVE"`.
* @type string $object_name_prefix If present, only apply this
* notification configuration to object names that begin with this
* prefix.
* @type string $payload_format The desired content of the Payload.
* Acceptable values include `"JSON_API_V1"`, `"NONE"`.
* **Defaults to** `"JSON_API_V1"`.
* }
* @return Notification
* @throws \InvalidArgumentException When providing a type other than string
* or {@see Google\Cloud\PubSub\Topic} as $topic.
* @throws GoogleException When a project ID has not been detected.
* @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 createNotification($topic, array $options = [])
{
$res = $this->connection->insertNotification($options + $this->identity + [
'topic' => $this->getFormattedTopic($topic),
'payload_format' => 'JSON_API_V1'
]);
return new Notification(
$this->connection,
$res['id'],
$this->identity['bucket'],
$res + [
'requesterProjectId' => $this->identity['userProject']
]
);
}
/**
* Lazily instantiates a notification. There are no network requests made at
* this point. To see the operations that can be performed on a notification
* please see {@see Google\Cloud\Storage\Notification}.
*
* Example:
* ```
* $notification = $bucket->notification('4582');
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/notifications#resource Notifications API documentation.
*
* @param string $id The ID of the notification to access.
* @return Notification
* @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 notification($id)
{
return new Notification(
$this->connection,
$id,
$this->identity['bucket'],
['requesterProjectId' => $this->identity['userProject']]
);
}
/**
* Fetches all notifications associated with this bucket.
*
* Example:
* ```
* $notifications = $bucket->notifications();
*
* foreach ($notifications as $notification) {
* echo $notification->id() . PHP_EOL;
* }
* ```
*
* @codingStandardsIgnoreStart
* @see https://cloud.google.com/storage/docs/json_api/v1/notifications/list Notifications list API documentation.
* @codingStandardsIgnoreEnd
*
* @param array $options [optional] {
* Configuration options.
*
* @type int $resultLimit Limit the number of results returned in total.
* **Defaults to** `0` (return all results).
* }
* @return ItemIterator<Notification>
* @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 notifications(array $options = [])
{
$resultLimit = $this->pluck('resultLimit', $options, false);
return new ItemIterator(
new PageIterator(
function (array $notification) {
return new Notification(
$this->connection,
$notification['id'],
$this->identity['bucket'],
$notification + [
'requesterProjectId' => $this->identity['userProject']
]
);
},
[$this->connection, 'listNotifications'],
$options + $this->identity,
['resultLimit' => $resultLimit]
)
);
}
/**
* Delete the bucket.
*
* Example:
* ```
* $bucket->delete();
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/delete Buckets delete API documentation.
*
* @param array $options [optional] {
* Configuration options.
* @type string $ifMetagenerationMatch If set, only deletes the bucket
* if its metageneration matches this value.
* @type string $ifMetagenerationNotMatch If set, only deletes the
* bucket if its metageneration does not match this value.
* }
* @return void
*/
public function delete(array $options = [])
{
$this->connection->deleteBucket($options + $this->identity);
}
/**
* Update the bucket. Upon receiving a result the local bucket's data will
* be updated.
*
* Example:
* ```
* // Enable logging on an existing bucket.
* $bucket->update([
* 'logging' => [
* 'logBucket' => 'myBucket',
* 'logObjectPrefix' => 'prefix'
* ]
* ]);
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/patch Buckets patch API documentation.
* @see https://cloud.google.com/storage/docs/key-terms#bucket-labels Bucket Labels
*
* @codingStandardsIgnoreStart
* @param array $options [optional] {
* Configuration options.
*
* @type string $ifMetagenerationMatch Makes the return of the bucket
* metadata conditional on whether the bucket's current
* metageneration matches the given value.
* @type string $ifMetagenerationNotMatch Makes the return of the bucket
* metadata conditional on whether the bucket's current
* metageneration does not match the given value.
* @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. Acceptable
* values include, `"authenticatedRead"`,
* `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
* `"projectPrivate"`, and `"publicRead"`.
* @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 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 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.
* @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 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 Google\Cloud\Storage\Bucket::lockRetentionPolicy()}.
* @type int $retentionPolicy.retentionPeriod Specifies the duration
* that objects need to be retained, in seconds. Retention
* duration 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 $iamConfiguration.publicAccessPrevention The bucket's
* Public Access Prevention configuration. Currently,
* 'inherited' and 'enforced' are supported. **defaults to**
* `inherited`. For more details, see
* [Public Access Prevention](https://cloud.google.com/storage/docs/public-access-prevention).
* }
* @codingStandardsIgnoreEnd
* @return array
*/
public function update(array $options = [])
{
if (isset($options['lifecycle']) && $options['lifecycle'] instanceof Lifecycle) {
$options['lifecycle'] = $options['lifecycle']->toArray();
}
return $this->info = $this->connection->patchBucket($options + $this->identity);
}
/**
* Composes a set of objects into a single object.
*
* Please note that all objects to be composed must come from the same
* bucket.
*
* Example:
* ```
* $sourceObjects = ['log1.txt', 'log2.txt'];
* $singleObject = $bucket->compose($sourceObjects, 'combined-logs.txt');
* ```
*
* ```
* // Use an instance of StorageObject.
* $sourceObjects = [
* $bucket->object('log1.txt'),
* $bucket->object('log2.txt')
* ];
*
* $singleObject = $bucket->compose($sourceObjects, 'combined-logs.txt');
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/objects/compose Objects compose API documentation
*
* @param string[]|StorageObject[] $sourceObjects The objects to compose.
* @param string $name The name of the composed object.
* @param array $options [optional] {
* Configuration options.
*
* @type string $predefinedAcl Predefined ACL to apply to the composed
* object. Acceptable values include, `"authenticatedRead"`,
* `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
* `"projectPrivate"`, and `"publicRead"`.
* @type array $metadata Metadata to apply to the composed object. The
* available options for metadata are outlined at the
* [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
* @type string $ifGenerationMatch Makes the operation conditional on whether the object's current generation
* matches the given value.
* @type string $ifMetagenerationMatch Makes the operation conditional on whether the object's current
* metageneration matches the given value.
* }
* @return StorageObject
* @throws \InvalidArgumentException
*/
public function compose(array $sourceObjects, $name, array $options = [])
{
if (count($sourceObjects) < 2) {
throw new \InvalidArgumentException('Must provide at least two objects to compose.');
}
$options += [
'destinationBucket' => $this->name(),
'destinationObject' => $name,
'destinationPredefinedAcl' => isset($options['predefinedAcl']) ? $options['predefinedAcl'] : null,
'destination' => isset($options['metadata']) ? $options['metadata'] : null,
'userProject' => $this->identity['userProject'],
'sourceObjects' => array_map(function ($sourceObject) {
$name = null;
$generation = null;
if ($sourceObject instanceof StorageObject) {
$name = $sourceObject->name();
$generation = isset($sourceObject->identity()['generation'])
? $sourceObject->identity()['generation']
: null;
}
return array_filter([
'name' => $name ?: $sourceObject,
'generation' => $generation
]);
}, $sourceObjects)
];
if (!isset($options['destination']['contentType'])) {
$options['destination']['contentType'] = MimeType::fromFilename($name);
}
if ($options['destination']['contentType'] === null) {
throw new \InvalidArgumentException('A content type could not be detected and must be provided manually.');
}
unset($options['metadata']);
unset($options['predefinedAcl']);
$response = $this->connection->composeObject(array_filter($options));
return new StorageObject(
$this->connection,
$response['name'],
$this->identity['bucket'],
$response['generation'],
$response + array_filter([
'requesterProjectId' => $this->identity['userProject']
])
);
}
/**
* Retrieves the bucket's details. If no bucket data is cached a network
* request will be made to retrieve it.
*
* Example:
* ```
* $info = $bucket->info();
* echo $info['location'];
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/get Buckets get API documentation.
*
* @param array $options [optional] {
* Configuration options.
*
* @type string $ifMetagenerationMatch Makes the return of the bucket
* metadata conditional on whether the bucket's current
* metageneration matches the given value.
* @type string $ifMetagenerationNotMatch Makes the return of the bucket
* metadata conditional on whether the bucket's current
* metageneration does not match the given value.
* @type string $projection Determines which properties to return. May
* be either `"full"` or `"noAcl"`.
* }
* @return array
*/
public function info(array $options = [])
{
return $this->info ?: $this->reload($options);
}
/**
* Triggers a network request to reload the bucket's details.
*
* Example:
* ```
* $bucket->reload();
* $info = $bucket->info();
* echo $info['location'];
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/get Buckets get API documentation.
*
* @param array $options [optional] {
* Configuration options.
*
* @type string $ifMetagenerationMatch Makes the return of the bucket
* metadata conditional on whether the bucket's current
* metageneration matches the given value.
* @type string $ifMetagenerationNotMatch Makes the return of the bucket
* metadata conditional on whether the bucket's current
* metageneration does not match the given value.
* @type string $projection Determines which properties to return. May
* be either `"full"` or `"noAcl"`.
* }
* @return array
*/
public function reload(array $options = [])
{
return $this->info = $this->connection->getBucket($options + $this->identity);
}
/**
* Retrieves the bucket's name.
*
* Example:
* ```
* echo $bucket->name();
* ```
*
* @return string
*/
public function name()
{
return $this->identity['bucket'];
}
/**
* Retrieves a fresh lifecycle builder. If a lifecyle configuration already
* exists on the target bucket and this builder is used, it will fully
* replace the configuration with the rules provided by this builder.
*
* This builder is intended to be used in tandem with
* {@see Google\Cloud\Storage\StorageClient::createBucket()} and
* {@see Google\Cloud\Storage\Bucket::update()}.
*
* Example:
* ```
* use Google\Cloud\Storage\Bucket;
*
* $lifecycle = Bucket::lifecycle()
* ->addDeleteRule([
* 'age' => 50,
* 'isLive' => true
* ]);
* $bucket->update([
* 'lifecycle' => $lifecycle
* ]);
* ```
*
* @see https://cloud.google.com/storage/docs/lifecycle Object Lifecycle Management API Documentation
*
* @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.
* @return Lifecycle
*/
public static function lifecycle(array $lifecycle = [])
{
return new Lifecycle($lifecycle);
}
/**
* Retrieves a lifecycle builder preconfigured with the lifecycle rules that
* already exists on the bucket. Use this if you want to make updates to an
* existing configuration without removing existing rules, as would be the
* case when using {@see Google\Cloud\Storage\Bucket::lifecycle()}.
*
* This builder is intended to be used in tandem with
* {@see Google\Cloud\Storage\StorageClient::createBucket()} and
* {@see Google\Cloud\Storage\Bucket::update()}.
*
* Please note, this method may trigger a network request in order to fetch
* the existing lifecycle rules from the server.
*
* Example:
* ```
* $lifecycle = $bucket->currentLifecycle()
* ->addDeleteRule([
* 'age' => 50,
* 'isLive' => true
* ]);
* $bucket->update([
* 'lifecycle' => $lifecycle
* ]);
* ```
*
* ```
* // Iterate over existing rules.
* $lifecycle = $bucket->currentLifecycle();
*
* foreach ($lifecycle as $rule) {
* print_r($rule);
* }
* ```
*
* @see https://cloud.google.com/storage/docs/lifecycle Object Lifecycle Management API Documentation
*
* @param array $options [optional] Configuration options.
* @return Lifecycle
*/
public function currentLifecycle(array $options = [])
{
return self::lifecycle(
isset($this->info($options)['lifecycle'])
? $this->info['lifecycle']
: []
);
}
/**
* Returns whether the bucket with the given file prefix is writable.
* Tries to create a temporary file as a resumable upload which will
* not be completed (and cleaned up by GCS).
*
* @param string $file [optional] File to try to write.
* @return bool
* @throws ServiceException
*/
public function isWritable($file = null)
{
$file = $file ?: '__tempfile';
$uploader = $this->getResumableUploader(
Utils::streamFor(''),
['name' => $file]
);
try {
$uploader->getResumeUri();
} catch (ServiceException $e) {
// We expect a 403 access denied error if the bucket is not writable
if ($e->getCode() == 403) {
return false;
}
// If not a 403, re-raise the unexpected error
throw $e;
}
return true;
}
/**
* Manage the IAM policy for the current Bucket.
*
* To request a policy with conditions, pass an array with
* '[requestedPolicyVersion => 3]' as argument to the policy() and
* reload() methods.
*
* Example:
* ```
* $iam = $bucket->iam();
*
* // Returns the stored policy, or fetches the policy if none exists.
* $policy = $iam->policy(['requestedPolicyVersion' => 3]);
*
* // Fetches a policy from the server.
* $policy = $iam->reload(['requestedPolicyVersion' => 3]);
* ```
*
* @codingStandardsIgnoreStart
* @see https://cloud.google.com/storage/docs/access-control/iam-with-json-and-xml Storage Access Control Documentation
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/getIamPolicy Get Bucket IAM Policy
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/setIamPolicy Set Bucket IAM Policy
* @see https://cloud.google.com/storage/docs/json_api/v1/buckets/testIamPermissions Test Bucket Permissions
* @see https://cloud.google.com/iam/docs/policies#versions policy versioning.
* @codingStandardsIgnoreEnd
*
* @return Iam
*/
public function iam()
{
if (!$this->iam) {
$this->iam = new Iam(
new IamBucket($this->connection),
$this->identity['bucket'],
[
'parent' => null,
'args' => $this->identity
]
);
}
return $this->iam;
}
/**
* Locks a provided retention policy on this bucket. Upon receiving a result,
* the local bucket's data will be updated.
*
* Please note that in order for this call to succeed, the applicable
* metageneration value will need to be available. It can either be supplied
* explicitly through the `ifMetagenerationMatch` option or detected for you
* by ensuring a value is cached locally (by calling
* {@see Google\Cloud\Storage\Bucket::reload()} or
* {@see Google\Cloud\Storage\Bucket::info()}, for example).
*
* Example:
* ```
* // Set a retention policy.
* $bucket->update([
* 'retentionPolicy' => [
* 'retentionPeriod' => 604800 // One week in seconds.
* ]
* ]);
* // Lock in the policy.
* $info = $bucket->lockRetentionPolicy();
* $retentionPolicy = $info['retentionPolicy'];
*
* // View the time from which the policy was enforced and effective. (RFC 3339 format)
* echo $retentionPolicy['effectiveTime'] . PHP_EOL;
*
* // View whether or not the retention policy is locked. This will be
* // `true` after a successful call to `lockRetentionPolicy`.
* echo $retentionPolicy['isLocked'];
* ```
*
* @see https://cloud.google.com/storage/docs/bucket-lock Bucket Lock Documentation
*
* @param array $options [optional] {
* Configuration options.
*
* @type string $ifMetagenerationMatch Only locks the retention policy
* if the bucket's metageneration matches this value. If not
* provided the locally cached metageneration value will be used,
* otherwise an exception will be thrown.
* }
* @throws \BadMethodCallException If no metageneration value is available.
* @return array
*/
public function lockRetentionPolicy(array $options = [])
{
if (!isset($options['ifMetagenerationMatch'])) {
if (!isset($this->info['metageneration'])) {
throw new \BadMethodCallException(
'No metageneration value was detected. Please either provide ' .
'a value explicitly or ensure metadata is loaded through a ' .
'call such as Bucket::reload().'
);
}
$options['ifMetagenerationMatch'] = $this->info['metageneration'];
}
return $this->info = $this->connection->lockRetentionPolicy(
$options + $this->identity
);
}
/**
* Create a Signed URL listing objects in this bucket.
*
* Example:
* ```
* $url = $bucket->signedUrl(time() + 3600);
* ```
*
* ```
* // Use V4 Signing
* $url = $bucket->signedUrl(time() + 3600, [
* 'version' => 'v4'
* ]);
* ```
*
* @see https://cloud.google.com/storage/docs/access-control/signed-urls Signed URLs
*
* @param Timestamp|\DateTimeInterface|int $expires Specifies when the URL
* will expire. May provide an instance of {@see Google\Cloud\Core\Timestamp},
* [http://php.net/datetimeimmutable](`\DateTimeImmutable`), or a
* UNIX timestamp as an integer.
* @param array $options {
* Configuration Options.
*
* @type string $cname The CNAME for the bucket, for instance
* `https://cdn.example.com`. **Defaults to**
* `https://storage.googleapis.com`.
* @type string $contentMd5 The MD5 digest value in base64. If you
* provide this, the client must provide this HTTP header with
* this same value in its request. If provided, take care to
* always provide this value as a base64 encoded string.
* @type string $contentType If you provide this value, the client must
* provide this HTTP header set to the same value.
* @type bool $forceOpenssl If true, OpenSSL will be used regardless of
* whether phpseclib is available. **Defaults to** `false`.
* @type array $headers If additional headers are provided, the server
* will check to make sure that the client provides matching
* values. Provide headers as a key/value array, where the key is
* the header name, and the value is an array of header values.
* Headers with multiple values may provide values as a simple
* array, or a comma-separated string. For a reference of allowed
* headers, see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers).
* Header values will be trimmed of leading and trailing spaces,
* multiple spaces within values will be collapsed to a single
* space, and line breaks will be replaced by an empty string.
* V2 Signed URLs may not provide `x-goog-encryption-key` or
* `x-goog-encryption-key-sha256` headers.
* @type array $keyFile Keyfile data to use in place of the keyfile with
* which the client was constructed. If `$options.keyFilePath` is
* set, this option is ignored.
* @type string $keyFilePath A path to a valid keyfile to use in place
* of the keyfile with which the client was constructed.
* @type string|array $scopes One or more authentication scopes to be
* used with a key file. This option is ignored unless
* `$options.keyFile` or `$options.keyFilePath` is set.
* @type array $queryParams Additional query parameters to be included
* as part of the signed URL query string. For allowed values,
* see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers#query).
* @type string $version One of "v2" or "v4". *Defaults to** `"v2"`.
* }
* @return string
* @throws \InvalidArgumentException If the given expiration is invalid or in the past.
* @throws \InvalidArgumentException If the given `$options.method` is not valid.
* @throws \InvalidArgumentException If the given `$options.keyFilePath` is not valid.
* @throws \InvalidArgumentException If the given custom headers are invalid.
* @throws \RuntimeException If the keyfile does not contain the required information.
*/
public function signedUrl($expires, array $options = [])
{
// May be overridden for testing.
$signingHelper = $this->pluck('helper', $options, false)
?: SigningHelper::getHelper();
$resource = sprintf(
'/%s',
$this->identity['bucket']
);
return $signingHelper->sign(
$this->connection,
$expires,
$resource,
null,
$options
);
}
/**
* Create a signed upload policy for uploading objects.
*
* This method generates and signs a policy document. You can use policy
* documents to allow visitors to a website to upload files to Google Cloud
* Storage without giving them direct write access.
*
* Google Cloud PHP does not support v2 post policies.
*
* Example:
* ```
* $policy = $bucket->generateSignedPostPolicyV4($objectName, new \DateTime('tomorrow'), [
* 'conditions' => [
* ['content-length-range', 0, 255]
* ],
* 'fields' => [
* 'x-goog-meta-hello' => 'world',
* 'success_action_redirect' => 'https://google.com'
* ]
* ]);
*
* echo '<form action="' . $policy['url'] . '" method="post" enctype="multipart/form-data">';
* foreach ($policy['fields'] as $name => $value) {
* echo '<input type="hidden" name="' . $name . '" value="' . $value . '">';
* }
*
* echo 'Upload a file!<br>';
* echo '<input type="file" name="file">';
* echo '<button type="submit">Submit!</button>';
* echo '</form>';
* ```
*
* @see https://cloud.google.com/storage/docs/xml-api/post-object#policydocument Policy Documents
*
* @param string $objectName The path to the file in Google Cloud Storage,
* relative to the bucket.
* @param Timestamp|\DateTimeInterface|int $expires Specifies when the URL
* will expire. May provide an instance of {@see Google\Cloud\Core\Timestamp},
* [http://php.net/datetimeimmutable](`\DateTimeImmutable`), or a
* UNIX timestamp as an integer.
* @param array $options [optional] {
* Configuration options
*
* @type string $bucketBoundHostname The hostname for the bucket, for
* instance `cdn.example.com`. May be used for Google Cloud Load
* Balancers or for custom bucket CNAMEs. **Defaults to**
* `storage.googleapis.com`.
* @type array $conditions A list of arrays containing policy matching
* conditions (e.g. `eq`, `starts-with`, `content-length-range`).
* @type array $fields Additional form fields (do not include
* `x-goog-signature`, `file`, `policy` or fields with an
* `x-ignore` prefix), given as key/value pairs.
* @type bool $forceOpenssl If true, OpenSSL will be used regardless of
* whether phpseclib is available. **Defaults to** `false`.
* @type array $keyFile Keyfile data to use in place of the keyfile with
* which the client was constructed. If `$options.keyFilePath` is
* set, this option is ignored.
* @type string $keyFilePath A path to a valid Keyfile to use in place
* of the keyfile with which the client was constructed.
* @type string $scheme Either `http` or `https`. Only used if a custom
* hostname is provided via `$options.bucketBoundHostname`. If a
* custom bucketBoundHostname is provided, **defaults to** `http`.
* In all other cases, **defaults to** `https`.
* @type string|array $scopes One or more authentication scopes to be
* used with a key file. This option is ignored unless
* `$options.keyFile` or `$options.keyFilePath` is set.
* @type bool $virtualHostedStyle If `true`, URL will be of form
* `mybucket.storage.googleapis.com`. If `false`,
* `storage.googleapis.com/mybucket`. **Defaults to** `false`.
* }
* @return array An associative array, containing (string) `uri` and
* (array) `fields` keys.
*/
public function generateSignedPostPolicyV4($objectName, $expires, array $options = [])
{
// May be overridden for testing.
$signingHelper = $this->pluck('helper', $options, false)
?: SigningHelper::getHelper();
$resource = sprintf('/%s/%s', $this->identity['bucket'], $objectName);
return $signingHelper->v4PostPolicy(
$this->connection,
$expires,
$resource,
$options
);
}
/**
* Determines if an object name is required.
*
* @param mixed $data
* @return bool
*/
private function isObjectNameRequired($data)
{
return is_string($data) || is_null($data);
}
/**
* Return a topic name in its fully qualified format.
*
* @param Topic|string $topic
* @return string
* @throws \InvalidArgumentException
* @throws GoogleException
*/
private function getFormattedTopic($topic)
{
if ($topic instanceof Topic) {
return sprintf(self::NOTIFICATION_TEMPLATE, $topic->name());
}
if (!is_string($topic)) {
throw new \InvalidArgumentException(
'$topic may only be a string or instance of Google\Cloud\PubSub\Topic'
);
}
if (preg_match('/projects\/[^\/]*\/topics\/(.*)/', $topic) === 1) {
return sprintf(self::NOTIFICATION_TEMPLATE, $topic);
}
if (!$this->projectId) {
throw new GoogleException(
'No project ID was provided, ' .
'and we were unable to detect a default project ID.'
);
}
return sprintf(
self::NOTIFICATION_TEMPLATE,
sprintf(self::TOPIC_TEMPLATE, $this->projectId, $topic)
);
}
}