PluginProbe
WP-Stateless – Google Cloud Storage / 3.0.3
WP-Stateless – Google Cloud Storage v3.0.3
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
wp-stateless / lib / Google / vendor / google / cloud-storage / src / Bucket.php

Bucket.php in WP-Stateless – Google Cloud Storage 3.0.3, at lib/Google/vendor/google/cloud-storage/src/Bucket.php

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