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 / StorageObject.php

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

1,277 lines 54.0 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\NotFoundException;
22 use Google\Cloud\Core\Timestamp;
23 use Google\Cloud\Core\Upload\SignedUrlUploader;
24 use Google\Cloud\Storage\Connection\ConnectionInterface;
25 use GuzzleHttp\Promise\PromiseInterface;
26 use GuzzleHttp\Psr7;
27 use Psr\Http\Message\StreamInterface;
28
29 /**
30 * Objects are the individual pieces of data that you store in Google Cloud
31 * Storage.
32 *
33 * Example:
34 * ```
35 * use Google\Cloud\Storage\StorageClient;
36 *
37 * $storage = new StorageClient();
38 *
39 * $bucket = $storage->bucket('my-bucket');
40 * $object = $bucket->object('my-object');
41 * ```
42 */
43 class StorageObject
44 {
45 use ArrayTrait;
46 use EncryptionTrait;
47
48 /**
49 * @deprecated
50 */
51 const DEFAULT_DOWNLOAD_URL = SigningHelper::DEFAULT_DOWNLOAD_HOST;
52
53 /**
54 * @var Acl ACL for the object.
55 */
56 private $acl;
57
58 /**
59 * @var ConnectionInterface Represents a connection to Cloud Storage.
60 */
61 protected $connection;
62
63 /**
64 * @var array|null The object's encryption data.
65 */
66 private $encryptionData;
67
68 /**
69 * @var array The object's identity.
70 */
71 private $identity;
72
73 /**
74 * @var array|null The object's metadata.
75 */
76 private $info;
77
78 /**
79 * @param ConnectionInterface $connection Represents a connection to Cloud
80 * Storage.
81 * @param string $name The object's name.
82 * @param string $bucket The name of the bucket the object is contained in.
83 * @param string $generation [optional] The generation of the object.
84 * @param array $info [optional] The object's metadata.
85 * @param string $encryptionKey [optional] An AES-256 customer-supplied
86 * encryption key.
87 * @param string $encryptionKeySHA256 [optional] The SHA256 hash of the
88 * customer-supplied encryption key.
89 */
90 public function __construct(
91 ConnectionInterface $connection,
92 $name,
93 $bucket,
94 $generation = null,
95 array $info = [],
96 $encryptionKey = null,
97 $encryptionKeySHA256 = null
98 ) {
99 $this->connection = $connection;
100 $this->info = $info;
101 $this->encryptionData = [
102 'encryptionKey' => $encryptionKey,
103 'encryptionKeySHA256' => $encryptionKeySHA256
104 ];
105 $this->identity = [
106 'bucket' => $bucket,
107 'object' => $name,
108 'generation' => $generation,
109 'userProject' => $this->pluck('requesterProjectId', $info, false)
110 ];
111 $this->acl = new Acl($this->connection, 'objectAccessControls', $this->identity);
112 }
113
114 /**
115 * Configure ACL for this object.
116 *
117 * Example:
118 * ```
119 * $acl = $object->acl();
120 * ```
121 *
122 * @see https://cloud.google.com/storage/docs/access-control More about Access Control Lists
123 *
124 * @return Acl
125 */
126 public function acl()
127 {
128 return $this->acl;
129 }
130
131 /**
132 * Check whether or not the object exists.
133 *
134 * Example:
135 * ```
136 * if ($object->exists()) {
137 * echo 'Object exists!';
138 * }
139 * ```
140 *
141 * @param array $options [optional] Configuration options.
142 * @return bool
143 */
144 public function exists(array $options = [])
145 {
146 try {
147 $this->connection->getObject($this->identity + $options + ['fields' => 'name']);
148 } catch (NotFoundException $ex) {
149 return false;
150 }
151
152 return true;
153 }
154
155 /**
156 * Delete the object.
157 *
158 * Example:
159 * ```
160 * $object->delete();
161 * ```
162 *
163 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/delete Objects delete API documentation.
164 *
165 * @param array $options [optional] {
166 * Configuration options.
167 *
168 * @type string $ifGenerationMatch Makes the operation conditional on
169 * whether the object's current generation matches the given
170 * value.
171 * @type string $ifGenerationNotMatch Makes the operation conditional on
172 * whether the object's current generation does not match the
173 * given value.
174 * @type string $ifMetagenerationMatch Makes the operation conditional
175 * on whether the object's current metageneration matches the
176 * given value.
177 * @type string $ifMetagenerationNotMatch Makes the operation
178 * conditional on whether the object's current metageneration does
179 * not match the given value.
180 * }
181 * @return void
182 */
183 public function delete(array $options = [])
184 {
185 $this->connection->deleteObject($options + array_filter($this->identity));
186 }
187
188 /**
189 * Update the object. Upon receiving a result the local object's data will
190 * be updated.
191 *
192 * Example:
193 * ```
194 * // Add custom metadata to an existing object.
195 * $object->update([
196 * 'metadata' => [
197 * 'albumType' => 'family'
198 * ]
199 * ]);
200 * ```
201 *
202 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/patch Objects patch API documentation.
203 *
204 * @param array $metadata The available options for metadata are outlined
205 * at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects#resource)
206 * @param array $options [optional] {
207 * Configuration options.
208 *
209 * @type string $ifGenerationMatch Makes the operation conditional on
210 * whether the object's current generation matches the given
211 * value.
212 * @type string $ifGenerationNotMatch Makes the operation conditional on
213 * whether the object's current generation does not match the
214 * given value.
215 * @type string $ifMetagenerationMatch Makes the operation conditional
216 * on whether the object's current metageneration matches the
217 * given value.
218 * @type string $ifMetagenerationNotMatch Makes the operation
219 * conditional on whether the object's current metageneration does
220 * not match the given value.
221 * @type string $predefinedAcl Predefined ACL to apply to the object.
222 * Acceptable values include, `"authenticatedRead"`,
223 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
224 * `"projectPrivate"`, and `"publicRead"`.
225 * @type string $projection Determines which properties to return. May
226 * be either 'full' or 'noAcl'.
227 * @type string $fields Selector which will cause the response to only
228 * return the specified fields.
229 * }
230 * @return array
231 */
232 public function update(array $metadata, array $options = [])
233 {
234 $options += $metadata;
235
236 // can only set predefinedAcl or acl
237 if (isset($options['predefinedAcl'])) {
238 $options['acl'] = null;
239 }
240
241 return $this->info = $this->connection->patchObject($options + array_filter($this->identity));
242 }
243
244 /**
245 * Copy the object to a destination bucket.
246 *
247 * Please note that if the destination bucket is the same as the source
248 * bucket and a new name is not provided the source object will be replaced
249 * with the copy of itself.
250 *
251 * Example:
252 * ```
253 * // Provide your destination bucket as a string and retain the source
254 * // object's name.
255 * $copiedObject = $object->copy('otherBucket');
256 * ```
257 *
258 * ```
259 * // Provide your destination bucket as a bucket object and choose a new
260 * // name for the copied object.
261 * $otherBucket = $storage->bucket('otherBucket');
262 * $copiedObject = $object->copy($otherBucket, [
263 * 'name' => 'newFile.txt'
264 * ]);
265 * ```
266 *
267 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/copy Objects copy API documentation.
268 *
269 * @param Bucket|string $destination The destination bucket.
270 * @param array $options [optional] {
271 * Configuration options.
272 *
273 * @type string $name The name of the destination object. **Defaults
274 * to** the name of the source object.
275 * @type string $predefinedAcl Predefined ACL to apply to the object.
276 * Acceptable values include, `"authenticatedRead"`,
277 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
278 * `"projectPrivate"`, and `"publicRead"`.
279 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
280 * encryption key. It will be neccesary to provide this when a key
281 * was used during the object's creation.
282 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
283 * customer-supplied encryption key. This value will be calculated
284 * from the `encryptionKey` on your behalf if not provided, but
285 * for best performance it is recommended to pass in a cached
286 * version of the already calculated SHA.
287 * @type string $ifGenerationMatch Makes the operation conditional on
288 * whether the destination object's current generation matches the
289 * given value.
290 * @type string $ifGenerationNotMatch Makes the operation conditional on
291 * whether the destination object's current generation does not
292 * match the given value.
293 * @type string $ifMetagenerationMatch Makes the operation conditional
294 * on whether the destination object's current metageneration
295 * matches the given value.
296 * @type string $ifMetagenerationNotMatch Makes the operation
297 * conditional on whether the destination object's current
298 * metageneration does not match the given value.
299 * @type string $ifSourceGenerationMatch Makes the operation conditional
300 * on whether the source object's current generation matches the
301 * given value.
302 * @type string $ifSourceGenerationNotMatch Makes the operation
303 * conditional on whether the source object's current generation
304 * does not match the given value.
305 * @type string $ifSourceMetagenerationMatch Makes the operation
306 * conditional on whether the source object's current
307 * metageneration matches the given value.
308 * @type string $ifSourceMetagenerationNotMatch Makes the operation
309 * conditional on whether the source object's current
310 * metageneration does not match the given value.
311 * }
312 * @return StorageObject
313 */
314 public function copy($destination, array $options = [])
315 {
316 $key = isset($options['encryptionKey']) ? $options['encryptionKey'] : null;
317 $keySHA256 = isset($options['encryptionKeySHA256']) ? $options['encryptionKeySHA256'] : null;
318
319 $response = $this->connection->copyObject(
320 $this->formatDestinationRequest($destination, $options)
321 );
322
323 return new StorageObject(
324 $this->connection,
325 $response['name'],
326 $response['bucket'],
327 $response['generation'],
328 $response + ['requesterProjectId' => $this->identity['userProject']],
329 $key,
330 $keySHA256
331 );
332 }
333
334 /**
335 * Rewrite the object to a destination bucket.
336 *
337 * This method copies data using multiple requests so large objects can be
338 * copied with a normal length timeout per request rather than one very long
339 * timeout for a single request.
340 *
341 * Please note that if the destination bucket is the same as the source
342 * bucket and a new name is not provided the source object will be replaced
343 * with the copy of itself.
344 *
345 * Example:
346 * ```
347 * // Provide your destination bucket as a string and retain the source
348 * // object's name.
349 * $rewrittenObject = $object->rewrite('otherBucket');
350 * ```
351 *
352 * ```
353 * // Provide your destination bucket as a bucket object and choose a new
354 * // name for the copied object.
355 * $otherBucket = $storage->bucket('otherBucket');
356 * $rewrittenObject = $object->rewrite($otherBucket, [
357 * 'name' => 'newFile.txt'
358 * ]);
359 * ```
360 *
361 * ```
362 * // Rotate customer-supplied encryption keys.
363 * $key = file_get_contents(__DIR__ . '/key.txt');
364 * $destinationKey = base64_encode(openssl_random_pseudo_bytes(32)); // Make sure to remember your key.
365 *
366 * $rewrittenObject = $object->rewrite('otherBucket', [
367 * 'encryptionKey' => $key,
368 * 'destinationEncryptionKey' => $destinationKey
369 * ]);
370 * ```
371 *
372 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite Objects rewrite API documentation.
373 * @see https://cloud.google.com/storage/docs/encryption#customer-supplied Customer-supplied encryption keys.
374 *
375 * @param Bucket|string $destination The destination bucket.
376 * @param array $options [optional] {
377 * Configuration options.
378 *
379 * @type string $name The name of the destination object. **Defaults
380 * to** the name of the source object.
381 * @type string $predefinedAcl Predefined ACL to apply to the object.
382 * Acceptable values include, `"authenticatedRead"`,
383 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
384 * `"projectPrivate"`, and `"publicRead"`.
385 * @type string $maxBytesRewrittenPerCall The maximum number of bytes
386 * that will be rewritten per rewrite request. Most callers
387 * shouldn't need to specify this parameter - it is primarily in
388 * place to support testing. If specified the value must be an
389 * integral multiple of 1 MiB (1048576). Also, this only applies
390 * to requests where the source and destination span locations
391 * and/or storage classes.
392 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
393 * encryption key. It will be neccesary to provide this when a key
394 * was used during the object's creation.
395 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
396 * customer-supplied encryption key. This value will be calculated
397 * from the `encryptionKey` on your behalf if not provided, but
398 * for best performance it is recommended to pass in a cached
399 * version of the already calculated SHA.
400 * @type string $destinationEncryptionKey A base64 encoded AES-256
401 * customer-supplied encryption key that will be used to encrypt
402 * the rewritten object.
403 * @type string $destinationEncryptionKeySHA256 Base64 encoded SHA256
404 * hash of the customer-supplied destination encryption key. This
405 * value will be calculated from the `destinationEncryptionKey` on
406 * your behalf if not provided, but for best performance it is
407 * recommended to pass in a cached version of the already
408 * calculated SHA.
409 * @type string $destinationKmsKeyName Name of the Cloud KMS key that
410 * will be used to encrypt the object. Should be in the format
411 * `projects/my-project/locations/kr-location/keyRings/my-kr/cryptoKeys/my-key`.
412 * Please note the KMS key ring must use the same location as the
413 * destination bucket.
414 * @type string $ifGenerationMatch Makes the operation conditional on
415 * whether the destination object's current generation matches the
416 * given value.
417 * @type string $ifGenerationNotMatch Makes the operation conditional on
418 * whether the destination object's current generation does not
419 * match the given value.
420 * @type string $ifMetagenerationMatch Makes the operation conditional
421 * on whether the destination object's current metageneration
422 * matches the given value.
423 * @type string $ifMetagenerationNotMatch Makes the operation
424 * conditional on whether the destination object's current
425 * metageneration does not match the given value.
426 * @type string $ifSourceGenerationMatch Makes the operation conditional
427 * on whether the source object's current generation matches the
428 * given value.
429 * @type string $ifSourceGenerationNotMatch Makes the operation
430 * conditional on whether the source object's current generation
431 * does not match the given value.
432 * @type string $ifSourceMetagenerationMatch Makes the operation
433 * conditional on whether the source object's current
434 * metageneration matches the given value.
435 * @type string $ifSourceMetagenerationNotMatch Makes the operation
436 * conditional on whether the source object's current
437 * metageneration does not match the given value.
438 * }
439 * @return StorageObject
440 * @throws \InvalidArgumentException
441 */
442 public function rewrite($destination, array $options = [])
443 {
444 $options['useCopySourceHeaders'] = true;
445 $destinationKey = isset($options['destinationEncryptionKey']) ? $options['destinationEncryptionKey'] : null;
446 $destinationKeySHA256 = isset($options['destinationEncryptionKeySHA256'])
447 ? $options['destinationEncryptionKeySHA256']
448 : null;
449
450 $options = $this->formatDestinationRequest($destination, $options);
451
452 do {
453 $response = $this->connection->rewriteObject($options);
454 $options['rewriteToken'] = isset($response['rewriteToken']) ? $response['rewriteToken'] : null;
455 } while ($options['rewriteToken']);
456
457 return new StorageObject(
458 $this->connection,
459 $response['resource']['name'],
460 $response['resource']['bucket'],
461 $response['resource']['generation'],
462 $response['resource'] + ['requesterProjectId' => $this->identity['userProject']],
463 $destinationKey,
464 $destinationKeySHA256
465 );
466 }
467
468 /**
469 * Renames the object.
470 *
471 * Please note that there is no atomic rename provided by the Storage API.
472 * This method is for convenience and is a set of sequential calls to copy
473 * and delete. Upon success the source object's metadata will be cleared,
474 * please use the returned object instead.
475 *
476 * Example:
477 * ```
478 * $object2 = $object->rename('object2.txt');
479 * echo $object2->name();
480 * ```
481 *
482 * @param string $name The new name.
483 * @param array $options [optional] {
484 * Configuration options.
485 *
486 * @type string $predefinedAcl Predefined ACL to apply to the object.
487 * Acceptable values include, `"authenticatedRead"`,
488 * `"bucketOwnerFullControl"`, `"bucketOwnerRead"`, `"private"`,
489 * `"projectPrivate"`, and `"publicRead"`.
490 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
491 * encryption key. It will be neccesary to provide this when a key
492 * was used during the object's creation.
493 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
494 * customer-supplied encryption key. This value will be calculated
495 * from the `encryptionKey` on your behalf if not provided, but
496 * for best performance it is recommended to pass in a cached
497 * version of the already calculated SHA.
498 * @type string $ifGenerationMatch Makes the operation conditional on
499 * whether the destination object's current generation matches the
500 * given value.
501 * @type string $ifGenerationNotMatch Makes the operation conditional on
502 * whether the destination object's current generation does not
503 * match the given value.
504 * @type string $ifMetagenerationMatch Makes the operation conditional
505 * on whether the destination object's current metageneration
506 * matches the given value.
507 * @type string $ifMetagenerationNotMatch Makes the operation
508 * conditional on whether the destination object's current
509 * metageneration does not match the given value.
510 * @type string $ifSourceGenerationMatch Makes the operation conditional
511 * on whether the source object's current generation matches the
512 * given value.
513 * @type string $ifSourceGenerationNotMatch Makes the operation
514 * conditional on whether the source object's current generation
515 * does not match the given value.
516 * @type string $ifSourceMetagenerationMatch Makes the operation
517 * conditional on whether the source object's current
518 * metageneration matches the given value.
519 * @type string $ifSourceMetagenerationNotMatch Makes the operation
520 * conditional on whether the source object's current
521 * metageneration does not match the given value.
522 * @type string $destinationBucket Will move to this bucket if set. If
523 * not set, will default to the same bucket.
524 * }
525 * @return StorageObject The renamed object.
526 */
527 public function rename($name, array $options = [])
528 {
529 $destinationBucket = isset($options['destinationBucket'])
530 ? $options['destinationBucket']
531 : $this->identity['bucket'];
532 unset($options['destinationBucket']);
533
534 $copiedObject = $this->copy($destinationBucket, [
535 'name' => $name
536 ] + $options);
537
538 $this->delete(
539 array_intersect_key($options, [
540 'restOptions' => null,
541 'retries' => null
542 ])
543 );
544 $this->info = [];
545
546 return $copiedObject;
547 }
548
549 /**
550 * Download an object as a string.
551 *
552 * For an example of setting the range header to download a subrange of the
553 * object please see {@see Google\Cloud\Storage\StorageObject::downloadAsStream()}.
554 *
555 * Example:
556 * ```
557 * $string = $object->downloadAsString();
558 * echo $string;
559 * ```
560 *
561 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/get Objects get API documentation.
562 * @see https://cloud.google.com/storage/docs/json_api/v1/parameters#range Learn more about the Range header.
563 *
564 * @param array $options [optional] {
565 * Configuration Options.
566 *
567 * @type string $encryptionKey An AES-256 customer-supplied encryption
568 * key. It will be neccesary to provide this when a key was used
569 * during the object's creation. If provided one must also include
570 * an `encryptionKeySHA256`.
571 * @type string $encryptionKeySHA256 The SHA256 hash of the
572 * customer-supplied encryption key. It will be neccesary to
573 * provide this when a key was used during the object's creation.
574 * If provided one must also include an `encryptionKey`.
575 * }
576 * @return string
577 */
578 public function downloadAsString(array $options = [])
579 {
580 return (string) $this->downloadAsStream($options);
581 }
582
583 /**
584 * Download an object to a specified location.
585 *
586 * For an example of setting the range header to download a subrange of the
587 * object please see {@see Google\Cloud\Storage\StorageObject::downloadAsStream()}.
588 *
589 * Example:
590 * ```
591 * $stream = $object->downloadToFile(__DIR__ . '/my-file.txt');
592 * ```
593 *
594 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/get Objects get API documentation.
595 * @see https://cloud.google.com/storage/docs/json_api/v1/parameters#range Learn more about the Range header.
596 *
597 * @param string $path Path to download the file to.
598 * @param array $options [optional] {
599 * Configuration Options.
600 *
601 * @type string $encryptionKey An AES-256 customer-supplied encryption
602 * key. It will be neccesary to provide this when a key was used
603 * during the object's creation. If provided one must also include
604 * an `encryptionKeySHA256`.
605 * @type string $encryptionKeySHA256 The SHA256 hash of the
606 * customer-supplied encryption key. It will be neccesary to
607 * provide this when a key was used during the object's creation.
608 * If provided one must also include an `encryptionKey`.
609 * }
610 * @return StreamInterface
611 */
612 public function downloadToFile($path, array $options = [])
613 {
614 $destination = Psr7\stream_for(fopen($path, 'w'));
615
616 Psr7\copy_to_stream(
617 $this->downloadAsStream($options),
618 $destination
619 );
620
621 $destination->seek(0);
622
623 return $destination;
624 }
625
626 /**
627 * Download an object as a stream.
628 *
629 * Please note Google Cloud Storage respects the Range header as specified
630 * by [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1). See below
631 * for an example of this in action.
632 *
633 * Example:
634 * ```
635 * $stream = $object->downloadAsStream();
636 * echo $stream->getContents();
637 * ```
638 *
639 * ```
640 * // Set the Range header in order to download a subrange of the object. For more examples of
641 * // setting the Range header, please see [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1).
642 * $firstFiveBytes = '0-4'; // Get the first 5 bytes.
643 * $fromFifthByteToLastByte = '4-'; // Get the bytes starting with the 5th to the last.
644 * $lastFiveBytes = '-5'; // Get the last 5 bytes.
645 *
646 * $stream = $object->downloadAsStream([
647 * 'restOptions' => [
648 * 'headers' => [
649 * 'Range' => "bytes=$firstFiveBytes"
650 * ]
651 * ]
652 * ]);
653 * ```
654 *
655 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/get Objects get API documentation.
656 * @see https://cloud.google.com/storage/docs/json_api/v1/parameters#range Learn more about the Range header.
657 *
658 * @param array $options [optional] {
659 * Configuration Options.
660 *
661 * @type string $encryptionKey An AES-256 customer-supplied encryption
662 * key. It will be neccesary to provide this when a key was used
663 * during the object's creation. If provided one must also include
664 * an `encryptionKeySHA256`.
665 * @type string $encryptionKeySHA256 The SHA256 hash of the
666 * customer-supplied encryption key. It will be neccesary to
667 * provide this when a key was used during the object's creation.
668 * If provided one must also include an `encryptionKey`.
669 * }
670 * @return StreamInterface
671 */
672 public function downloadAsStream(array $options = [])
673 {
674 return $this->connection->downloadObject(
675 $this->formatEncryptionHeaders(
676 $options
677 + $this->encryptionData
678 + array_filter($this->identity)
679 )
680 );
681 }
682
683 /**
684 * Asynchronously download an object as a stream.
685 *
686 * For an example of setting the range header to download a subrange of the
687 * object please see {@see Google\Cloud\Storage\StorageObject::downloadAsStream()}.
688 *
689 * Example:
690 * ```
691 * use Psr\Http\Message\StreamInterface;
692 *
693 * $promise = $object->downloadAsStreamAsync()
694 * ->then(function (StreamInterface $data) {
695 * echo $data->getContents();
696 * });
697 *
698 * $promise->wait();
699 * ```
700 *
701 * ```
702 * // Download all objects in a bucket asynchronously.
703 * use GuzzleHttp\Promise;
704 * use Psr\Http\Message\StreamInterface;
705 *
706 * $promises = [];
707 *
708 * foreach ($bucket->objects() as $object) {
709 * $promises[] = $object->downloadAsStreamAsync()
710 * ->then(function (StreamInterface $data) {
711 * echo $data->getContents();
712 * });
713 * }
714 *
715 * Promise\unwrap($promises);
716 * ```
717 *
718 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/get Objects get API documentation.
719 * @see https://cloud.google.com/storage/docs/json_api/v1/parameters#range Learn more about the Range header.
720 * @see https://github.com/guzzle/promises Learn more about Guzzle Promises
721 *
722 * @param array $options [optional] {
723 * Configuration Options.
724 *
725 * @type string $encryptionKey An AES-256 customer-supplied encryption
726 * key. It will be neccesary to provide this when a key was used
727 * during the object's creation. If provided one must also include
728 * an `encryptionKeySHA256`.
729 * @type string $encryptionKeySHA256 The SHA256 hash of the
730 * customer-supplied encryption key. It will be neccesary to
731 * provide this when a key was used during the object's creation.
732 * If provided one must also include an `encryptionKey`.
733 * }
734 * @return PromiseInterface<StreamInterface>
735 * @experimental The experimental flag means that while we believe this method
736 * or class is ready for use, it may change before release in backwards-
737 * incompatible ways. Please use with caution, and test thoroughly when
738 * upgrading.
739 */
740 public function downloadAsStreamAsync(array $options = [])
741 {
742 return $this->connection->downloadObjectAsync(
743 $this->formatEncryptionHeaders(
744 $options
745 + $this->encryptionData
746 + array_filter($this->identity)
747 )
748 );
749 }
750
751 /**
752 * Create a Signed URL for this object.
753 *
754 * Signed URLs can be complex, and it is strongly recommended you read and
755 * understand the [documentation](https://cloud.google.com/storage/docs/access-control/signed-urls).
756 *
757 * In cases where a keyfile is available, signing is accomplished in the
758 * client using your Service Account private key. In Google Compute Engine,
759 * signing is accomplished using
760 * [IAM signBlob](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/signBlob).
761 * Signing using IAM requires that your service account be granted the
762 * `iam.serviceAccounts.signBlob` permission, part of the "Service Account
763 * Token Creator" IAM role.
764 *
765 * Additionally, signing using IAM requires different scopes. When creating
766 * an instance of {@see Google\Cloud\Storage\StorageClient}, provide the
767 * `https://www.googleapis.com/auth/cloud-platform` scopein `$options.scopes`.
768 * This scope may be used entirely in place of the scopes provided in
769 * {@see Google\Cloud\Storage\StorageClient}.
770 *
771 * App Engine and Compute Engine will attempt to sign URLs using IAM.
772 *
773 * Example:
774 * ```
775 * $url = $object->signedUrl(new \DateTime('tomorrow'));
776 * ```
777 *
778 * ```
779 * // Create a signed URL allowing updates to the object.
780 * $url = $object->signedUrl(new \DateTime('tomorrow'), [
781 * 'method' => 'PUT'
782 * ]);
783 * ```
784 *
785 * ```
786 * // Use Signed URLs v4
787 * $url = $object->signedUrl(new \DateTime('tomorrow'), [
788 * 'version' => 'v4'
789 * ]);
790 * ```
791 *
792 * ```
793 * // Using Bucket-Bound hostnames
794 * // By default, a custom bucket-bound hostname will use `http` as the schema rather than `https`.
795 * // In order to get an https URI, we need to specify the proper scheme.
796 * $url = $object->signedUrl(new \DateTime('tomorrow'), [
797 * 'version' => 'v4',
798 * 'bucketBoundHostname' => 'cdn.example.com',
799 * 'scheme' => 'https'
800 * ]);
801 * ```
802 *
803 * ```
804 * // Using virtual hosted style URIs
805 * // When true, returns a URL with the hostname `<bucket>.storage.googleapis.com`.
806 * $url = $object->signedUrl(new \DateTime('tomorrow'), [
807 * 'virtualHostedStyle' => true
808 * ]);
809 * ````
810 *
811 * @see https://cloud.google.com/storage/docs/access-control/signed-urls Signed URLs
812 *
813 * @param Timestamp|\DateTimeInterface|int $expires Specifies when the URL
814 * will expire. May provide an instance of {@see Google\Cloud\Core\Timestamp},
815 * [http://php.net/datetimeimmutable](`\DateTimeImmutable`), or a
816 * UNIX timestamp as an integer.
817 * @param array $options {
818 * Configuration Options.
819 *
820 * @type string $bucketBoundHostname The hostname for the bucket, for
821 * instance `cdn.example.com`. May be used for Google Cloud Load
822 * Balancers or for custom bucket CNAMEs. **Defaults to**
823 * `storage.googleapis.com`.
824 * @type string $contentMd5 The MD5 digest value in base64. If you
825 * provide this, the client must provide this HTTP header with
826 * this same value in its request. If provided, take care to
827 * always provide this value as a base64 encoded string.
828 * @type string $contentType If you provide this value, the client must
829 * provide this HTTP header set to the same value.
830 * @type bool $forceOpenssl If true, OpenSSL will be used regardless of
831 * whether phpseclib is available. **Defaults to** `false`.
832 * @type array $headers If additional headers are provided, the server
833 * will check to make sure that the client provides matching
834 * values. Provide headers as a key/value array, where the key is
835 * the header name, and the value is an array of header values.
836 * Headers with multiple values may provide values as a simple
837 * array, or a comma-separated string. For a reference of allowed
838 * headers, see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers).
839 * Header values will be trimmed of leading and trailing spaces,
840 * multiple spaces within values will be collapsed to a single
841 * space, and line breaks will be replaced by an empty string.
842 * V2 Signed URLs may not provide `x-goog-encryption-key` or
843 * `x-goog-encryption-key-sha256` headers.
844 * @type array $keyFile Keyfile data to use in place of the keyfile with
845 * which the client was constructed. If `$options.keyFilePath` is
846 * set, this option is ignored.
847 * @type string $keyFilePath A path to a valid Keyfile to use in place
848 * of the keyfile with which the client was constructed.
849 * @type string $method One of `GET`, `PUT` or `DELETE`.
850 * **Defaults to** `GET`.
851 * @type string $responseDisposition The
852 * [`response-content-disposition`](http://www.iana.org/assignments/cont-disp/cont-disp.xhtml)
853 * parameter of the signed url.
854 * @type string $responseType The `response-content-type` parameter of the
855 * signed url. When the server contentType is `null`, this option
856 * may be used to control the content type of the response.
857 * @type string $saveAsName The filename to prompt the user to save the
858 * file as when the signed url is accessed. This is ignored if
859 * `$options.responseDisposition` is set.
860 * @type string $scheme Either `http` or `https`. Only used if a custom
861 * hostname is provided via `$options.bucketBoundHostname`. If a
862 * custom bucketBoundHostname is provided, **defaults to** `http`.
863 * In all other cases, **defaults to** `https`.
864 * @type string|array $scopes One or more authentication scopes to be
865 * used with a key file. This option is ignored unless
866 * `$options.keyFile` or `$options.keyFilePath` is set.
867 * @type array $queryParams Additional query parameters to be included
868 * as part of the signed URL query string. For allowed values,
869 * see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers#query).
870 * @type string $version One of "v2" or "v4". **Defaults to** `"v2"`.
871 * @type bool $virtualHostedStyle If `true`, URL will be of form
872 * `mybucket.storage.googleapis.com`. If `false`,
873 * `storage.googleapis.com/mybucket`. **Defaults to** `false`.
874 * }
875 * @return string
876 * @throws \InvalidArgumentException If the given expiration is invalid or in the past.
877 * @throws \InvalidArgumentException If the given `$options.method` is not valid.
878 * @throws \InvalidArgumentException If the given `$options.keyFilePath` is not valid.
879 * @throws \InvalidArgumentException If the given custom headers are invalid.
880 * @throws \InvalidArgumentException If the keyfile does not contain the required information.
881 * @throws \RuntimeException If the credentials provided cannot be used for signing strings.
882 */
883 public function signedUrl($expires, array $options = [])
884 {
885 // May be overridden for testing.
886 $signingHelper = $this->pluck('helper', $options, false)
887 ?: SigningHelper::getHelper();
888
889 $resource = sprintf(
890 '/%s/%s',
891 $this->identity['bucket'],
892 $this->identity['object']
893 );
894
895 return $signingHelper->sign(
896 $this->connection,
897 $expires,
898 $resource,
899 $this->identity['generation'],
900 $options
901 );
902 }
903
904 /**
905 * Create a Signed Upload URL for this object.
906 *
907 * This method differs from {@see Google\Cloud\Storage\StorageObject::signedUrl()}
908 * in that it allows you to initiate a new resumable upload session. This
909 * can be used to allow non-authenticated users to insert an object into a
910 * bucket.
911 *
912 * In order to upload data, a session URI must be
913 * obtained by sending an HTTP POST request to the URL returned from this
914 * method. See the [Cloud Storage Documentation](https://goo.gl/b1ZiZm) for
915 * more information.
916 *
917 * If you prefer to skip this initial step, you may find
918 * {@see Google\Cloud\Storage\StorageObject::beginSignedUploadSession()} to
919 * fit your needs. Note that `beginSignedUploadSession()` cannot be used
920 * with Google Cloud PHP's Signed URL Uploader, and does not support a
921 * configurable expiration date.
922 *
923 * Example:
924 * ```
925 * $url = $object->signedUploadUrl(new \DateTime('tomorrow'));
926 * ```
927 *
928 * ```
929 * // Use Signed URLs v4
930 * $url = $object->signedUploadUrl(new \DateTime('tomorrow'), [
931 * 'version' => 'v4'
932 * ]);
933 * ```
934 *
935 * @param Timestamp|\DateTimeInterface|int $expires Specifies when the URL
936 * will expire. May provide an instance of {@see Google\Cloud\Core\Timestamp},
937 * [http://php.net/datetimeimmutable](`\DateTimeImmutable`), or a
938 * UNIX timestamp as an integer.
939 * @param array $options {
940 * Configuration Options.
941 *
942 * @type string $contentMd5 The MD5 digest value in base64. If you
943 * provide this, the client must provide this HTTP header with
944 * this same value in its request. If provided, take care to
945 * always provide this value as a base64 encoded string.
946 * @type string $contentType If you provide this value, the client must
947 * provide this HTTP header set to the same value.
948 * @type bool $forceOpenssl If true, OpenSSL will be used regardless of
949 * whether phpseclib is available. **Defaults to** `false`.
950 * @type array $headers If additional headers are provided, the server
951 * will check to make sure that the client provides matching
952 * values. Provide headers as a key/value array, where the key is
953 * the header name, and the value is an array of header values.
954 * Headers with multiple values may provide values as a simple
955 * array, or a comma-separated string. For a reference of allowed
956 * headers, see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers).
957 * Header values will be trimmed of leading and trailing spaces,
958 * multiple spaces within values will be collapsed to a single
959 * space, and line breaks will be replaced by an empty string.
960 * V2 Signed URLs may not provide `x-goog-encryption-key` or
961 * `x-goog-encryption-key-sha256` headers.
962 * @type array $keyFile Keyfile data to use in place of the keyfile with
963 * which the client was constructed. If `$options.keyFilePath` is
964 * set, this option is ignored.
965 * @type string $keyFilePath A path to a valid Keyfile to use in place
966 * of the keyfile with which the client was constructed.
967 * @type string $responseDisposition The
968 * [`response-content-disposition`](http://www.iana.org/assignments/cont-disp/cont-disp.xhtml)
969 * parameter of the signed url.
970 * @type string $responseType The `response-content-type` parameter of the
971 * signed url. When the server contentType is `null`, this option
972 * may be used to control the content type of the response.
973 * @type string $saveAsName The filename to prompt the user to save the
974 * file as when the signed url is accessed. This is ignored if
975 * `$options.responseDisposition` is set.
976 * @type string $scheme Either `http` or `https`. Only used if a custom
977 * hostname is provided via `$options.bucketBoundHostname`. In all
978 * other cases, `https` is used. When a custom bucketBoundHostname
979 * is provided, **defaults to** `http`.
980 * @type string|array $scopes One or more authentication scopes to be
981 * used with a key file. This option is ignored unless
982 * `$options.keyFile` or `$options.keyFilePath` is set.
983 * @type array $queryParams Additional query parameters to be included
984 * as part of the signed URL query string. For allowed values,
985 * see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers#query).
986 * @type string $version One of "v2" or "v4". **Defaults to** `"v2"`.
987 * }
988 * @return string
989 */
990 public function signedUploadUrl($expires, array $options = [])
991 {
992 $options += [
993 'headers' => []
994 ];
995
996 $options['headers']['x-goog-resumable'] = 'start';
997
998 unset(
999 $options['cname'],
1000 $options['bucketBoundHostname'],
1001 $options['saveAsName'],
1002 $options['responseDisposition'],
1003 $options['responseType'],
1004 $options['virtualHostedStyle']
1005 );
1006
1007 return $this->signedUrl($expires, [
1008 'method' => 'POST',
1009 'allowPost' => true
1010 ] + $options);
1011 }
1012
1013 /**
1014 * Create a signed URL upload session.
1015 *
1016 * The returned URL differs from the return value of
1017 * {@see Google\Cloud\Storage\StorageObject::signedUploadUrl()} in that it
1018 * is ready to accept upload data immediately via an HTTP PUT request.
1019 *
1020 * Because an upload session is created by the client, the expiration date
1021 * is not configurable. The URL generated by this method is valid for one
1022 * week.
1023 *
1024 * Example:
1025 * ```
1026 * $url = $object->beginSignedUploadSession();
1027 * ```
1028 *
1029 * ```
1030 * // Use Signed URLs v4
1031 * $url = $object->beginSignedUploadSession([
1032 * 'version' => 'v4'
1033 * ]);
1034 * ```
1035 *
1036 * @see https://cloud.google.com/storage/docs/xml-api/resumable-upload#practices Resumable Upload Best Practices
1037 *
1038 * @param array $options {
1039 * Configuration Options.
1040 *
1041 * @type string $contentMd5 The MD5 digest value in base64. If you
1042 * provide this, the client must provide this HTTP header with
1043 * this same value in its request. If provided, take care to
1044 * always provide this value as a base64 encoded string.
1045 * @type string $contentType If you provide this value, the client must
1046 * provide this HTTP header set to the same value.
1047 * @type bool $forceOpenssl If true, OpenSSL will be used regardless of
1048 * whether phpseclib is available. **Defaults to** `false`.
1049 * @type array $headers If additional headers are provided, the server
1050 * will check to make sure that the client provides matching
1051 * values. Provide headers as a key/value array, where the key is
1052 * the header name, and the value is an array of header values.
1053 * Headers with multiple values may provide values as a simple
1054 * array, or a comma-separated string. For a reference of allowed
1055 * headers, see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers).
1056 * Header values will be trimmed of leading and trailing spaces,
1057 * multiple spaces within values will be collapsed to a single
1058 * space, and line breaks will be replaced by an empty string.
1059 * V2 Signed URLs may not provide `x-goog-encryption-key` or
1060 * `x-goog-encryption-key-sha256` headers.
1061 * @type array $keyFile Keyfile data to use in place of the keyfile with
1062 * which the client was constructed. If `$options.keyFilePath` is
1063 * set, this option is ignored.
1064 * @type string $keyFilePath A path to a valid Keyfile to use in place
1065 * of the keyfile with which the client was constructed.
1066 * @type string $origin Value of CORS header
1067 * "Access-Control-Allow-Origin". **Defaults to** `"*"`.
1068 * @type string|array $scopes One or more authentication scopes to be
1069 * used with a key file. This option is ignored unless
1070 * `$options.keyFile` or `$options.keyFilePath` is set.
1071 * @type array $queryParams Additional query parameters to be included
1072 * as part of the signed URL query string. For allowed values,
1073 * see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers#query).
1074 * @type string $version One of "v2" or "v4". **Defaults to** `"v2"`.
1075 * }
1076 * @return string
1077 */
1078 public function beginSignedUploadSession(array $options = [])
1079 {
1080 $expires = new \DateTimeImmutable('+1 minute');
1081 $startUri = $this->signedUploadUrl($expires, $options);
1082
1083 $uploaderOptions = $this->pluckArray([
1084 'contentType',
1085 'origin'
1086 ], $options);
1087
1088 if (!isset($uploaderOptions['origin'])) {
1089 $uploaderOptions['origin'] = '*';
1090 }
1091
1092 $uploader = new SignedUrlUploader($this->connection->requestWrapper(), '', $startUri, $uploaderOptions);
1093
1094 return $uploader->getResumeUri();
1095 }
1096
1097 /**
1098 * Retrieves the object's details. If no object data is cached a network
1099 * request will be made to retrieve it.
1100 *
1101 * Example:
1102 * ```
1103 * $info = $object->info();
1104 * echo $info['size'];
1105 * ```
1106 *
1107 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/get Objects get API documentation.
1108 *
1109 * @param array $options [optional] {
1110 * Configuration options.
1111 *
1112 * @type string $encryptionKey An AES-256 customer-supplied encryption
1113 * key. It will be neccesary to provide this when a key was used
1114 * during the object's creation in order to retrieve the MD5 hash
1115 * and CRC32C checksum. If provided one must also include an
1116 * `encryptionKeySHA256`.
1117 * @type string $encryptionKeySHA256 The SHA256 hash of the
1118 * customer-supplied encryption key. It will be neccesary to
1119 * provide this when a key was used during the object's creation
1120 * in order to retrieve the MD5 hash and CRC32C checksum. If
1121 * provided one must also include an `encryptionKey`.
1122 * @type string $ifGenerationMatch Makes the operation conditional on
1123 * whether the object's current generation matches the given
1124 * value.
1125 * @type string $ifGenerationNotMatch Makes the operation conditional on
1126 * whether the object's current generation does not match the
1127 * given value.
1128 * @type string $ifMetagenerationMatch Makes the operation conditional
1129 * on whether the object's current metageneration matches the
1130 * given value.
1131 * @type string $ifMetagenerationNotMatch Makes the operation
1132 * conditional on whether the object's current metageneration does
1133 * not match the given value.
1134 * @type string $projection Determines which properties to return. May
1135 * be either 'full' or 'noAcl'.
1136 * }
1137 * @return array
1138 */
1139 public function info(array $options = [])
1140 {
1141 return $this->info ?: $this->reload($options);
1142 }
1143
1144 /**
1145 * Triggers a network request to reload the object's details.
1146 *
1147 * Example:
1148 * ```
1149 * $object->reload();
1150 * $info = $object->info();
1151 * echo $info['location'];
1152 * ```
1153 *
1154 * @see https://cloud.google.com/storage/docs/json_api/v1/objects/get Objects get API documentation.
1155 *
1156 * @param array $options [optional] {
1157 * Configuration options.
1158 *
1159 * @type string $encryptionKey A base64 encoded AES-256 customer-supplied
1160 * encryption key. It will be neccesary to provide this when a key
1161 * was used during the object's creation.
1162 * @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
1163 * customer-supplied encryption key. This value will be calculated
1164 * from the `encryptionKey` on your behalf if not provided, but
1165 * for best performance it is recommended to pass in a cached
1166 * version of the already calculated SHA.
1167 * @type string $ifGenerationMatch Makes the operation conditional on
1168 * whether the object's current generation matches the given
1169 * value.
1170 * @type string $ifGenerationNotMatch Makes the operation conditional on
1171 * whether the object's current generation does not match the
1172 * given value.
1173 * @type string $ifMetagenerationMatch Makes the operation conditional
1174 * on whether the object's current metageneration matches the
1175 * given value.
1176 * @type string $ifMetagenerationNotMatch Makes the operation
1177 * conditional on whether the object's current metageneration does
1178 * not match the given value.
1179 * @type string $projection Determines which properties to return. May
1180 * be either 'full' or 'noAcl'.
1181 * }
1182 * @return array
1183 */
1184 public function reload(array $options = [])
1185 {
1186 return $this->info = $this->connection->getObject(
1187 $this->formatEncryptionHeaders(
1188 $options
1189 + $this->encryptionData
1190 + array_filter($this->identity)
1191 )
1192 );
1193 }
1194
1195 /**
1196 * Retrieves the object's name.
1197 *
1198 * Example:
1199 * ```
1200 * echo $object->name();
1201 * ```
1202 *
1203 * @return string
1204 */
1205 public function name()
1206 {
1207 return $this->identity['object'];
1208 }
1209
1210 /**
1211 * Retrieves the object's identity.
1212 *
1213 * Example:
1214 * ```
1215 * echo $object->identity()['object'];
1216 * ```
1217 *
1218 * @return array
1219 */
1220 public function identity()
1221 {
1222 return $this->identity;
1223 }
1224
1225 /**
1226 * Formats the object as a string in the following format:
1227 * `gs://{bucket-name}/{object-name}`.
1228 *
1229 * Example:
1230 * ```
1231 * echo $object->gcsUri();
1232 * ```
1233 *
1234 * @return string
1235 */
1236 public function gcsUri()
1237 {
1238 return sprintf(
1239 'gs://%s/%s',
1240 $this->identity['bucket'],
1241 $this->identity['object']
1242 );
1243 }
1244
1245 /**
1246 * Formats a destination based request, such as copy or rewrite.
1247 *
1248 * @param string|Bucket $destination The destination bucket.
1249 * @param array $options Options to configure.
1250 * @return array
1251 */
1252 private function formatDestinationRequest($destination, array $options)
1253 {
1254 if (!is_string($destination) && !($destination instanceof Bucket)) {
1255 throw new \InvalidArgumentException(
1256 '$destination must be either a string or an instance of Bucket.'
1257 );
1258 }
1259
1260 $destAcl = isset($options['predefinedAcl']) ? $options['predefinedAcl'] : null;
1261 $destObject = isset($options['name']) ? $options['name'] : $this->identity['object'];
1262
1263 unset($options['name']);
1264 unset($options['predefinedAcl']);
1265
1266 return array_filter([
1267 'destinationBucket' => $destination instanceof Bucket ? $destination->name() : $destination,
1268 'destinationObject' => $destObject,
1269 'destinationPredefinedAcl' => $destAcl,
1270 'sourceBucket' => $this->identity['bucket'],
1271 'sourceObject' => $this->identity['object'],
1272 'sourceGeneration' => $this->identity['generation'],
1273 'userProject' => $this->identity['userProject'],
1274 ]) + $this->formatEncryptionHeaders($options + $this->encryptionData);
1275 }
1276 }
1277