404

[ Avaa Bypassed ]




Upload:

Command:

elspacio@18.225.156.98: ~ $
<?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)
        );
    }
}

Filemanager

Name Type Size Permission Actions
Connection Folder 0755
Acl.php File 7.18 KB 0644
Bucket.php File 66.47 KB 0644
CreatedHmacKey.php File 1.88 KB 0644
EncryptionTrait.php File 5.23 KB 0644
HmacKey.php File 4.84 KB 0644
Lifecycle.php File 14.7 KB 0644
Notification.php File 5.62 KB 0644
ObjectIterator.php File 1.17 KB 0644
ObjectPageIterator.php File 1.85 KB 0644
ReadStream.php File 2.71 KB 0644
SigningHelper.php File 29.42 KB 0644
StorageClient.php File 23.54 KB 0644
StorageObject.php File 53.99 KB 0644
StreamWrapper.php File 24.72 KB 0644
WriteStream.php File 3.24 KB 0644