Пример #1
0
 protected function createTransferAction(\SplFileInfo $file)
 {
     // Open the file for reading
     $filename = $file->getRealPath() ?: $file->getPathName();
     if (!($resource = fopen($filename, 'r'))) {
         // @codeCoverageIgnoreStart
         throw new RuntimeException('Could not open ' . $file->getPathname() . ' for reading');
         // @codeCoverageIgnoreEnd
     }
     $key = $this->options['source_converter']->convert($filename);
     $body = EntityBody::factory($resource);
     // Determine how the ACL should be applied
     if ($acl = $this->options['acl']) {
         $aclType = is_string($this->options['acl']) ? 'ACL' : 'ACP';
     } else {
         $acl = 'private';
         $aclType = 'ACL';
     }
     // Use a multi-part upload if the file is larger than the cutoff size and is a regular file
     if ($body->getWrapper() == 'plainfile' && $file->getSize() >= $this->options['multipart_upload_size']) {
         $builder = UploadBuilder::newInstance()->setBucket($this->options['bucket'])->setKey($key)->setMinPartSize($this->options['multipart_upload_size'])->setOption($aclType, $acl)->setClient($this->options['client'])->setSource($body)->setConcurrency($this->options['concurrency']);
         $this->dispatch(self::BEFORE_MULTIPART_BUILD, array('builder' => $builder, 'file' => $file));
         return $builder->build();
     }
     return $this->options['client']->getCommand('PutObject', array('Bucket' => $this->options['bucket'], 'Key' => $key, 'Body' => $body, $aclType => $acl));
 }
Пример #2
0
 /**
  * {@inheritdoc}
  */
 protected function transfer()
 {
     while (!$this->stopped && !$this->source->isConsumed()) {
         if ($this->source->getContentLength() && $this->source->isSeekable()) {
             // If the stream is seekable and the Content-Length known, then stream from the data source
             $body = new ReadLimitEntityBody($this->source, $this->partSize, $this->source->ftell());
         } else {
             // We need to read the data source into a temporary buffer before streaming
             $body = EntityBody::factory();
             while ($body->getContentLength() < $this->partSize && $body->write($this->source->read(max(1, min(10 * Size::KB, $this->partSize - $body->getContentLength()))))) {
             }
         }
         // @codeCoverageIgnoreStart
         if ($body->getContentLength() == 0) {
             break;
         }
         // @codeCoverageIgnoreEnd
         $params = $this->state->getUploadId()->toParams();
         $command = $this->client->getCommand('UploadPart', array_replace($params, array('PartNumber' => count($this->state) + 1, 'Body' => $body, 'ContentMD5' => (bool) $this->options['part_md5'], Ua::OPTION => Ua::MULTIPART_UPLOAD)));
         // Notify observers that the part is about to be uploaded
         $eventData = $this->getEventData();
         $eventData['command'] = $command;
         $this->dispatch(self::BEFORE_PART_UPLOAD, $eventData);
         // Allow listeners to stop the transfer if needed
         if ($this->stopped) {
             break;
         }
         $response = $command->getResponse();
         $this->state->addPart(UploadPart::fromArray(array('PartNumber' => count($this->state) + 1, 'ETag' => $response->getEtag(), 'Size' => $body->getContentLength(), 'LastModified' => gmdate(DateFormat::RFC2822))));
         // Notify observers that the part was uploaded
         $this->dispatch(self::AFTER_PART_UPLOAD, $eventData);
     }
 }
Пример #3
0
 /**
  * Receive a response header from curl
  *
  * @param resource $curl   Curl handle
  * @param string   $header Received header
  *
  * @return int
  */
 public function receiveResponseHeader($curl, $header)
 {
     static $normalize = array("\r", "\n");
     $length = strlen($header);
     $header = str_replace($normalize, '', $header);
     if (strpos($header, 'HTTP/') === 0) {
         $startLine = explode(' ', $header, 3);
         $code = $startLine[1];
         $status = isset($startLine[2]) ? $startLine[2] : '';
         // Only download the body of the response to the specified response
         // body when a successful response is received.
         if ($code >= 200 && $code < 300) {
             $body = $this->request->getResponseBody();
         } else {
             $body = EntityBody::factory();
         }
         $response = new Response($code, null, $body);
         $response->setStatus($code, $status);
         $this->request->startResponse($response);
         $this->request->dispatch('request.receive.status_line', array('request' => $this, 'line' => $header, 'status_code' => $code, 'reason_phrase' => $status));
     } elseif ($pos = strpos($header, ':')) {
         $this->request->getResponse()->addHeader(trim(substr($header, 0, $pos)), trim(substr($header, $pos + 1)));
     }
     return $length;
 }
Пример #4
0
 public function setBody($body, $contentType = null)
 {
     $this->body = EntityBody::factory($body);
     // Auto detect the Content-Type from the path of the request if possible
     if ($contentType === null && !$this->hasHeader('Content-Type')) {
         $contentType = $this->body->getContentType();
     }
     if ($contentType) {
         $this->setHeader('Content-Type', $contentType);
     }
     // Always add the Expect 100-Continue header if the body cannot be rewound. This helps with redirects.
     if (!$this->body->isSeekable() && $this->expectCutoff !== false) {
         $this->setHeader('Expect', '100-Continue');
     }
     // Set the Content-Length header if it can be determined
     $size = $this->body->getContentLength();
     if ($size !== null && $size !== false) {
         $this->setHeader('Content-Length', $size);
         if ($size > $this->expectCutoff) {
             $this->setHeader('Expect', '100-Continue');
         }
     } elseif (!$this->hasHeader('Content-Length')) {
         if ('1.1' == $this->protocolVersion) {
             $this->setHeader('Transfer-Encoding', 'chunked');
         } else {
             throw new RequestException('Cannot determine Content-Length and cannot use chunked Transfer-Encoding when using HTTP/1.0');
         }
     }
     return $this;
 }
Пример #5
0
 public function visit(CommandInterface $command, RequestInterface $request, Parameter $param, $value)
 {
     $value = $param->filter($value);
     $entityBody = EntityBody::factory($value);
     $request->setBody($entityBody);
     $this->addExpectHeader($request, $entityBody, $param->getData('expect_header'));
     // Add the Content-Encoding header if one is set on the EntityBody
     if ($encoding = $entityBody->getContentEncoding()) {
         $request->setHeader('Content-Encoding', $encoding);
     }
 }
Пример #6
0
 /**
  * Create a tree hash from a content body
  *
  * @param string|resource|EntityBody $content   Content to create a tree hash for
  * @param string                     $algorithm A valid hash algorithm name as returned by `hash_algos()`
  *
  * @return TreeHash
  */
 public static function fromContent($content, $algorithm = self::DEFAULT_ALGORITHM)
 {
     $treeHash = new self($algorithm);
     // Read the data in 1MB chunks and add to tree hash
     $content = EntityBody::factory($content);
     while ($data = $content->read(Size::MB)) {
         $treeHash->addData($data);
     }
     // Pre-calculate hash
     $treeHash->getHash();
     return $treeHash;
 }
Пример #7
0
 /**
  * @param S3Client                            $client Client to use when executing requests
  * @param string                              $bucket Bucket that holds the object
  * @param string                              $key    Key of the object
  * @param string|resource|EntityBodyInterface $target Where the object should be downloaded to. Pass a string to
  *                                                    save the object to a file, pass a resource returned by
  *                                                    fopen() to save the object to a stream resource, or pass a
  *                                                    Guzzle EntityBody object to save the contents to an
  *                                                    EntityBody.
  * @param array                               $params Any additional GetObject or HeadObject parameters to use
  *                                                    with each command issued by the client. (e.g. pass "Version"
  *                                                    to download a specific version of an object)
  * @throws RuntimeException if the target variable points to a file that cannot be opened
  */
 public function __construct(S3Client $client, $bucket, $key, $target, array $params = array())
 {
     $this->params = $params;
     $this->client = $client;
     $this->params['Bucket'] = $bucket;
     $this->params['Key'] = $key;
     // If a string is passed, then assume that the download should stream to a file on disk
     if (is_string($target)) {
         if (!($target = fopen($target, 'a+'))) {
             throw new RuntimeException("Unable to open {$target} for writing");
         }
         // Always append to the file
         fseek($target, 0, SEEK_END);
     }
     // Get the metadata and Content-MD5 of the object
     $this->target = EntityBody::factory($target);
 }
 /**
  * Converts filenames and file handles into EntityBody objects before the command is validated
  *
  * @param Event $event Event emitted
  * @throws InvalidArgumentException
  */
 public function onCommandBeforePrepare(Event $event)
 {
     /** @var $command Command */
     $command = $event['command'];
     if (in_array($command->getName(), $this->commands)) {
         // Get the interesting parameters
         $source = $command->get($this->sourceParameter);
         $body = $command->get($this->bodyParameter);
         // If a file path is passed in then get the file handle
         if (is_string($source) && file_exists($source)) {
             $body = fopen($source, 'r');
         }
         // Prepare the body parameter and remove the source file parameter
         if (null !== $body) {
             $command->remove($this->sourceParameter);
             $command->set($this->bodyParameter, EntityBody::factory($body));
         } else {
             throw new InvalidArgumentException("You must specify a non-null value for the {$this->bodyParameter} or {$this->sourceParameter} parameters.");
         }
     }
 }
Пример #9
0
 public function getResponseBody()
 {
     if ($this->responseBody === null) {
         $this->responseBody = EntityBody::factory()->setCustomData('default', true);
     }
     return $this->responseBody;
 }
Пример #10
0
 /**
  * Set the data source of the transfer
  *
  * @param resource|string|EntityBody $source Source of the transfer. Pass a string to transfer from a file on disk.
  *                                           You can also stream from a resource returned from fopen or a Guzzle
  *                                           {@see EntityBody} object.
  *
  * @return self
  * @throws InvalidArgumentException when the source cannot be found or opened
  */
 public function setSource($source)
 {
     // Use the contents of a file as the data source
     if (is_string($source)) {
         if (!file_exists($source)) {
             throw new InvalidArgumentException("File does not exist: {$source}");
         }
         // Clear the cache so that we send accurate file sizes
         clearstatcache(true, $source);
         $source = fopen($source, 'r');
     }
     $this->source = EntityBody::factory($source);
     if ($this->source->isSeekable() && $this->source->getSize() == 0) {
         throw new InvalidArgumentException('Empty body provided to upload builder');
     }
     return $this;
 }
Пример #11
0
 /**
  * Called before a request is sent
  *
  * @param Event $event
  */
 public function onRequestBeforeSend(Event $event)
 {
     if ($this->wireBodies) {
         $request = $event['request'];
         // Ensure that curl IO events are emitted
         $request->getCurlOptions()->set('emit_io', true);
         // We need to make special handling for content wiring and non-repeatable streams.
         if ($request instanceof EntityEnclosingRequestInterface && $request->getBody() && (!$request->getBody()->isSeekable() || !$request->getBody()->isReadable())) {
             // The body of the request cannot be recalled so logging the body will require us to buffer it
             $request->getParams()->set('request_wire', EntityBody::factory());
         }
         if (!$request->getResponseBody()->isRepeatable()) {
             // The body of the response cannot be recalled so logging the body will require us to buffer it
             $request->getParams()->set('response_wire', EntityBody::factory());
         }
     }
 }
Пример #12
0
 /**
  * Upload a file, stream, or string to a bucket. If the upload size exceeds the specified threshold, the upload
  * will be performed using parallel multipart uploads.
  *
  * @param string $bucket  Bucket to upload the object
  * @param string $key     Key of the object
  * @param mixed  $body    Object data to upload. Can be a Guzzle\Http\EntityBodyInterface, stream resource, or
  *                        string of data to upload.
  * @param string $acl     ACL to apply to the object
  * @param array  $options Custom options used when executing commands:
  *     - params: Custom parameters to use with the upload. The parameters must map to a PutObject
  *       or InitiateMultipartUpload operation parameters.
  *     - min_part_size: Minimum size to allow for each uploaded part when performing a multipart upload.
  *     - concurrency: Maximum number of concurrent multipart uploads.
  *     - before_upload: Callback to invoke before each multipart upload. The callback will receive a
  *       Guzzle\Common\Event object with context.
  *
  * @see Aws\S3\Model\MultipartUpload\UploadBuilder for more options and customization
  * @return \Guzzle\Service\Resource\Model Returns the modeled result of the performed operation
  */
 public function upload($bucket, $key, $body, $acl = 'private', array $options = array())
 {
     $body = EntityBody::factory($body);
     $options = Collection::fromConfig(array_change_key_case($options), array('min_part_size' => AbstractMulti::MIN_PART_SIZE, 'params' => array(), 'concurrency' => $body->getWrapper() == 'plainfile' ? 3 : 1));
     if ($body->getSize() < $options['min_part_size']) {
         // Perform a simple PutObject operation
         return $this->putObject(array('Bucket' => $bucket, 'Key' => $key, 'Body' => $body, 'ACL' => $acl) + $options['params']);
     }
     // Perform a multipart upload if the file is large enough
     $transfer = UploadBuilder::newInstance()->setBucket($bucket)->setKey($key)->setMinPartSize($options['min_part_size'])->setConcurrency($options['concurrency'])->setClient($this)->setSource($body)->setTransferOptions($options->toArray())->addOptions($options['params'])->setOption('ACL', $acl)->build();
     if ($options['before_upload']) {
         $transfer->getEventDispatcher()->addListener(AbstractTransfer::BEFORE_PART_UPLOAD, $options['before_upload']);
     }
     return $transfer->upload();
 }
Пример #13
0
 /**
  * Set the response entity body
  *
  * @param EntityBodyInterface|string $body Body to set
  *
  * @return self
  */
 public function setBody($body)
 {
     $this->body = EntityBody::factory($body);
     return $this;
 }