Client.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <?php
  2. namespace Qcloud\Cos;
  3. include("Common.php");
  4. use Qcloud\Cos\Signature;
  5. use GuzzleHttp\Client as HttpClient;
  6. use GuzzleHttp\HandlerStack;
  7. use Psr\Http\Message\RequestInterface;
  8. use Psr\Http\Message\ResponseInterface;
  9. use GuzzleHttp\Command\Guzzle\Description;
  10. use GuzzleHttp\Command\Guzzle\GuzzleClient;
  11. use GuzzleHttp\Command\Guzzle\Deserializer;
  12. use GuzzleHttp\Command\CommandInterface;
  13. use GuzzleHttp\Command\Exception\CommandException;
  14. use GuzzleHttp\Exception\RequestException;
  15. use GuzzleHttp\Middleware;
  16. use GuzzleHttp\Psr7;
  17. use GuzzleHttp\Pool;
  18. class Client extends GuzzleClient {
  19. const VERSION = '2.0.9';
  20. public $httpClient;
  21. private $api;
  22. private $desc;
  23. private $action;
  24. private $operation;
  25. private $cosConfig;
  26. private $signature;
  27. private $rawCosConfig;
  28. public function __construct($cosConfig) {
  29. $this->rawCosConfig = $cosConfig;
  30. $this->cosConfig['schema'] = isset($cosConfig['schema']) ? $cosConfig['schema'] : 'http';
  31. $this->cosConfig['region'] = region_map($cosConfig['region']);
  32. $this->cosConfig['appId'] = isset($cosConfig['credentials']['appId']) ? $cosConfig['credentials']['appId'] : null;
  33. $this->cosConfig['secretId'] = isset($cosConfig['credentials']['secretId']) ? $cosConfig['credentials']['secretId'] : "";
  34. $this->cosConfig['secretKey'] = isset($cosConfig['credentials']['secretKey']) ? $cosConfig['credentials']['secretKey'] : "";
  35. $this->cosConfig['anonymous'] = isset($cosConfig['credentials']['anonymous']) ? $cosConfig['anonymous']['anonymous'] : false;
  36. $this->cosConfig['token'] = isset($cosConfig['credentials']['token']) ? $cosConfig['credentials']['token'] : null;
  37. $this->cosConfig['timeout'] = isset($cosConfig['timeout']) ? $cosConfig['timeout'] : 3600;
  38. $this->cosConfig['connect_timeout'] = isset($cosConfig['connect_timeout']) ? $cosConfig['connect_timeout'] : 3600;
  39. $this->cosConfig['ip'] = isset($cosConfig['ip']) ? $cosConfig['ip'] : null;
  40. $this->cosConfig['port'] = isset($cosConfig['port']) ? $cosConfig['port'] : null;
  41. $this->cosConfig['endpoint'] = isset($cosConfig['endpoint']) ? $cosConfig['endpoint'] : 'myqcloud.com';
  42. $this->cosConfig['domain'] = isset($cosConfig['domain']) ? $cosConfig['domain'] : null;
  43. $this->cosConfig['proxy'] = isset($cosConfig['proxy']) ? $cosConfig['proxy'] : null;
  44. $this->cosConfig['retry'] = isset($cosConfig['retry']) ? $cosConfig['retry'] : 1;
  45. $this->cosConfig['userAgent'] = isset($cosConfig['userAgent']) ? $cosConfig['userAgent'] : 'cos-php-sdk-v5.'. Client::VERSION;
  46. $this->cosConfig['pathStyle'] = isset($cosConfig['pathStyle']) ? $cosConfig['pathStyle'] : false;
  47. $service = Service::getService();
  48. $handler = HandlerStack::create();
  49. $handler->push(Middleware::mapRequest(function (RequestInterface $request) {
  50. return $request->withHeader('User-Agent', $this->cosConfig['userAgent']);
  51. }));
  52. if ($this->cosConfig['anonymous'] != true) {
  53. $handler->push($this::handleSignature($this->cosConfig['secretId'], $this->cosConfig['secretKey']));
  54. }
  55. if ($this->cosConfig['token'] != null) {
  56. $handler->push(Middleware::mapRequest(function (RequestInterface $request) {
  57. return $request->withHeader('x-cos-security-token', $this->cosConfig['token']);
  58. }));
  59. }
  60. $handler->push($this::handleErrors());
  61. $this->signature = new Signature($this->cosConfig['secretId'], $this->cosConfig['secretKey'], $this->cosConfig['token']);
  62. $this->httpClient = new HttpClient([
  63. 'base_uri' => $this->cosConfig['schema'].'://cos.' . $this->cosConfig['region'] . '.myqcloud.com/',
  64. 'timeout' => $this->cosConfig['timeout'],
  65. 'handler' => $handler,
  66. 'proxy' => $this->cosConfig['proxy'],
  67. ]);
  68. $this->desc = new Description($service);
  69. $this->api = (array)($this->desc->getOperations());
  70. parent::__construct($this->httpClient, $this->desc, [$this,
  71. 'commandToRequestTransformer'], [$this, 'responseToResultTransformer'],
  72. null);
  73. }
  74. public function commandToRequestTransformer(CommandInterface $command)
  75. {
  76. $this->action = $command->GetName();
  77. $this->operation = $this->api[$this->action];
  78. $transformer = new CommandToRequestTransformer($this->cosConfig, $this->operation);
  79. $seri = new Serializer($this->desc);
  80. $request = $seri($command);
  81. $request = $transformer->bucketStyleTransformer($command, $request);
  82. $request = $transformer->uploadBodyTransformer($command, $request);
  83. $request = $transformer->metadataTransformer($command, $request);
  84. $request = $transformer->md5Transformer($command, $request);
  85. $request = $transformer->specialParamTransformer($command, $request);
  86. return $request;
  87. }
  88. public function responseToResultTransformer(ResponseInterface $response, RequestInterface $request, CommandInterface $command)
  89. {
  90. $transformer = new ResultTransformer($this->cosConfig, $this->operation);
  91. $transformer->writeDataToLocal($command, $request, $response);
  92. $deseri = new Deserializer($this->desc, true);
  93. $result = $deseri($response, $request, $command);
  94. $result = $transformer->metaDataTransformer($command, $response, $result);
  95. $result = $transformer->extraHeadersTransformer($command, $request, $result);
  96. $result = $transformer->selectContentTransformer($command, $result);
  97. return $result;
  98. }
  99. public function __destruct() {
  100. }
  101. public function __call($method, array $args) {
  102. for ($i = 1; $i <= $this->cosConfig['retry']; $i++) {
  103. try {
  104. return parent::__call(ucfirst($method), $args);
  105. } catch (CommandException $e) {
  106. if ($i != $this->cosConfig['retry']) {
  107. sleep(1 << ($i-1));
  108. continue;
  109. }
  110. $previous = $e->getPrevious();
  111. if ($previous !== null) {
  112. throw $previous;
  113. } else {
  114. throw $e;
  115. }
  116. }
  117. }
  118. }
  119. public function getApi() {
  120. return $this->api;
  121. }
  122. private function getCosConfig() {
  123. return $this->cosConfig;
  124. }
  125. private function createPresignedUrl(RequestInterface $request, $expires) {
  126. return $this->signature->createPresignedUrl($request, $expires);
  127. }
  128. public function getPresignetUrl($method, $args, $expires = "+30 minutes") {
  129. $command = $this->getCommand($method, $args);
  130. $request = $this->commandToRequestTransformer($command);
  131. return $this->createPresignedUrl($request, $expires);
  132. }
  133. public function getObjectUrl($bucket, $key, $expires = "+30 minutes", array $args = array()) {
  134. $command = $this->getCommand('GetObject', $args + array('Bucket' => $bucket, 'Key' => $key));
  135. $request = $this->commandToRequestTransformer($command);
  136. return $this->createPresignedUrl($request, $expires)->__toString();
  137. }
  138. public function upload($bucket, $key, $body, $options = array()) {
  139. $body = Psr7\stream_for($body);
  140. $options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : MultipartUpload::DEFAULT_PART_SIZE;
  141. if ($body->getSize() < $options['PartSize']) {
  142. $rt = $this->putObject(array(
  143. 'Bucket' => $bucket,
  144. 'Key' => $key,
  145. 'Body' => $body,
  146. ) + $options);
  147. }
  148. else {
  149. $multipartUpload = new MultipartUpload($this, $body, array(
  150. 'Bucket' => $bucket,
  151. 'Key' => $key,
  152. ) + $options);
  153. $rt = $multipartUpload->performUploading();
  154. }
  155. return $rt;
  156. }
  157. public function resumeUpload($bucket, $key, $body, $uploadId, $options = array()) {
  158. $body = Psr7\stream_for($body);
  159. $options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : MultipartUpload::DEFAULT_PART_SIZE;
  160. $multipartUpload = new MultipartUpload($this, $body, array(
  161. 'Bucket' => $bucket,
  162. 'Key' => $key,
  163. 'UploadId' => $uploadId,
  164. ) + $options);
  165. $rt = $multipartUpload->resumeUploading();
  166. return $rt;
  167. }
  168. public function copy($bucket, $key, $copySource, $options = array()) {
  169. $options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : Copy::DEFAULT_PART_SIZE;
  170. // set copysource client
  171. $sourceConfig = $this->rawCosConfig;
  172. $sourceConfig['region'] = $copySource['Region'];
  173. $cosSourceClient = new Client($sourceConfig);
  174. $copySource['VersionId'] = isset($copySource['VersionId']) ? $copySource['VersionId'] : "";
  175. try {
  176. $rt = $cosSourceClient->headObject(
  177. array('Bucket'=>$copySource['Bucket'],
  178. 'Key'=>$copySource['Key'],
  179. 'VersionId'=>$copySource['VersionId'],
  180. )
  181. );
  182. } catch (\Exception $e) {
  183. throw $e;
  184. }
  185. $contentLength =$rt['ContentLength'];
  186. // sample copy
  187. if ($contentLength < $options['PartSize']) {
  188. $rt = $this->copyObject(array(
  189. 'Bucket' => $bucket,
  190. 'Key' => $key,
  191. 'CopySource' => $copySource['Bucket']. '.cos.'. $copySource['Region'].
  192. ".myqcloud.com/". $copySource['Key']. "?versionId=". $copySource['VersionId'],
  193. ) + $options
  194. );
  195. return $rt;
  196. }
  197. // multi part copy
  198. $copySource['ContentLength'] = $contentLength;
  199. $copy = new Copy($this, $copySource, array(
  200. 'Bucket' => $bucket,
  201. 'Key' => $key
  202. ) + $options
  203. );
  204. return $copy->copy();
  205. }
  206. public function doesBucketExist($bucket, array $options = array())
  207. {
  208. try {
  209. $this->HeadBucket(array(
  210. 'Bucket' => $bucket));
  211. return True;
  212. } catch (\Exception $e){
  213. return False;
  214. }
  215. }
  216. public function doesObjectExist($bucket, $key, array $options = array())
  217. {
  218. try {
  219. $this->HeadObject(array(
  220. 'Bucket' => $bucket,
  221. 'Key' => $key));
  222. return True;
  223. } catch (\Exception $e){
  224. return False;
  225. }
  226. }
  227. public static function explodeKey($key) {
  228. // Remove a leading slash if one is found
  229. $split_key = explode('/', $key && $key[0] == '/' ? substr($key, 1) : $key);
  230. // Remove empty element
  231. $split_key = array_filter($split_key, function($var) {
  232. return !($var == '' || $var == null);
  233. });
  234. $final_key = implode("/", $split_key);
  235. if (substr($key, -1) == '/') {
  236. $final_key = $final_key . '/';
  237. }
  238. return $final_key;
  239. }
  240. public static function handleSignature($secretId, $secretKey) {
  241. return function (callable $handler) use ($secretId, $secretKey) {
  242. return new SignatureMiddleware($handler, $secretId, $secretKey);
  243. };
  244. }
  245. public static function handleErrors() {
  246. return function (callable $handler) {
  247. return new ExceptionMiddleware($handler);
  248. };
  249. }
  250. }