PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/aws/aws-sdk-php/src/Aws/S3/ResumableDownload.php

https://github.com/lslucas/105fm
PHP | 176 lines | 78 code | 22 blank | 76 comment | 8 complexity | d54fce84af9a35d046e3346355499327 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright 2010-2013 Amazon.com, Inc. or its affiliates. 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. * A copy of the License is located at
  8. *
  9. * http://aws.amazon.com/apache2.0
  10. *
  11. * or in the "license" file accompanying this file. This file is distributed
  12. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  13. * express or implied. See the License for the specific language governing
  14. * permissions and limitations under the License.
  15. */
  16. namespace Aws\S3;
  17. use Aws\Common\Exception\RuntimeException;
  18. use Aws\Common\Exception\UnexpectedValueException;
  19. use Guzzle\Http\EntityBody;
  20. use Guzzle\Http\ReadLimitEntityBody;
  21. use Guzzle\Http\EntityBodyInterface;
  22. use Guzzle\Service\Resource\Model;
  23. /**
  24. * Allows you to resume the download of a partially downloaded object.
  25. *
  26. * Downloads objects from Amazon S3 in using "Range" downloads. This allows a partially downloaded object to be resumed
  27. * so that only the remaining portion of the object is downloaded.
  28. */
  29. class ResumableDownload
  30. {
  31. /** @var S3Client The S3 client to use to download objects and issue HEAD requests */
  32. protected $client;
  33. /** @var \Guzzle\Service\Resource\Model Model object returned when the initial HeadObject operation was called */
  34. protected $meta;
  35. /** @var array Array of parameters to pass to a GetObject operation */
  36. protected $params;
  37. /** @var \Guzzle\Http\EntityBody Where the object will be downloaded */
  38. protected $target;
  39. /**
  40. * @param S3Client $client Client to use when executing requests
  41. * @param string $bucket Bucket that holds the object
  42. * @param string $key Key of the object
  43. * @param string|resource|EntityBodyInterface $target Where the object should be downloaded to. Pass a string to
  44. * save the object to a file, pass a resource returned by
  45. * fopen() to save the object to a stream resource, or pass a
  46. * Guzzle EntityBody object to save the contents to an
  47. * EntityBody.
  48. * @param array $params Any additional GetObject or HeadObject parameters to use
  49. * with each command issued by the client. (e.g. pass "Version"
  50. * to download a specific version of an object)
  51. * @throws RuntimeException if the target variable points to a file that cannot be opened
  52. */
  53. public function __construct(S3Client $client, $bucket, $key, $target, array $params = array())
  54. {
  55. $this->params = $params;
  56. $this->client = $client;
  57. $this->params['Bucket'] = $bucket;
  58. $this->params['Key'] = $key;
  59. // If a string is passed, then assume that the download should stream to a file on disk
  60. if (is_string($target)) {
  61. if (!($target = fopen($target, 'a+'))) {
  62. throw new RuntimeException("Unable to open {$target} for writing");
  63. }
  64. // Always append to the file
  65. fseek($target, 0, SEEK_END);
  66. }
  67. // Get the metadata and Content-MD5 of the object
  68. $this->target = EntityBody::factory($target);
  69. }
  70. /**
  71. * Get the bucket of the download
  72. *
  73. * @return string
  74. */
  75. public function getBucket()
  76. {
  77. return $this->params['Bucket'];
  78. }
  79. /**
  80. * Get the key of the download
  81. *
  82. * @return string
  83. */
  84. public function getKey()
  85. {
  86. return $this->params['Key'];
  87. }
  88. /**
  89. * Get the file to which the contents are downloaded
  90. *
  91. * @return string
  92. */
  93. public function getFilename()
  94. {
  95. return $this->target->getUri();
  96. }
  97. /**
  98. * Download the remainder of the object from Amazon S3
  99. *
  100. * Performs a message integrity check if possible
  101. *
  102. * @return Model
  103. */
  104. public function __invoke()
  105. {
  106. $command = $this->client->getCommand('HeadObject', $this->params);
  107. $this->meta = $command->execute();
  108. if ($this->target->ftell() >= $this->meta['ContentLength']) {
  109. return false;
  110. }
  111. $this->meta['ContentMD5'] = (string) $command->getResponse()->getHeader('Content-MD5');
  112. // Use a ReadLimitEntityBody so that rewinding the stream after an error does not cause the file pointer
  113. // to enter an inconsistent state with the data being downloaded
  114. $this->params['SaveAs'] = new ReadLimitEntityBody(
  115. $this->target,
  116. $this->meta['ContentLength'],
  117. $this->target->ftell()
  118. );
  119. $result = $this->getRemaining();
  120. $this->checkIntegrity();
  121. return $result;
  122. }
  123. /**
  124. * Send the command to get the remainder of the object
  125. *
  126. * @return Model
  127. */
  128. protected function getRemaining()
  129. {
  130. $current = $this->target->ftell();
  131. $targetByte = $this->meta['ContentLength'] - 1;
  132. $this->params['Range'] = "bytes={$current}-{$targetByte}";
  133. // Set the starting offset so that the body is never seeked to before this point in the event of a retry
  134. $this->params['SaveAs']->setOffset($current);
  135. $command = $this->client->getCommand('GetObject', $this->params);
  136. return $command->execute();
  137. }
  138. /**
  139. * Performs an MD5 message integrity check if possible
  140. *
  141. * @throws UnexpectedValueException if the message does not validate
  142. */
  143. protected function checkIntegrity()
  144. {
  145. if ($this->target->isReadable() && $expected = $this->meta['ContentMD5']) {
  146. $actual = $this->target->getContentMd5();
  147. if ($actual != $expected) {
  148. throw new UnexpectedValueException(
  149. "Message integrity check failed. Expected {$expected} but got {$actual}."
  150. );
  151. }
  152. }
  153. }
  154. }