PluginProbe
Media Cloud Sync / 1.2.10
Media Cloud Sync v1.2.10
1.4.2 1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 All 36 releases
media-cloud-sync / includes / sdk / google / google / cloud-storage / src / Bucket.php

Bucket.php in Media Cloud Sync 1.2.10, at includes/sdk/google/google/cloud-storage/src/Bucket.php

1,416 lines 65.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Copyright 2015 Google Inc. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 namespace Dudlewebs\WPMCS\Google\Cloud\Storage;
19
20 use Dudlewebs\WPMCS\Google\Cloud\Core\ArrayTrait;
21 use Dudlewebs\WPMCS\Google\Cloud\Core\Exception\GoogleException;
22 use Dudlewebs\WPMCS\Google\Cloud\Core\Exception\NotFoundException;
23 use Dudlewebs\WPMCS\Google\Cloud\Core\Exception\ServiceException;
24 use Dudlewebs\WPMCS\Google\Cloud\Core\Iam\Iam;
25 use Dudlewebs\WPMCS\Google\Cloud\Core\Iterator\ItemIterator;
26 use Dudlewebs\WPMCS\Google\Cloud\Core\Iterator\PageIterator;
27 use Dudlewebs\WPMCS\Google\Cloud\Core\Timestamp;
28 use Dudlewebs\WPMCS\Google\Cloud\Core\Upload\ResumableUploader;
29 use Dudlewebs\WPMCS\Google\Cloud\Core\Upload\StreamableUploader;
30 use Dudlewebs\WPMCS\Google\Cloud\PubSub\Topic;
31 use Dudlewebs\WPMCS\Google\Cloud\Storage\Connection\ConnectionInterface;
32 use Dudlewebs\WPMCS\Google\Cloud\Storage\Connection\IamBucket;
33 use Dudlewebs\WPMCS\Google\Cloud\Storage\SigningHelper;
34 use Dudlewebs\WPMCS\GuzzleHttp\Promise\PromiseInterface;
35 use Dudlewebs\WPMCS\GuzzleHttp\Psr7\MimeType;
36 use Dudlewebs\WPMCS\GuzzleHttp\Psr7\Utils;
37 use Dudlewebs\WPMCS\Psr\Http\Message\StreamInterface;
38 /**
39 * Buckets are the basic containers that hold your data. Everything that you
40 * store in Google Cloud Storage must be contained in a bucket.
41 *
42 * Example:
43 * ```
44 * use Google\Cloud\Storage\StorageClient;
45 *
46 * $storage = new StorageClient();
47 *
48 * $bucket = $storage->bucket('my-bucket');
49 * ```
50 */
51 class Bucket
52 {
53 use ArrayTrait;
54 use EncryptionTrait;
55 const NOTIFICATION_TEMPLATE = '//pubsub.googleapis.com/%s';
56 const TOPIC_TEMPLATE = 'projects/%s/topics/%s';
57 const TOPIC_REGEX = '/projects\/[^\/]*\/topics\/(.*)/';
58 /**
59 * @var Acl ACL for the bucket.
60 */
61 private $acl;
62 /**
63 * @var ConnectionInterface Represents a connection to Cloud Storage.
64 * @internal
65 */
66 private $connection;
67 /**
68 * @var Acl Default ACL for objects created within the bucket.
69 */
70 private $defaultAcl;
71 /**
72 * @var array The bucket's identity.
73 */
74 private $identity;
75 /**
76 * @var string The project ID.
77 */
78 private $projectId;
79 /**
80 * @var array|null The bucket's metadata.
81 */
82 private $info;
83 /**
84 * @var Iam|null
85 */
86 private $iam;
87 /**
88 * @param ConnectionInterface $connection Represents a connection to Cloud
89 * Storage. This object is created by StorageClient,
90 * and should not be instantiated outside of this client.
91 * @param string $name The bucket's name.
92 * @param array $info [optional] The bucket's metadata.
93 */
94 public function __construct(ConnectionInterface $connection, $name, array $info = [])
95 {
96 $this->connection = $connection;
97 $this->identity = ['bucket' => $name, 'userProject' => $this->pluck('requesterProjectId', $info, \false)];
98 $this->info = $info;
99 $this->projectId = $this->connection->projectId();
100 $this->acl = new Acl($this->connection, 'bucketAccessControls', $this->identity);
101 $this->defaultAcl = new Acl($this->connection, 'defaultObjectAccessControls', $this->identity);
102 }
103 /**
104 * Configure ACL for this bucket.
105 *
106 * Example:
107 * ```
108 * $acl = $bucket->acl();
109 * ```
110 *
111 * @see https://cloud.google.com/storage/docs/access-control More about Access Control Lists
112 *
113 * @return Acl An ACL instance configured to handle the bucket's access
114 * control policies.
115 */
116 public function acl()
117 {
118 return $this->acl;
119 }
120 /**
121 * Configure default object ACL for this bucket.
122 *
123 * Example:
124 * ```
125 * $acl = $bucket->defaultAcl();
126 * ```
127 *
128 * @see https://cloud.google.com/storage/docs/access-control More about Access Control Lists
129 * @return Acl An ACL instance configured to handle the bucket's default
130 * object access control policies.
131 */
132 public function defaultAcl()
133 {
134 return $this->defaultAcl;
135 }
136 /**
137 * Check whether or not the bucket exists.
138 *
139 * Example:
140 * ```
141 * if ($bucket->exists()) {
142 * echo 'Bucket exists!';
143 * }
144 * ```
145 *
146 * @param array $options [optional] {
147 * Configuration options.
148 * }
149 * @return bool
150 */
151 public function exists(array $options = [])
152 {
153 try {
154 $this->connection->getBucket($options + $this->identity + ['fields' => 'name']);
155 } catch (NotFoundException $ex) {
156 return \false;
157 }
158 return \true;
159 }
160 /**
161 * Upload your data in a simple fashion. Uploads will default to being
162 * resumable if the file size is greater than 5mb.
163 *
164 * Example:
165 * ```
166 * $object = $bucket->upload(
167 * fopen(__DIR__ . '/image.jpg', 'r')
168 * );
169 * ```
170 *
171 * ```
172 * // Upload an object in a resumable fashion while setting a new name for
173 * // the object and including the content language.
174 * $options = [
175 * 'resumable' => true,
176 * 'name' => '/images/new-name.jpg',
177 * 'metadata' => [
178 * 'contentLanguage' => 'en'
179 * ]
180 * ];
181 *
182 * $object = $bucket->upload(
183 * fopen(__DIR__ . '/image.jpg', 'r'),
184 * $options
185 * );
186 * ```
187 *
188 * ```
189 * // Upload an object with a customer-supplied encryption key.
190 * $key = base64_encode(openssl_random_pseudo_bytes(32)); // Make sure to remember your key.
191 *
192 * $object = $bucket->upload(
193 * fopen(__DIR__ . '/image.jpg', 'r'),
194 * ['encryptionKey' => $key]
195 * );
196 * ```
197 *
198 * ```
199 * // Upload an object utilizing an encryption key managed by the Cloud Key Management Service (KMS).
200 * $object = $bucket->upload(
201 * fopen(__DIR__ . '/image.jpg', 'r'),
202 * [
203 * 'metadata' => [
204 * 'kmsKeyName' => 'projects/my-project/locations/kr-location/keyRings/my-kr/cryptoKeys/my-key'
205 * ]
206 * ]
207 * );
208 * ```
209 *
210 * @see https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable Learn more about resumable
211 * uploads.
212 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
213 * @see https://cloud.google.com/storage/docs/encryption#customer-supplied Customer-supplied encryption keys.
214 * @see https://github.com/google/php-crc32 crc32c PHP extension for hardware-accelerated validation hashes.
215 *
216 * @param string|resource|StreamInterface|null $data The data to be uploaded.
217 * @param array $options [optional] {
218 * Configuration options.
219 *
220 * @type string $name The name of the destination. Required when data is
221 * of type string or null.
222 * @type bool $resumable Indicates whether or not the upload will be
223 * performed in a resumable fashion.
224 * @type bool|string $validate Indicates whether or not validation will
225 * be applied using md5 or crc32c hashing functionality. If
226 * enabled, and the calculated hash does not match that of the
227 * upstream server, the upload will be rejected. Available options
228 * are `true`, `false`, `md5` and `crc32`. If true, either md5 or
229 * crc32c will be chosen based on your platform. If false, no
230 * validation hash will be sent. Choose either `md5` or `crc32` to
231 * force a hash method regardless of performance implications. In
232 * PHP versions earlier than 7.4, performance will be very
233 * adversely impacted by using crc32c unless you install the
234 * `crc32c` PHP extension. **Defaults to** `true`.
235 * @type int $chunkSize If provided the upload will be done in chunks.
236 * The size must be in multiples of 262144 bytes. With chunking
237 * you have increased reliability at the risk of higher overhead.
238 * It is recommended to not use chunking.
239 * @type callable $uploadProgressCallback If provided together with
240 * $resumable == true the given callable function/method will be
241 * called after each successfully uploaded chunk. The callable
242 * function/method will receive the number of uploaded bytes
243 * after each uploaded chunk as a parameter to this callable.
244 * It's useful if you want to create a progress bar when using
245 * resumable upload type together with $chunkSize parameter.
246 * If $chunkSize is not set the callable function/method will be
247 * called only once after the successful file upload.
248 * @type string $predefinedAcl Predefined ACL to apply to the object.
249 * Acceptable values include, `"authenticatedRead"`,
250 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
251 * `"projectPrivate"`, and `"publicRead"`.
252 * @type array $retention The full list of available options are outlined
253 * at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
254 * @type string $retention.retainUntilTime The earliest time in RFC 3339
255 * UTC "Zulu" format that the object can be deleted or replaced.
256 * This is the retention configuration set for this object.
257 * @type string $retention.mode The mode of the retention configuration,
258 * which can be either `"Unlocked"` or `"Locked"`.
259 * @type array $metadata The full list of available options are outlined
260 * at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
261 * @type array $metadata.metadata User-provided metadata, in key/value pairs.
262 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
263 * encryption key. If you would prefer to manage encryption
264 * utilizing the Cloud Key Management Service (KMS) please use the
265 * `$metadata.kmsKeyName` setting. Please note if using KMS the
266 * key ring must use the same location as the bucket.
267 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
268 * customer-supplied encryption key. This value will be calculated
269 * from the `encryptionKey` on your behalf if not provided, but
270 * for best performance it is recommended to pass in a cached
271 * version of the already calculated SHA.
272 * }
273 * @return StorageObject
274 * @throws \InvalidArgumentException
275 */
276 public function upload($data, array $options = [])
277 {
278 if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
279 throw new \InvalidArgumentException('A name is required when data is of type string or null.');
280 }
281 $encryptionKey = $options['encryptionKey'] ?? null;
282 $encryptionKeySHA256 = $options['encryptionKeySHA256'] ?? null;
283 $response = $this->connection->insertObject($this->formatEncryptionHeaders($options) + $this->identity + ['data' => $data])->upload();
284 return new StorageObject($this->connection, $response['name'], $this->identity['bucket'], $response['generation'], $response, $encryptionKey, $encryptionKeySHA256);
285 }
286 /**
287 * Asynchronously uploads an object.
288 *
289 * Please note this method does not support resumable or streaming uploads.
290 *
291 * Example:
292 * ```
293 * $promise = $bucket->uploadAsync('Lorem Ipsum', ['name' => 'keyToData']);
294 * $object = $promise->wait();
295 * ```
296 *
297 * ```
298 * // Upload multiple objects to a bucket asynchronously.
299 * $promises = [];
300 * $objects = ['key1' => 'Lorem', 'key2' => 'Ipsum', 'key3' => 'Gypsum'];
301 *
302 * foreach ($objects as $k => $v) {
303 * $promises[] = $bucket->uploadAsync($v, ['name' => $k])
304 * ->then(function (StorageObject $object) {
305 * echo $object->name() . PHP_EOL;
306 * }, function(\Exception $e) {
307 * throw new Exception('An error has occurred in the matrix.', null, $e);
308 * });
309 * }
310 *
311 * foreach ($promises as $promise) {
312 * $promise->wait();
313 * }
314 * ```
315 *
316 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
317 * @see https://cloud.google.com/storage/docs/encryption#customer-supplied Customer-supplied encryption keys.
318 * @see https://github.com/google/php-crc32 crc32c PHP extension for hardware-accelerated validation hashes.
319 * @see https://github.com/guzzle/promises Learn more about Guzzle Promises
320 *
321 * @param string|resource|StreamInterface|null $data The data to be uploaded.
322 * @param array $options [optional] {
323 * Configuration options.
324 *
325 * @type string $name The name of the destination. Required when data is
326 * of type string or null.
327 * @type bool|string $validate Indicates whether or not validation will
328 * be applied using md5 or crc32c hashing functionality. If
329 * enabled, and the calculated hash does not match that of the
330 * upstream server, the upload will be rejected. Available options
331 * are `true`, `false`, `md5` and `crc32`. If true, either md5 or
332 * crc32c will be chosen based on your platform. If false, no
333 * validation hash will be sent. Choose either `md5` or `crc32` to
334 * force a hash method regardless of performance implications. In
335 * PHP versions earlier than 7.4, performance will be very
336 * adversely impacted by using crc32c unless you install the
337 * `crc32c` PHP extension. **Defaults to** `true`.ß
338 * @type string $predefinedAcl Predefined ACL to apply to the object.
339 * Acceptable values include, `"authenticatedRead"`,
340 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
341 * `"projectPrivate"`, and `"publicRead"`.
342 * @type array $metadata The full list of available options are outlined
343 * at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
344 * @type array $metadata.metadata User-provided metadata, in key/value pairs.
345 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
346 * encryption key. If you would prefer to manage encryption
347 * utilizing the Cloud Key Management Service (KMS) please use the
348 * `$metadata.kmsKeyName` setting. Please note if using KMS the
349 * key ring must use the same location as the bucket.
350 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
351 * customer-supplied encryption key. This value will be calculated
352 * from the `encryptionKey` on your behalf if not provided, but
353 * for best performance it is recommended to pass in a cached
354 * version of the already calculated SHA.
355 * }
356 * @return PromiseInterface<StorageObject>
357 * @throws \InvalidArgumentException
358 * @experimental The experimental flag means that while we believe this method
359 * or class is ready for use, it may change before release in backwards-
360 * incompatible ways. Please use with caution, and test thoroughly when
361 * upgrading.
362 */
363 public function uploadAsync($data, array $options = [])
364 {
365 if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
366 throw new \InvalidArgumentException('A name is required when data is of type string or null.');
367 }
368 $encryptionKey = $options['encryptionKey'] ?? null;
369 $encryptionKeySHA256 = $options['encryptionKeySHA256'] ?? null;
370 $promise = $this->connection->insertObject($this->formatEncryptionHeaders($options) + $this->identity + ['data' => $data, 'resumable' => \false])->uploadAsync();
371 return $promise->then(function (array $response) use ($encryptionKey, $encryptionKeySHA256) {
372 return new StorageObject($this->connection, $response['name'], $this->identity['bucket'], $response['generation'], $response, $encryptionKey, $encryptionKeySHA256);
373 });
374 }
375 /**
376 * Get a resumable uploader which can provide greater control over the
377 * upload process. This is recommended when dealing with large files where
378 * reliability is key.
379 *
380 * Example:
381 * ```
382 * $uploader = $bucket->getResumableUploader(
383 * fopen(__DIR__ . '/image.jpg', 'r')
384 * );
385 *
386 * try {
387 * $object = $uploader->upload();
388 * } catch (GoogleException $ex) {
389 * $resumeUri = $uploader->getResumeUri();
390 * $object = $uploader->resume($resumeUri);
391 * }
392 * ```
393 *
394 * @see https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable Learn more about resumable
395 * uploads.
396 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
397 *
398 * @param string|resource|StreamInterface|null $data The data to be uploaded.
399 * @param array $options [optional] {
400 * Configuration options.
401 *
402 * @type string $name The name of the destination. Required when data is
403 * of type string or null.
404 * @type bool $validate Indicates whether or not validation will be
405 * applied using md5 hashing functionality. If true and the
406 * calculated hash does not match that of the upstream server the
407 * upload will be rejected.
408 * @type string $predefinedAcl Predefined ACL to apply to the object.
409 * Acceptable values include `"authenticatedRead`",
410 * `"bucketOwnerFullControl`", `"bucketOwnerRead`", `"private`",
411 * `"projectPrivate`", and `"publicRead"`.
412 * @type array $metadata The available options for metadata are outlined
413 * at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
414 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
415 * encryption key. If you would prefer to manage encryption
416 * utilizing the Cloud Key Management Service (KMS) please use the
417 * $metadata['kmsKeyName'] setting. Please note if using KMS the
418 * key ring must use the same location as the bucket.
419 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
420 * customer-supplied encryption key. This value will be calculated
421 * from the `encryptionKey` on your behalf if not provided, but
422 * for best performance it is recommended to pass in a cached
423 * version of the already calculated SHA.
424 * @type callable $uploadProgressCallback The given callable
425 * function/method will be called after each successfully uploaded
426 * chunk. The callable function/method will receive the number of
427 * uploaded bytes after each uploaded chunk as a parameter to this
428 * callable. It's useful if you want to create a progress bar when
429 * using resumable upload type together with $chunkSize parameter.
430 * If $chunkSize is not set the callable function/method will be
431 * called only once after the successful file upload.
432 * }
433 * @return ResumableUploader
434 * @throws \InvalidArgumentException
435 */
436 public function getResumableUploader($data, array $options = [])
437 {
438 if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
439 throw new \InvalidArgumentException('A name is required when data is of type string or null.');
440 }
441 return $this->connection->insertObject($this->formatEncryptionHeaders($options) + $this->identity + ['data' => $data, 'resumable' => \true]);
442 }
443 /**
444 * Get a streamable uploader which can provide greater control over the
445 * upload process. This is useful for generating large files and uploading
446 * the contents in chunks.
447 *
448 * Example:
449 * ```
450 * $uploader = $bucket->getStreamableUploader(
451 * 'initial contents',
452 * ['name' => 'data.txt']
453 * );
454 *
455 * // finish uploading the item
456 * $uploader->upload();
457 * ```
458 *
459 * @see https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable Learn more about resumable
460 * uploads.
461 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
462 *
463 * @param string|resource|StreamInterface $data The data to be uploaded.
464 * @param array $options [optional] {
465 * Configuration options.
466 *
467 * @type string $name The name of the destination. Required when data is
468 * of type string or null.
469 * @type bool $validate Indicates whether or not validation will be
470 * applied using md5 hashing functionality. If true and the
471 * calculated hash does not match that of the upstream server the
472 * upload will be rejected.
473 * @type int $chunkSize If provided the upload will be done in chunks.
474 * The size must be in multiples of 262144 bytes. With chunking
475 * you have increased reliability at the risk of higher overhead.
476 * It is recommended to not use chunking.
477 * @type string $predefinedAcl Predefined ACL to apply to the object.
478 * Acceptable values include, `"authenticatedRead"`,
479 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
480 * `"projectPrivate"`, and `"publicRead"`.
481 * @type array $metadata The available options for metadata are outlined
482 * at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
483 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
484 * encryption key. If you would prefer to manage encryption
485 * utilizing the Cloud Key Management Service (KMS) please use the
486 * $metadata['kmsKeyName'] setting. Please note if using KMS the
487 * key ring must use the same location as the bucket.
488 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
489 * customer-supplied encryption key. This value will be calculated
490 * from the `encryptionKey` on your behalf if not provided, but
491 * for best performance it is recommended to pass in a cached
492 * version of the already calculated SHA.
493 * }
494 * @return StreamableUploader
495 * @throws \InvalidArgumentException
496 */
497 public function getStreamableUploader($data, array $options = [])
498 {
499 if ($this->isObjectNameRequired($data) && !isset($options['name'])) {
500 throw new \InvalidArgumentException('A name is required when data is of type string or null.');
501 }
502 return $this->connection->insertObject($this->formatEncryptionHeaders($options) + $this->identity + ['data' => $data, 'streamable' => \true, 'validate' => \false]);
503 }
504 /**
505 * Lazily instantiates an object. There are no network requests made at this
506 * point.
507 *
508 * To see the operations that can be performed on an object please
509 * see {@see StorageObject}.
510 *
511 * Example:
512 * ```
513 * $object = $bucket->object('file.txt');
514 * ```
515 *
516 * @param string $name The name of the object to request.
517 * @param array $options [optional] {
518 * Configuration options.
519 *
520 * @type string $generation Request a specific revision of the object.
521 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
522 * encryption key. It will be neccesary to provide this when a key
523 * was used during the object's creation.
524 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
525 * customer-supplied encryption key. This value will be calculated
526 * from the `encryptionKey` on your behalf if not provided, but
527 * for best performance it is recommended to pass in a cached
528 * version of the already calculated SHA.
529 * }
530 * @return StorageObject
531 */
532 public function object($name, array $options = [])
533 {
534 $generation = $options['generation'] ?? null;
535 $encryptionKey = $options['encryptionKey'] ?? null;
536 $encryptionKeySHA256 = $options['encryptionKeySHA256'] ?? null;
537 return new StorageObject($this->connection, $name, $this->identity['bucket'], $generation, array_filter(['requesterProjectId' => $this->identity['userProject']]), $encryptionKey, $encryptionKeySHA256);
538 }
539 /**
540 * Fetches all objects in the bucket.
541 *
542 * Example:
543 * ```
544 * // Get all objects beginning with the prefix 'photo'
545 * $objects = $bucket->objects([
546 * 'prefix' => 'photo',
547 * 'fields' => 'items/name,nextPageToken'
548 * ]);
549 *
550 * foreach ($objects as $object) {
551 * echo $object->name() . PHP_EOL;
552 * }
553 * ```
554 *
555 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/list Objects list API documentation.
556 *
557 * @param array $options [optional] {
558 * Configuration options.
559 *
560 * @type string $delimiter Returns results in a directory-like mode.
561 * Results will contain only objects whose names, aside from the
562 * prefix, do not contain delimiter. Objects whose names, aside
563 * from the prefix, contain delimiter will have their name,
564 * truncated after the delimiter, returned in prefixes. Duplicate
565 * prefixes are omitted.
566 * @type bool $includeFoldersAsPrefixes If true, will also include folders
567 * and managed folders (besides objects) in the returned prefixes.
568 * Only applicable if delimiter is set to '/'.
569 * @type int $maxResults Maximum number of results to return per
570 * request. **Defaults to** `1000`.
571 * @type int $resultLimit Limit the number of results returned in total.
572 * **Defaults to** `0` (return all results).
573 * @type string $pageToken A previously-returned page token used to
574 * resume the loading of results from a specific point.
575 * @type string $prefix Filter results with this prefix.
576 * @type string $projection Determines which properties to return. May
577 * be either `"full"` or `"noAcl"`.
578 * @type bool $versions If true, lists all versions of an object as
579 * distinct results. **Defaults to** `false`.
580 * @type string $fields Selector which will cause the response to only
581 * return the specified fields.
582 * @type string $matchGlob A glob pattern to filter results. The string
583 * value must be UTF-8 encoded. See:
584 * https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
585 * }
586 * @return ObjectIterator<StorageObject>
587 */
588 public function objects(array $options = [])
589 {
590 $resultLimit = $this->pluck('resultLimit', $options, \false);
591 return new ObjectIterator(new ObjectPageIterator(function (array $object) {
592 return new StorageObject($this->connection, $object['name'], $this->identity['bucket'], isset($object['generation']) ? $object['generation'] : null, $object + array_filter(['requesterProjectId' => $this->identity['userProject']]));
593 }, [$this->connection, 'listObjects'], $options + $this->identity, ['resultLimit' => $resultLimit]));
594 }
595 /**
596 * Create a Cloud PubSub notification.
597 *
598 * Please note, the desired topic must be given the IAM role of
599 * "pubsub.publisher" from the service account associated with the project
600 * which contains the bucket you would like to receive notifications from.
601 * Please see the example below for a programmatic example of achieving
602 * this.
603 *
604 * Example:
605 * ```
606 * // Update the permissions on the desired topic prior to creating the
607 * // notification.
608 * use Google\Cloud\Core\Iam\PolicyBuilder;
609 * use Google\Cloud\PubSub\PubSubClient;
610 *
611 * $pubSub = new PubSubClient();
612 * $topicName = 'my-topic';
613 * $serviceAccountEmail = $storage->getServiceAccount();
614 * $topic = $pubSub->topic($topicName);
615 * $iam = $topic->iam();
616 * $updatedPolicy = (new PolicyBuilder($iam->policy()))
617 * ->addBinding('roles/pubsub.publisher', [
618 * "serviceAccount:$serviceAccountEmail"
619 * ])
620 * ->result();
621 * $iam->setPolicy($updatedPolicy);
622 *
623 * $notification = $bucket->createNotification($topicName);
624 * ```
625 *
626 * ```
627 * // Use a fully qualified topic name.
628 * $notification = $bucket->createNotification('projects/my-project/topics/my-topic');
629 * ```
630 *
631 * ```
632 * // Provide a Topic object from the Cloud PubSub component.
633 * use Google\Cloud\PubSub\PubSubClient;
634 *
635 * $pubSub = new PubSubClient();
636 * $topic = $pubSub->topic('my-topic');
637 * $notification = $bucket->createNotification($topic);
638 * ```
639 *
640 * ```
641 * // Supplying event types to trigger the notifications.
642 * $notification = $bucket->createNotification('my-topic', [
643 * 'event_types' => [
644 * 'OBJECT_DELETE',
645 * 'OBJECT_METADATA_UPDATE'
646 * ]
647 * ]);
648 * ```
649 *
650 * @codingStandardsIgnoreStart
651 * @see https://cloud.google.com/storage/docs/pubsub-notifications Cloud PubSub Notifications.
652 * @see https://cloud.google.com/storage/docs/json_api/v1/notifications/insert Notifications insert API documentation.
653 * @see https://cloud.google.com/storage/docs/reporting-changes Registering Object Changes.
654 * @codingStandardsIgnoreEnd
655 *
656 * @param string|Topic $topic The topic used to publish notifications.
657 * @param array $options [optional] {
658 * Configuration options.
659 *
660 * @type array $custom_attributes An optional list of additional
661 * attributes to attach to each Cloud PubSub message published for
662 * this notification subscription.
663 * @type array $event_types If present, only send notifications about
664 * listed event types. If empty, sent notifications for all event
665 * types. Acceptablue values include `"OBJECT_FINALIZE"`,
666 * `"OBJECT_METADATA_UPDATE"`, `"OBJECT_DELETE"`
667 * , `"OBJECT_ARCHIVE"`.
668 * @type string $object_name_prefix If present, only apply this
669 * notification configuration to object names that begin with this
670 * prefix.
671 * @type string $payload_format The desired content of the Payload.
672 * Acceptable values include `"JSON_API_V1"`, `"NONE"`.
673 * **Defaults to** `"JSON_API_V1"`.
674 * }
675 * @return Notification
676 * @throws \InvalidArgumentException When providing a type other than string
677 * or {@see \Google\Cloud\PubSub\Topic} as $topic.
678 * @throws GoogleException When a project ID has not been detected.
679 * @experimental The experimental flag means that while we believe this
680 * method or class is ready for use, it may change before release in
681 * backwards-incompatible ways. Please use with caution, and test
682 * thoroughly when upgrading.
683 */
684 public function createNotification($topic, array $options = [])
685 {
686 $res = $this->connection->insertNotification($options + $this->identity + ['topic' => $this->getFormattedTopic($topic), 'payload_format' => 'JSON_API_V1']);
687 return new Notification($this->connection, $res['id'], $this->identity['bucket'], $res + ['requesterProjectId' => $this->identity['userProject']]);
688 }
689 /**
690 * Lazily instantiates a notification. There are no network requests made at
691 * this point.
692 *
693 * To see the operations that can be performed on a notification
694 * please see {@see Notification}.
695 *
696 * Example:
697 * ```
698 * $notification = $bucket->notification('4582');
699 * ```
700 *
701 * @see https://cloud.google.com/storage/docs/json_api/v1/notifications#resource Notifications API documentation.
702 *
703 * @param string $id The ID of the notification to access.
704 * @return Notification
705 * @experimental The experimental flag means that while we believe this
706 * method or class is ready for use, it may change before release in
707 * backwards-incompatible ways. Please use with caution, and test
708 * thoroughly when upgrading.
709 */
710 public function notification($id)
711 {
712 return new Notification($this->connection, $id, $this->identity['bucket'], ['requesterProjectId' => $this->identity['userProject']]);
713 }
714 /**
715 * Fetches all notifications associated with this bucket.
716 *
717 * Example:
718 * ```
719 * $notifications = $bucket->notifications();
720 *
721 * foreach ($notifications as $notification) {
722 * echo $notification->id() . PHP_EOL;
723 * }
724 * ```
725 *
726 * @codingStandardsIgnoreStart
727 * @see https://cloud.google.com/storage/docs/json_api/v1/notifications/list Notifications list API documentation.
728 * @codingStandardsIgnoreEnd
729 *
730 * @param array $options [optional] {
731 * Configuration options.
732 *
733 * @type int $resultLimit Limit the number of results returned in total.
734 * **Defaults to** `0` (return all results).
735 * }
736 * @return ItemIterator<Notification>
737 * @experimental The experimental flag means that while we believe this
738 * method or class is ready for use, it may change before release in
739 * backwards-incompatible ways. Please use with caution, and test
740 * thoroughly when upgrading.
741 */
742 public function notifications(array $options = [])
743 {
744 $resultLimit = $this->pluck('resultLimit', $options, \false);
745 return new ItemIterator(new PageIterator(function (array $notification) {
746 return new Notification($this->connection, $notification['id'], $this->identity['bucket'], $notification + ['requesterProjectId' => $this->identity['userProject']]);
747 }, [$this->connection, 'listNotifications'], $options + $this->identity, ['resultLimit' => $resultLimit]));
748 }
749 /**
750 * Delete the bucket.
751 *
752 * Example:
753 * ```
754 * $bucket->delete();
755 * ```
756 *
757 * @see https://cloud.google.com/storage/docs/json_api/v1/buckets/delete Buckets delete API documentation.
758 *
759 * @param array $options [optional] {
760 * Configuration options.
761 * @type string $ifMetagenerationMatch If set, only deletes the bucket
762 * if its metageneration matches this value.
763 * @type string $ifMetagenerationNotMatch If set, only deletes the
764 * bucket if its metageneration does not match this value.
765 * }
766 * @return void
767 */
768 public function delete(array $options = [])
769 {
770 $this->connection->deleteBucket($options + $this->identity);
771 }
772 /**
773 * Update the bucket. Upon receiving a result the local bucket's data will
774 * be updated.
775 *
776 * Example:
777 * ```
778 * // Enable logging on an existing bucket.
779 * $bucket->update([
780 * 'logging' => [
781 * 'logBucket' => 'myBucket',
782 * 'logObjectPrefix' => 'prefix'
783 * ]
784 * ]);
785 * ```
786 *
787 * @see https://cloud.google.com/storage/docs/json_api/v1/buckets/patch Buckets patch API documentation.
788 * @see https://cloud.google.com/storage/docs/key-terms#bucket-labels Bucket Labels
789 *
790 * @codingStandardsIgnoreStart
791 * @param array $options [optional] {
792 * Configuration options.
793 *
794 * @type string $ifMetagenerationMatch Makes the return of the bucket
795 * metadata conditional on whether the bucket's current
796 * metageneration matches the given value.
797 * @type string $ifMetagenerationNotMatch Makes the return of the bucket
798 * metadata conditional on whether the bucket's current
799 * metageneration does not match the given value.
800 * @type string $predefinedAcl Predefined ACL to apply to the bucket.
801 * Acceptable values include, `"authenticatedRead"`,
802 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
803 * `"projectPrivate"`, and `"publicRead"`.
804 * @type string $predefinedDefaultObjectAcl Apply a predefined set of
805 * default object access controls to this bucket. Acceptable
806 * values include, `"authenticatedRead"`,
807 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
808 * `"projectPrivate"`, and `"publicRead"`.
809 * @type string $projection Determines which properties to return. May
810 * be either `"full"` or `"noAcl"`.
811 * @type string $fields Selector which will cause the response to only
812 * return the specified fields.
813 * @type array $acl Access controls on the bucket.
814 * @type array $cors The bucket's Cross-Origin Resource Sharing (CORS)
815 * configuration.
816 * @type array $defaultObjectAcl Default access controls to apply to new
817 * objects when no ACL is provided.
818 * @type array|Lifecycle $lifecycle The bucket's lifecycle configuration.
819 * @type array $logging The bucket's logging configuration, which
820 * defines the destination bucket and optional name prefix for the
821 * current bucket's logs.
822 * @type string $storageClass The bucket's storage class. This defines
823 * how objects in the bucket are stored and determines the SLA and
824 * the cost of storage. Acceptable values include the following
825 * strings: `"STANDARD"`, `"NEARLINE"`, `"COLDLINE"` and
826 * `"ARCHIVE"`. Legacy values including `"MULTI_REGIONAL"`,
827 * `"REGIONAL"` and `"DURABLE_REDUCED_AVAILABILITY"` are also
828 * available, but should be avoided for new implementations. For
829 * more information, refer to the
830 * [Storage Classes](https://cloud.google.com/storage/docs/storage-classes)
831 * documentation. **Defaults to** `"STANDARD"`.
832 * @type array $autoclass The bucket's autoclass configuration.
833 * Buckets can have either StorageClass OLM rules or Autoclass,
834 * but not both. When Autoclass is enabled on a bucket, adding
835 * StorageClass OLM rules will result in failure.
836 * For more information, refer to
837 * [Storage Autoclass](https://cloud.google.com/storage/docs/autoclass)
838 * @type array $versioning The bucket's versioning configuration.
839 * @type array $website The bucket's website configuration.
840 * @type array $billing The bucket's billing configuration.
841 * @type bool $billing.requesterPays When `true`, requests to this bucket
842 * and objects within it must provide a project ID to which the
843 * request will be billed.
844 * @type array $labels The Bucket labels. Labels are represented as an
845 * array of keys and values. To remove an existing label, set its
846 * value to `null`.
847 * @type array $encryption Encryption configuration used by default for
848 * newly inserted objects.
849 * @type string $encryption.defaultKmsKeyName A Cloud KMS Key used to
850 * encrypt objects uploaded into this bucket. Should be in the
851 * format
852 * `projects/my-project/locations/kr-location/keyRings/my-kr/cryptoKeys/my-key`.
853 * Please note the KMS key ring must use the same location as the
854 * bucket.
855 * @type bool $defaultEventBasedHold When `true`, newly created objects
856 * in this bucket will be retained indefinitely until an event
857 * occurs, signified by the hold's release.
858 * @type array $retentionPolicy Defines the retention policy for a
859 * bucket. In order to lock a retention policy, please see
860 * {@see Bucket::lockRetentionPolicy()}.
861 * @type int $retentionPolicy.retentionPeriod Specifies the duration
862 * that objects need to be retained, in seconds. Retention
863 * duration must be greater than zero and less than 100 years.
864 * @type array $iamConfiguration The bucket's IAM configuration.
865 * @type bool $iamConfiguration.bucketPolicyOnly.enabled this is an alias
866 * for $iamConfiguration.uniformBucketLevelAccess.
867 * @type bool $iamConfiguration.uniformBucketLevelAccess.enabled If set and
868 * true, access checks only use bucket-level IAM policies or
869 * above. When enabled, requests attempting to view or manipulate
870 * ACLs will fail with error code 400. **NOTE**: Before using
871 * Uniform bucket-level access, please review the
872 * [feature documentation](https://cloud.google.com/storage/docs/uniform-bucket-level-access),
873 * as well as
874 * [Should You Use uniform bucket-level access](https://cloud.google.com/storage/docs/uniform-bucket-level-access#should-you-use)
875 * @type string $iamConfiguration.publicAccessPrevention The bucket's
876 * Public Access Prevention configuration. Currently,
877 * 'inherited' and 'enforced' are supported. **defaults to**
878 * `inherited`. For more details, see
879 * [Public Access Prevention](https://cloud.google.com/storage/docs/public-access-prevention).
880 * }
881 * @codingStandardsIgnoreEnd
882 * @return array
883 */
884 public function update(array $options = [])
885 {
886 if (isset($options['lifecycle']) && $options['lifecycle'] instanceof Lifecycle) {
887 $options['lifecycle'] = $options['lifecycle']->toArray();
888 }
889 return $this->info = $this->connection->patchBucket($options + $this->identity);
890 }
891 /**
892 * Composes a set of objects into a single object.
893 *
894 * Please note that all objects to be composed must come from the same
895 * bucket.
896 *
897 * Example:
898 * ```
899 * $sourceObjects = ['log1.txt', 'log2.txt'];
900 * $singleObject = $bucket->compose($sourceObjects, 'combined-logs.txt');
901 * ```
902 *
903 * ```
904 * // Use an instance of StorageObject.
905 * $sourceObjects = [
906 * $bucket->object('log1.txt'),
907 * $bucket->object('log2.txt')
908 * ];
909 *
910 * $singleObject = $bucket->compose($sourceObjects, 'combined-logs.txt');
911 * ```
912 *
913 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/compose Objects compose API documentation
914 *
915 * @param string[]|StorageObject[] $sourceObjects The objects to compose.
916 * @param string $name The name of the composed object.
917 * @param array $options [optional] {
918 * Configuration options.
919 *
920 * @type string $predefinedAcl Predefined ACL to apply to the composed
921 * object. Acceptable values include, `"authenticatedRead"`,
922 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
923 * `"projectPrivate"`, and `"publicRead"`.
924 * @type array $metadata Metadata to apply to the composed object. The
925 * available options for metadata are outlined at the
926 * [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
927 * @type string $ifGenerationMatch Makes the operation conditional on whether the object's current generation
928 * matches the given value.
929 * @type string $ifMetagenerationMatch Makes the operation conditional on whether the object's current
930 * metageneration matches the given value.
931 * }
932 * @return StorageObject
933 * @throws \InvalidArgumentException
934 */
935 public function compose(array $sourceObjects, $name, array $options = [])
936 {
937 if (count($sourceObjects) < 2) {
938 throw new \InvalidArgumentException('Must provide at least two objects to compose.');
939 }
940 $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) {
941 $name = null;
942 $generation = null;
943 if ($sourceObject instanceof StorageObject) {
944 $name = $sourceObject->name();
945 $generation = $sourceObject->identity()['generation'] ?? null;
946 }
947 return array_filter(['name' => $name ?: $sourceObject, 'generation' => $generation]);
948 }, $sourceObjects)];
949 if (!isset($options['destination']['contentType'])) {
950 $options['destination']['contentType'] = MimeType::fromFilename($name);
951 }
952 if ($options['destination']['contentType'] === null) {
953 throw new \InvalidArgumentException('A content type could not be detected and must be provided manually.');
954 }
955 unset($options['metadata']);
956 unset($options['predefinedAcl']);
957 $response = $this->connection->composeObject(array_filter($options));
958 return new StorageObject($this->connection, $response['name'], $this->identity['bucket'], $response['generation'], $response + array_filter(['requesterProjectId' => $this->identity['userProject']]));
959 }
960 /**
961 * Retrieves the bucket's details. If no bucket data is cached a network
962 * request will be made to retrieve it.
963 *
964 * Example:
965 * ```
966 * $info = $bucket->info();
967 * echo $info['location'];
968 * ```
969 *
970 * @see https://cloud.google.com/storage/docs/json_api/v1/buckets/get Buckets get API documentation.
971 *
972 * @param array $options [optional] {
973 * Configuration options.
974 *
975 * @type string $ifMetagenerationMatch Makes the return of the bucket
976 * metadata conditional on whether the bucket's current
977 * metageneration matches the given value.
978 * @type string $ifMetagenerationNotMatch Makes the return of the bucket
979 * metadata conditional on whether the bucket's current
980 * metageneration does not match the given value.
981 * @type string $projection Determines which properties to return. May
982 * be either `"full"` or `"noAcl"`.
983 * }
984 * @return array
985 */
986 public function info(array $options = [])
987 {
988 return $this->info ?: $this->reload($options);
989 }
990 /**
991 * Triggers a network request to reload the bucket's details.
992 *
993 * Example:
994 * ```
995 * $bucket->reload();
996 * $info = $bucket->info();
997 * echo $info['location'];
998 * ```
999 *
1000 * @see https://cloud.google.com/storage/docs/json_api/v1/buckets/get Buckets get API documentation.
1001 *
1002 * @param array $options [optional] {
1003 * Configuration options.
1004 *
1005 * @type string $ifMetagenerationMatch Makes the return of the bucket
1006 * metadata conditional on whether the bucket's current
1007 * metageneration matches the given value.
1008 * @type string $ifMetagenerationNotMatch Makes the return of the bucket
1009 * metadata conditional on whether the bucket's current
1010 * metageneration does not match the given value.
1011 * @type string $projection Determines which properties to return. May
1012 * be either `"full"` or `"noAcl"`.
1013 * }
1014 * @return array
1015 */
1016 public function reload(array $options = [])
1017 {
1018 return $this->info = $this->connection->getBucket($options + $this->identity);
1019 }
1020 /**
1021 * Retrieves the bucket's name.
1022 *
1023 * Example:
1024 * ```
1025 * echo $bucket->name();
1026 * ```
1027 *
1028 * @return string
1029 */
1030 public function name()
1031 {
1032 return $this->identity['bucket'];
1033 }
1034 /**
1035 * Retrieves a fresh lifecycle builder. If a lifecyle configuration already
1036 * exists on the target bucket and this builder is used, it will fully
1037 * replace the configuration with the rules provided by this builder.
1038 *
1039 * This builder is intended to be used in tandem with
1040 * {@see StorageClient::createBucket()} and
1041 * {@see Bucket::update()}.
1042 *
1043 * Example:
1044 * ```
1045 * use Google\Cloud\Storage\Bucket;
1046 *
1047 * $lifecycle = Bucket::lifecycle()
1048 * ->addDeleteRule([
1049 * 'age' => 50,
1050 * 'isLive' => true
1051 * ]);
1052 * $bucket->update([
1053 * 'lifecycle' => $lifecycle
1054 * ]);
1055 * ```
1056 *
1057 * @see https://cloud.google.com/storage/docs/lifecycle Object Lifecycle Management API Documentation
1058 *
1059 * @param array $lifecycle [optional] A lifecycle configuration. Please see
1060 * [here](https://cloud.google.com/storage/docs/json_api/v1/buckets#lifecycle)
1061 * for the expected structure.
1062 * @return Lifecycle
1063 */
1064 public static function lifecycle(array $lifecycle = [])
1065 {
1066 return new Lifecycle($lifecycle);
1067 }
1068 /**
1069 * Retrieves a lifecycle builder preconfigured with the lifecycle rules that
1070 * already exists on the bucket.
1071 *
1072 * Use this if you want to make updates to an
1073 * existing configuration without removing existing rules, as would be the
1074 * case when using {@see Bucket::lifecycle()}.
1075 *
1076 * This builder is intended to be used in tandem with
1077 * {@see StorageClient::createBucket()} and
1078 * {@see Bucket::update()}.
1079 *
1080 * Please note, this method may trigger a network request in order to fetch
1081 * the existing lifecycle rules from the server.
1082 *
1083 * Example:
1084 * ```
1085 * $lifecycle = $bucket->currentLifecycle()
1086 * ->addDeleteRule([
1087 * 'age' => 50,
1088 * 'isLive' => true
1089 * ]);
1090 * $bucket->update([
1091 * 'lifecycle' => $lifecycle
1092 * ]);
1093 * ```
1094 *
1095 * ```
1096 * // Iterate over existing rules.
1097 * $lifecycle = $bucket->currentLifecycle();
1098 *
1099 * foreach ($lifecycle as $rule) {
1100 * print_r($rule);
1101 * }
1102 * ```
1103 *
1104 * @see https://cloud.google.com/storage/docs/lifecycle Object Lifecycle Management API Documentation
1105 *
1106 * @param array $options [optional] Configuration options.
1107 * @return Lifecycle
1108 */
1109 public function currentLifecycle(array $options = [])
1110 {
1111 return self::lifecycle(isset($this->info($options)['lifecycle']) ? $this->info['lifecycle'] : []);
1112 }
1113 /**
1114 * Returns whether the bucket with the given file prefix is writable.
1115 * Tries to create a temporary file as a resumable upload which will
1116 * not be completed (and cleaned up by GCS).
1117 *
1118 * @param string $file [optional] File to try to write.
1119 * @return bool
1120 * @throws ServiceException
1121 */
1122 public function isWritable($file = null)
1123 {
1124 $file = $file ?: '__tempfile';
1125 $uploader = $this->getResumableUploader(Utils::streamFor(''), ['name' => $file]);
1126 try {
1127 $uploader->getResumeUri();
1128 } catch (ServiceException $e) {
1129 // We expect a 403 access denied error if the bucket is not writable
1130 if ($e->getCode() == 403) {
1131 return \false;
1132 }
1133 // If not a 403, re-raise the unexpected error
1134 throw $e;
1135 }
1136 return \true;
1137 }
1138 /**
1139 * Manage the IAM policy for the current Bucket.
1140 *
1141 * To request a policy with conditions, pass an array with
1142 * '[requestedPolicyVersion => 3]' as argument to the policy() and
1143 * reload() methods.
1144 *
1145 * Example:
1146 * ```
1147 * $iam = $bucket->iam();
1148 *
1149 * // Returns the stored policy, or fetches the policy if none exists.
1150 * $policy = $iam->policy(['requestedPolicyVersion' => 3]);
1151 *
1152 * // Fetches a policy from the server.
1153 * $policy = $iam->reload(['requestedPolicyVersion' => 3]);
1154 * ```
1155 *
1156 * @codingStandardsIgnoreStart
1157 * @see https://cloud.google.com/storage/docs/access-control/iam-with-json-and-xml Storage Access Control Documentation
1158 * @see https://cloud.google.com/storage/docs/json_api/v1/buckets/getIamPolicy Get Bucket IAM Policy
1159 * @see https://cloud.google.com/storage/docs/json_api/v1/buckets/setIamPolicy Set Bucket IAM Policy
1160 * @see https://cloud.google.com/storage/docs/json_api/v1/buckets/testIamPermissions Test Bucket Permissions
1161 * @see https://cloud.google.com/iam/docs/policies#versions policy versioning.
1162 * @codingStandardsIgnoreEnd
1163 *
1164 * @return Iam
1165 */
1166 public function iam()
1167 {
1168 if (!$this->iam) {
1169 $this->iam = new Iam(new IamBucket($this->connection), $this->identity['bucket'], ['parent' => null, 'args' => $this->identity]);
1170 }
1171 return $this->iam;
1172 }
1173 /**
1174 * Locks a provided retention policy on this bucket. Upon receiving a result,
1175 * the local bucket's data will be updated.
1176 *
1177 * Please note that in order for this call to succeed, the applicable
1178 * metageneration value will need to be available. It can either be supplied
1179 * explicitly through the `ifMetagenerationMatch` option or detected for you
1180 * by ensuring a value is cached locally (by calling
1181 * {@see Bucket::reload()} or
1182 * {@see Bucket::info()}, for example).
1183 *
1184 * Example:
1185 * ```
1186 * // Set a retention policy.
1187 * $bucket->update([
1188 * 'retentionPolicy' => [
1189 * 'retentionPeriod' => 604800 // One week in seconds.
1190 * ]
1191 * ]);
1192 * // Lock in the policy.
1193 * $info = $bucket->lockRetentionPolicy();
1194 * $retentionPolicy = $info['retentionPolicy'];
1195 *
1196 * // View the time from which the policy was enforced and effective. (RFC 3339 format)
1197 * echo $retentionPolicy['effectiveTime'] . PHP_EOL;
1198 *
1199 * // View whether or not the retention policy is locked. This will be
1200 * // `true` after a successful call to `lockRetentionPolicy`.
1201 * echo $retentionPolicy['isLocked'];
1202 * ```
1203 *
1204 * @see https://cloud.google.com/storage/docs/bucket-lock Bucket Lock Documentation
1205 *
1206 * @param array $options [optional] {
1207 * Configuration options.
1208 *
1209 * @type string $ifMetagenerationMatch Only locks the retention policy
1210 * if the bucket's metageneration matches this value. If not
1211 * provided the locally cached metageneration value will be used,
1212 * otherwise an exception will be thrown.
1213 * }
1214 * @throws \BadMethodCallException If no metageneration value is available.
1215 * @return array
1216 */
1217 public function lockRetentionPolicy(array $options = [])
1218 {
1219 if (!isset($options['ifMetagenerationMatch'])) {
1220 if (!isset($this->info['metageneration'])) {
1221 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().');
1222 }
1223 $options['ifMetagenerationMatch'] = $this->info['metageneration'];
1224 }
1225 return $this->info = $this->connection->lockRetentionPolicy($options + $this->identity);
1226 }
1227 /**
1228 * Create a Signed URL listing objects in this bucket.
1229 *
1230 * Example:
1231 * ```
1232 * $url = $bucket->signedUrl(time() + 3600);
1233 * ```
1234 *
1235 * ```
1236 * // Use V4 Signing
1237 * $url = $bucket->signedUrl(time() + 3600, [
1238 * 'version' => 'v4'
1239 * ]);
1240 * ```
1241 *
1242 * @see https://cloud.google.com/storage/docs/access-control/signed-urls Signed URLs
1243 *
1244 * @param Timestamp|\DateTimeInterface|int $expires Specifies when the URL
1245 * will expire. May provide an instance of {@see \Google\Cloud\Core\Timestamp},
1246 * [http://php.net/datetimeimmutable](`\DateTimeImmutable`), or a
1247 * UNIX timestamp as an integer.
1248 * @param array $options {
1249 * Configuration Options.
1250 *
1251 * @type string $cname The CNAME for the bucket, for instance
1252 * `https://cdn.example.com`. **Defaults to**
1253 * `https://storage.googleapis.com`.
1254 * @type string $contentMd5 The MD5 digest value in base64. If you
1255 * provide this, the client must provide this HTTP header with
1256 * this same value in its request. If provided, take care to
1257 * always provide this value as a base64 encoded string.
1258 * @type string $contentType If you provide this value, the client must
1259 * provide this HTTP header set to the same value.
1260 * @type bool $forceOpenssl If true, OpenSSL will be used regardless of
1261 * whether phpseclib is available. **Defaults to** `false`.
1262 * @type array $headers If additional headers are provided, the server
1263 * will check to make sure that the client provides matching
1264 * values. Provide headers as a key/value array, where the key is
1265 * the header name, and the value is an array of header values.
1266 * Headers with multiple values may provide values as a simple
1267 * array, or a comma-separated string. For a reference of allowed
1268 * headers, see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers).
1269 * Header values will be trimmed of leading and trailing spaces,
1270 * multiple spaces within values will be collapsed to a single
1271 * space, and line breaks will be replaced by an empty string.
1272 * V2 Signed URLs may not provide `x-goog-encryption-key` or
1273 * `x-goog-encryption-key-sha256` headers.
1274 * @type array $keyFile Keyfile data to use in place of the keyfile with
1275 * which the client was constructed. If `$options.keyFilePath` is
1276 * set, this option is ignored.
1277 * @type string $keyFilePath A path to a valid keyfile to use in place
1278 * of the keyfile with which the client was constructed.
1279 * @type string|array $scopes One or more authentication scopes to be
1280 * used with a key file. This option is ignored unless
1281 * `$options.keyFile` or `$options.keyFilePath` is set.
1282 * @type array $queryParams Additional query parameters to be included
1283 * as part of the signed URL query string. For allowed values,
1284 * see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers#query).
1285 * @type string $version One of "v2" or "v4". *Defaults to** `"v2"`.
1286 * }
1287 * @return string
1288 * @throws \InvalidArgumentException If the given expiration is invalid or in the past.
1289 * @throws \InvalidArgumentException If the given `$options.method` is not valid.
1290 * @throws \InvalidArgumentException If the given `$options.keyFilePath` is not valid.
1291 * @throws \InvalidArgumentException If the given custom headers are invalid.
1292 * @throws \RuntimeException If the keyfile does not contain the required information.
1293 */
1294 public function signedUrl($expires, array $options = [])
1295 {
1296 // May be overridden for testing.
1297 $signingHelper = $this->pluck('helper', $options, \false) ?: SigningHelper::getHelper();
1298 $resource = sprintf('/%s', $this->identity['bucket']);
1299 return $signingHelper->sign($this->connection, $expires, $resource, null, $options);
1300 }
1301 /**
1302 * Create a signed upload policy for uploading objects.
1303 *
1304 * This method generates and signs a policy document. You can use policy
1305 * documents to allow visitors to a website to upload files to Google Cloud
1306 * Storage without giving them direct write access.
1307 *
1308 * Google Cloud PHP does not support v2 post policies.
1309 *
1310 * Example:
1311 * ```
1312 * $policy = $bucket->generateSignedPostPolicyV4($objectName, new \DateTime('tomorrow'), [
1313 * 'conditions' => [
1314 * ['content-length-range', 0, 255]
1315 * ],
1316 * 'fields' => [
1317 * 'x-goog-meta-hello' => 'world',
1318 * 'success_action_redirect' => 'https://google.com'
1319 * ]
1320 * ]);
1321 *
1322 * echo '<form action="' . $policy['url'] . '" method="post" enctype="multipart/form-data">';
1323 * foreach ($policy['fields'] as $name => $value) {
1324 * echo '<input type="hidden" name="' . $name . '" value="' . $value . '">';
1325 * }
1326 *
1327 * echo 'Upload a file!<br>';
1328 * echo '<input type="file" name="file">';
1329 * echo '<button type="submit">Submit!</button>';
1330 * echo '</form>';
1331 * ```
1332 *
1333 * @see https://cloud.google.com/storage/docs/xml-api/post-object#policydocument Policy Documents
1334 *
1335 * @param string $objectName The path to the file in Google Cloud Storage,
1336 * relative to the bucket.
1337 * @param Timestamp|\DateTimeInterface|int $expires Specifies when the URL
1338 * will expire. May provide an instance of {@see \Google\Cloud\Core\Timestamp},
1339 * [http://php.net/datetimeimmutable](`\DateTimeImmutable`), or a
1340 * UNIX timestamp as an integer.
1341 * @param array $options [optional] {
1342 * Configuration options
1343 *
1344 * @type string $bucketBoundHostname The hostname for the bucket, for
1345 * instance `cdn.example.com`. May be used for Google Cloud Load
1346 * Balancers or for custom bucket CNAMEs. **Defaults to**
1347 * `storage.googleapis.com`.
1348 * @type array $conditions A list of arrays containing policy matching
1349 * conditions (e.g. `eq`, `starts-with`, `content-length-range`).
1350 * @type array $fields Additional form fields (do not include
1351 * `x-goog-signature`, `file`, `policy` or fields with an
1352 * `x-ignore` prefix), given as key/value pairs.
1353 * @type bool $forceOpenssl If true, OpenSSL will be used regardless of
1354 * whether phpseclib is available. **Defaults to** `false`.
1355 * @type array $keyFile Keyfile data to use in place of the keyfile with
1356 * which the client was constructed. If `$options.keyFilePath` is
1357 * set, this option is ignored.
1358 * @type string $keyFilePath A path to a valid Keyfile to use in place
1359 * of the keyfile with which the client was constructed.
1360 * @type string $scheme Either `http` or `https`. Only used if a custom
1361 * hostname is provided via `$options.bucketBoundHostname`. If a
1362 * custom bucketBoundHostname is provided, **defaults to** `http`.
1363 * In all other cases, **defaults to** `https`.
1364 * @type string|array $scopes One or more authentication scopes to be
1365 * used with a key file. This option is ignored unless
1366 * `$options.keyFile` or `$options.keyFilePath` is set.
1367 * @type bool $virtualHostedStyle If `true`, URL will be of form
1368 * `mybucket.storage.googleapis.com`. If `false`,
1369 * `storage.googleapis.com/mybucket`. **Defaults to** `false`.
1370 * }
1371 * @return array An associative array, containing (string) `uri` and
1372 * (array) `fields` keys.
1373 */
1374 public function generateSignedPostPolicyV4($objectName, $expires, array $options = [])
1375 {
1376 // May be overridden for testing.
1377 $signingHelper = $this->pluck('helper', $options, \false) ?: SigningHelper::getHelper();
1378 $resource = sprintf('/%s/%s', $this->identity['bucket'], $objectName);
1379 return $signingHelper->v4PostPolicy($this->connection, $expires, $resource, $options);
1380 }
1381 /**
1382 * Determines if an object name is required.
1383 *
1384 * @param mixed $data
1385 * @return bool
1386 */
1387 private function isObjectNameRequired($data)
1388 {
1389 return is_string($data) || is_null($data);
1390 }
1391 /**
1392 * Return a topic name in its fully qualified format.
1393 *
1394 * @param Topic|string $topic
1395 * @return string
1396 * @throws \InvalidArgumentException
1397 * @throws GoogleException
1398 */
1399 private function getFormattedTopic($topic)
1400 {
1401 if ($topic instanceof Topic) {
1402 return sprintf(self::NOTIFICATION_TEMPLATE, $topic->name());
1403 }
1404 if (!is_string($topic)) {
1405 throw new \InvalidArgumentException('$topic may only be a string or instance of Google\Cloud\PubSub\Topic');
1406 }
1407 if (preg_match('/projects\/[^\/]*\/topics\/(.*)/', $topic) === 1) {
1408 return sprintf(self::NOTIFICATION_TEMPLATE, $topic);
1409 }
1410 if (!$this->projectId) {
1411 throw new GoogleException('No project ID was provided, ' . 'and we were unable to detect a default project ID.');
1412 }
1413 return sprintf(self::NOTIFICATION_TEMPLATE, sprintf(self::TOPIC_TEMPLATE, $this->projectId, $topic));
1414 }
1415 }
1416