/** * Send request to BCE. * * @param array $config * @param string $httpMethod The Http request method, uppercase. * @param string $path The resource path. * @param string|resource $body The Http request body. * @param array $headers The extra Http request headers. * @param array $params The extra Http url query strings. * @param SignerInterface $signer This function will generate authorization header. * @param resource|string $outputStream Write the Http response to this stream. * * @return \Guzzle\Http\Message\Response body and http_headers * * @throws BceClientException * @throws BceServiceException */ public function sendRequest(array $config, $httpMethod, $path, $body, array $headers, array $params, SignerInterface $signer, $outputStream = null, $options = array()) { $headers[HttpHeaders::USER_AGENT] = sprintf('bce-sdk-php/%s/%s/%s', Bce::SDK_VERSION, php_uname(), phpversion()); if (!isset($headers[HttpHeaders::BCE_DATE])) { $now = new \DateTime(); $now->setTimezone(DateUtils::$UTC_TIMEZONE); $headers[HttpHeaders::BCE_DATE] = DateUtils::formatAlternateIso8601Date($now); } list($hostUrl, $hostHeader) = HttpUtils::parseEndpointFromConfig($config); $headers[HttpHeaders::HOST] = $hostHeader; $url = $hostUrl . HttpUtils::urlEncodeExceptSlash($path); $queryString = HttpUtils::getCanonicalQueryString($params, false); if ($queryString !== '') { $url .= "?{$queryString}"; } if (!isset($headers[HttpHeaders::CONTENT_LENGTH])) { $headers[HttpHeaders::CONTENT_LENGTH] = $this->guessContentLength($body); } $entityBody = null; if ($headers[HttpHeaders::CONTENT_LENGTH] == 0) { //if passing a stream and content length is 0, guzzle will remove //"Content-Length:0" from header, to work around this, we have to //set body to a empty string $entityBody = ""; } else { if (is_resource($body)) { $offset = ftell($body); $original = EntityBody::factory($body); $entityBody = new ReadLimitEntityBody($original, $headers[HttpHeaders::CONTENT_LENGTH], $offset); } else { $entityBody = $body; } } $headers[HttpHeaders::AUTHORIZATION] = $signer->sign($config[BceClientConfigOptions::CREDENTIALS], $httpMethod, $path, $headers, $params, $options); if (LogFactory::isDebugEnabled()) { $this->logger->debug('HTTP method: ' . $httpMethod); $this->logger->debug('HTTP url: ' . $url); $this->logger->debug('HTTP headers: ' . print_r($headers, true)); } $guzzleRequestOptions = array('exceptions' => false); if (isset($config[BceClientConfigOptions::CONNECTION_TIMEOUT_IN_MILLIS])) { $guzzleRequestOptions['connect_timeout'] = $config[BceClientConfigOptions::CONNECTION_TIMEOUT_IN_MILLIS] / 1000.0; } if (isset($config[BceClientConfigOptions::SOCKET_TIMEOUT_IN_MILLIS])) { $guzzleRequestOptions['timeout'] = $config[BceClientConfigOptions::SOCKET_TIMEOUT_IN_MILLIS] / 1000.0; } $guzzleRequest = $this->guzzleClient->createRequest($httpMethod, $url, $headers, $entityBody, $guzzleRequestOptions); if ($outputStream !== null) { $guzzleRequest->setResponseBody($outputStream); } // Send request try { $guzzleResponse = $this->guzzleClient->send($guzzleRequest); } catch (\Exception $e) { throw new BceClientException($e->getMessage()); } if ($guzzleResponse->isInformational()) { throw new BceClientException('Can not handle 1xx Http status code'); } elseif (!$guzzleResponse->isSuccessful()) { $requestId = $guzzleResponse->getHeader(HttpHeaders::BCE_REQUEST_ID); $message = $guzzleResponse->getReasonPhrase(); $code = null; if ($guzzleResponse->isContentType('json')) { try { $responseBody = $guzzleResponse->json(); if (isset($responseBody['message'])) { $message = $responseBody['message']; } if (isset($responseBody['code'])) { $code = $responseBody['code']; } } catch (\Exception $e) { // ignore this error $this->logger->warning('Fail to parse error response body: ' . $e->getMessage()); } } throw new BceServiceException($requestId, $code, $message, $guzzleResponse->getStatusCode()); } if ($outputStream === null) { $body = $guzzleResponse->getBody(true); } else { $body = null; // detach the stream so that it will not be closed when the response // is garbage collected. $guzzleResponse->getBody()->detachStream(); } return array('headers' => $this->parseHeaders($guzzleResponse), 'body' => $body); }
/** * Copy one object to another. * * @param string $sourceBucketName The source bucket name. * @param string $sourceKey The source object path. * @param string $targetBucketName The target bucket name. * @param string $targetKey The target object path. * @param mixed $options The optional bce configuration, which will overwrite the * default configuration that was passed while creating BosClient instance. * * @return mixed */ public function copyObject($sourceBucketName, $sourceKey, $targetBucketName, $targetKey, $options = array()) { if (empty($sourceBucketName)) { throw new \InvalidArgumentException('$sourceBucketName should not be empty or null.'); } if (empty($sourceKey)) { throw new \InvalidArgumentException('$sourceKey should not be empty or null.'); } if (empty($targetBucketName)) { throw new \InvalidArgumentException('$targetBucketName should not be empty or null.'); } if (empty($targetKey)) { throw new \InvalidArgumentException('$targetKey should not be empty or null.'); } list($config, $userMetadata, $etag) = $this->parseOptions($options, BosOptions::CONFIG, BosOptions::USER_METADATA, BosOptions::ETAG); $headers = array(); $headers[HttpHeaders::BCE_COPY_SOURCE] = HttpUtils::urlEncodeExceptSlash(sprintf("/%s/%s", $sourceBucketName, $sourceKey)); if ($etag !== null) { $etag = trim($etag, '"'); $headers[HttpHeaders::BCE_COPY_SOURCE_IF_MATCH] = '"' . $etag . '"'; } if ($userMetadata === null) { $headers[HttpHeaders::BCE_COPY_METADATA_DIRECTIVE] = 'copy'; } else { $headers[HttpHeaders::BCE_COPY_METADATA_DIRECTIVE] = 'replace'; $this->populateRequestHeadersWithUserMetadata($headers, $userMetadata); } return $this->sendRequest(HttpMethod::PUT, array(BosOptions::CONFIG => $config, 'bucket_name' => $targetBucketName, 'key' => $targetKey, 'headers' => $headers)); }
/** * @param $path string * @return string */ private static function getCanonicalURIPath($path) { if (empty($path)) { return '/'; } else { if ($path[0] == '/') { return HttpUtils::urlEncodeExceptSlash($path); } else { return '/' . HttpUtils::urlEncodeExceptSlash($path); } } }