diff --git a/extend/icloud/src/AbstractCloud.php b/extend/icloud/src/AbstractCloud.php new file mode 100644 index 0000000..8d74d34 --- /dev/null +++ b/extend/icloud/src/AbstractCloud.php @@ -0,0 +1,104 @@ +host = config('icloud.host'); + } + + + /** + * 获取 api url + * + * @time at 2019年01月26日 + * @param string $host + * @param bool $isHttps + * @throws NotFoundException + * @return string + */ + protected function host($host = 'rs', bool $isHttps = false) + { + if (!array_key_exists($host, $this->host)) { + throw NotFoundException::NotFoundKey("Host Key '{$host}' Not Found In Config File"); + } + + return self::getHost($host, $isHttps); + } + + /** + * 指定目标资源空间与目标资源名编码 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $resourceName + * @return mixed + */ + protected function encodedEntry(string $bucket, string $resourceName) + { + return self::urlSafeBase64Encode(sprintf('%s:%s', $bucket, $resourceName)); + } + + public function __call($name, ...$arguments) + { + // TODO: Implement __call() method. + $client = new Client; + $client->url = $arguments[0]; + $this->method = $name; + + if (isset($arguments[1]['headers']['Authorization'])) { + $client->params = $arguments[1]; + } else { + $headers = AuthFactory::authorization($arguments[0], $name); + $client->params = array_merge_recursive(['headers' => $headers], $arguments[1]); + } + + return $client->send(); + } + + protected function send(string $uri, string $method, array $options = []) + { + $client = new Client; + $client->uri = $uri; + $client->method = $method; + + if (isset($options['headers']['Authorization'])) { + $client->params = $options; + } else { + $headers = AuthFactory::authorization($uri, $method); + $client->params = array_merge_recursive(['headers' => $headers], $options); + } + + return $client->send(); + } + + /** + * 上传凭证 + * + * @time at 2019年01月26日 + * @param mixed ...$argument + * @return mixed + */ + public function uploadToken(...$argument) + { + return AuthFactory::uploadToken(...$argument); + } +} \ No newline at end of file diff --git a/extend/icloud/src/Utility.php b/extend/icloud/src/Utility.php new file mode 100644 index 0000000..ac5a8ce --- /dev/null +++ b/extend/icloud/src/Utility.php @@ -0,0 +1,51 @@ + sprintf('QBox %s', self::getAccessToken($uri, '', 'application/x-www-form-urlencoded'))]; + } + + /** + * 管理 Token + * + * @time at 2019年01月26日 + * @param string $urlString + * @param string $body + * @param string $contentType + * @return string + */ + public static function getAccessToken(string $urlString, string $body, string $contentType = '') + { + $appKey = config('cloud.qiniu.appKey'); + $appSecret = config('cloud.qiniu.appSecret'); + + $url = parse_url($urlString); + $data = ''; + if (array_key_exists('path', $url)) { + $data = $url['path']; + } + if (array_key_exists('query', $url)) { + $data .= '?' . $url['query']; + } + $data .= "\n"; + if ($body && $contentType === 'application/x-www-form-urlencoded') { + $data .= $body; + } + $data = hash_hmac('sha1', $data, $appSecret, true); + $encodedSign = self::urlSafeBase64Encode($data); + $accessToken = sprintf('%s:%s', $appKey, $encodedSign); + return $accessToken; + } + + /** + * 获取上传凭证 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $key + * @param int $expires + * @param string $policy + * @param bool $strictPolicy + * @return string + */ + public static function uploadToken( + string $bucket, + string $key = '', + int $expires = 3600, + string $policy = '', + bool $strictPolicy = true + ){ + $appKey = config('cloud.qiniu.appKey'); + $appSecret = config('cloud.qiniu.appSecret'); + + $scope = $key ? sprintf('%s:%s', $bucket, $key) : $bucket; + $deadline = time() + $expires; + $args = self::copyPolicy($args, $policy, $strictPolicy); + + $args['scope'] = $scope; + $args['deadline'] = $deadline; + + $encodedPutPolicy = self::urlSafeBase64Encode(json_encode($args)); + $sign = hash_hmac('sha1', $encodedPutPolicy, $appSecret, true); + $encodedSign = self::urlSafeBase64Encode($sign); + + return sprintf('%s:%s:%s', $appKey, $encodedSign, $encodedPutPolicy); + } + + private static function copyPolicy(&$policy, $originPolicy, $strictPolicy) + { + if (!$originPolicy) { + return []; + } + + $policyFields = config('cloud.qiniu.policyFields'); + + foreach ($originPolicy as $key => $value) { + if (!$strictPolicy || in_array((string)$key, $policyFields, true)) { + $policy[$key] = $value; + } + } + + return $policy; + } + + /** + * 下载凭证 + * + * @time at 2019年01月26日 + * @param string $uri + * @param int $expires + * @return string + */ + public static function dowmloadToken(string $uri, int $expires = 3600) + { + $appSecret = config('cloud.qiniu.appSecret'); + $appKey = config('cloud.qiniu.appKey'); + + $uri = sprintf('%s?e=%s', $uri, time() + $expires); + + $sign = hash_hmac('sha1', $uri, $appSecret, true); + + $encodedSign = self::urlSafeBase64Encode($sign); + + return sprintf('%s:%s', $appKey, $encodedSign); + + } +} \ No newline at end of file diff --git a/extend/icloud/src/auth/UpYunAuth.php b/extend/icloud/src/auth/UpYunAuth.php new file mode 100644 index 0000000..fb7c37a --- /dev/null +++ b/extend/icloud/src/auth/UpYunAuth.php @@ -0,0 +1,60 @@ + sprintf('UPYUN %s:%s', config('cloud.upyun.opreator'), $sign), + 'Date' => $date, + ]; + } + + + /** + * 获取 token + * + * @time at 2019年01月26日 + * @param string $method + * @param int $expire + * @param string $uriPrefix + * @param string $uriPostfix + * @return string + */ + public static function uploadToken(string $method, int $expire = 3888000, string $uriPrefix = '', string $uriPostfix= '') + { + $operator = config('cloud.upyun.opreator'); + $password = config('cloud.upyun.password'); + + $tokenArr = [$operator, $password, $method, $expire]; + + if ($uriPrefix) $tokenArr[] = $uriPrefix; + if ($uriPostfix) $tokenArr[] = $uriPostfix; + + $token = base64_encode(hash_hmac('sha1',implode('&', $tokenArr) , $password, true)); + + return sprintf('UPYUN %s:%s', $operator, $token); + } +} \ No newline at end of file diff --git a/extend/icloud/src/cloud/QiNiuCloud.php b/extend/icloud/src/cloud/QiNiuCloud.php new file mode 100644 index 0000000..fbb439a --- /dev/null +++ b/extend/icloud/src/cloud/QiNiuCloud.php @@ -0,0 +1,417 @@ +host() . '/buckets' ; + + return $this->get($uri); + } + + /** + * 创建 bucket + * + * @time at 2019年01月26日 + * @param string $bucket (bucket名称) + * @param string $region 地区)[z0华东 z1华北 z2华南 na0北美 as0新加坡 ] + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function create(string $bucket, string $region) + { + $uri = sprintf($this->host() . '/mkbucketv2/%s/region/%s', self::urlSafeBase64Encode($bucket), $region); + + return $this->post($uri); + } + + /** + * 删除空间 + * + * @time at 2019年01月26日 + * @param string $bucket + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function drop(string $bucket) + { + $uri = sprintf($this->host() . '/drop/%s', $bucket); + + return $this->post($uri); + } + + /** + * 获取空间名称 + * + * @time at 2019年01月26日 + * @param string $bucket + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function getDomainListOfBucket(string $bucket) + { + $uri = sprintf($this->host( 'api') . '/v6/domain/list?tbl=%s', $bucket); + + return $this->get($uri); + } + + /** + * 设置空间权限 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param int $private (0 公开 1 私有) + * @throws \thinking\icloud\exception\NotFoundException + * @return bool + */ + public function setPrivate(string $bucket, int $private = 0) + { + if (!in_array($private, [0, 1])) return false; + + $uri = sprintf('%s?%s', $this->host( 'uc') . '/private', http_build_query(['bucket' => $bucket, 'private' => $private])); + + return $this->post($uri); + } + + /** + * + * 资源统计 + * @space 获取标准存储的存储量统计 + * @count 获取标准存储的文件数量统计 + * @space_line 获取低频存储的存储量统计 + * @count_line 获取低频存储的文件数量统计 + * @blob_transfer 获取跨区域同步流量统计 + * @rs_chtype 获取存储类型请求次数统计 + * @blob_io 获取外网流出流量统计和 GET 请求次数统计 + * @rs_put 获取 PUT 请求次数统计 + * @time at 2019年01月26日 + * @param string $begin + * @param string $end + * @param string $type + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function statistics(string $begin, string $end, $type = 'space') + { + $urls = [ + 'space' => '/v6/space?begin=%s&end=%s&g=day', + 'count' => '/v6/count?begin=%s&end=%s&g=day', + 'space_line' => '/v6/space_line?begin=%s&end=%s&g=day', + 'count_line' => '/v6/count_line?begin=%s&end=%s&g=day', + 'blob_transfer' => '/v6/blob_transfer?begin=%s&end=%s&g=day&select=size', + 'rs_chtype' => '/v6/rs_chtype?begin=%s&end=%s&g=day&select=hits', + 'blob_io' => '/v6/blob_io?begin=%s&end=%s&g=day&select=flow&$src=origin', + 'rs_put' => '/v6/rs_put?begin=%s&end=%s&g=day&select=hits', + ]; + + $uri = sprintf($this->host('api') . $urls[$type], $begin, $end); + + return $this->get($uri); + } + + /** + * 列出空间所有资源 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $marker + * @param int $limit + * @param string $prefix + * @param string $delimiter + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function list(string $bucket, string $marker = '', int $limit = 10, string $prefix = '', string $delimiter = '') + { + $uri = sprintf($this->host('rsf') .'/list?bucket=%s&marker=%s&limit=%d&prefix=%s&delimiter=%s', $bucket, $marker, $limit, $prefix, $delimiter); + + return $this->get($uri); + } + + /** + * 获取资源原信息 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $resourceName + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function stat(string $bucket, string $resourceName) + { + //1372-the-dawn-of-hope-tomasz-chistowski.jpg + + $encodedEntryUri = $this->encodedEntry($bucket, $resourceName); + + $uri = sprintf($this->host() . '/stat/%s', $encodedEntryUri); + + return $this->get($uri); + } + + /** + * 将资源从一个空间移动到另一个空间, 该操作不支持跨账号操作, 不支持跨区域操作 + * + * @time at 2019年01月26日 + * @param string $localBucket + * @param string $destBucket + * @param string $localResourceName + * @param string $destResourceName + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function move(string $localBucket, string $destBucket, string $localResourceName, string $destResourceName = '') + { + $encodedEntryURISrc = $this->encodedEntry($localBucket, $localResourceName); + $encodedEntryURIDest = $this->encodedEntry($destBucket, $destResourceName ? : $localResourceName); + + $uri = sprintf($this->host() .'/move/%s/%s' , $encodedEntryURISrc, $encodedEntryURIDest); + + return $this->post($uri); + } + + /** + * 将资源从一个空间复制到另一个空间, 该操作不支持跨账号操作, 不支持跨区域操作 + * + * @time at 2019年01月26日 + * @param string $localBucket + * @param string $destBucket + * @param string $localResourceName + * @param string $destResourceName + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function copy(string $localBucket, string $destBucket, string $localResourceName, string $destResourceName = '') + { + $encodedEntryURISrc = $this->encodedEntry($localBucket, $localResourceName); + $encodedEntryURIDest = $this->encodedEntry($destBucket, $destResourceName ? : $localResourceName); + + $uri = sprintf($this->host() . '/copy/%s/%s', $encodedEntryURISrc, $encodedEntryURIDest); + + return $this->post($uri); + } + + /** + * 删除指定空间资源 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $resourceName + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function delete(string $bucket, string $resourceName) + { + $encodedEntryUri = $this->encodedEntry($bucket, $resourceName); + + $uri = sprintf($this->host() . '/delete/%s', $encodedEntryUri); + + return $this->post($uri); + } + + /** + * 主权远程 IMG 到指定空间 + * + * @time at 2019年01月26日 + * @param string $remoteImgUri + * @param string $destBucket + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function fetch(string $remoteImgUri, string $destBucket) + { + $imgEncodedUri = self::urlSafeBase64Encode($remoteImgUri); + $encodedEntryUri = self::urlSafeBase64Encode($destBucket); + + $uri = sprintf($this->host( 'iovip') . '/fetch/%s/to/%s', $imgEncodedUri, $encodedEntryUri); + + return $this->post($uri); + } + + /** + * 批量操作 + * + * @说明 + * 数组格式 + * [ + * stat => ['bucket', 'resourceName'] + * delete => ['bucket', 'resourceName'] + * move => ['localbucket', 'destbucket', 'resourceName', 'destResourceName'(可不写)] + * copy => ['localbucket', 'destbucket', 'resourceName', 'destResourceName'(可不写)] + * ] + * @time at 2019年01月26日 + * @param array $batchOptions + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function batch(array $batchOptions) + { + $requestParams = ''; + + foreach ($batchOptions as $option => $param) + { + if ($option === 'stat' || $option === 'delete') { + $requestParams .= sprintf('op=/%s/%s&', $option, $this->encodedEntry($param[0], $param[1])); + } else if($option === 'move' || $option === 'copy') { + $encodedEntryURISrc = $this->encodedEntry($param[0], $param[2]); + $encodedEntryURIDest = $this->encodedEntry($param[1], count($param) >= 4 ? $param[3] : $param[2]); + $requestParams .= sprintf('op=/%s/%s/%s&', $option, $encodedEntryURISrc, $encodedEntryURIDest); + } else { + continue; + } + } + + $uri = sprintf('%s?%s', $this->host() . '/batch', $requestParams); + + return $this->post($uri); + } + + /** + * 镜像资源更新 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $resourceName + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function prefetch(string $bucket, string $resourceName) + { + $encodedEntryUri = $this->encodedEntry($bucket, $resourceName); + + $uri = sprintf($this->host('iovip') .'/prefetch/%s' , $encodedEntryUri); + + return $this->post($uri); + } + + /** + * Http 直传文件 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param resource $file + * @param array $params 直传可选参数 => https://developer.qiniu.com/kodo/api/1312/upload + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + public function uploadFile(string $bucket, $file, array $params = []) + { + if (!is_resource($file)) { + throw new \Exception('$file Must Be Resource Type'); + } + + $uri = $this->host( 'up'); + $stream = new Stream($file); + //判断如果文件大于4M则使用分块上传 + if ($stream->getSize() > self::BLOCK_SIZE) { + return $this->uploadFileByBlocks($bucket, $file); + } + + //$filename = md5(basename($stream->getMetadata('uri')) . time()); + $uploadToken = $this->UploadToken($bucket); + + $options['multipart'] = [ + ['name' => 'key', 'contents' => basename($stream->getMetadata('uri'))], + ['name' => 'file', 'contents' => $stream, 'filename' => basename($stream->getMetadata('uri'))], + ['name' => 'token', 'contents' => $uploadToken], + ['name' => 'crc32', 'contents' => self::crc32_data($stream)], + ['name' => 'Content-Type', 'contents' => 'application/octet-stream'], + ]; + + if (!empty($params)) { + $options['multipart'] = array_merge($params, $options['multipart']); + } + + return $this->post($uri, $options); + } + + /** + * 创建块 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param $file + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + protected function uploadFileByBlocks(string $bucket, $file) + { + //需要安装fileinfo扩展 + if (!extension_loaded('fileinfo')) { + throw NotFoundException::NotFoundExtension('PHPExtension Fileinfo Not Found, Please Install It First'); + } + $stream = new Stream($file); + $filezie = $stream->getSize(); + //保存ctx值, 用于后续合并文件 + $ctxArr = []; + //已上传文件大小 + $uploadSize = 0; + while ($uploadSize < $filezie) { + //剩余文件大小 + $remainsize = $filezie - $uploadSize; + //需要读取的文件大小 + $needReadSize = $remainsize > self::BLOCK_SIZE ? self::BLOCK_SIZE : $remainsize; + $content = $stream->read($needReadSize); + //创建块并且上传第一个片 + $options['body'] = $content; + $headers = [ + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => $needReadSize, + ]; + $options['headers'] = $headers; + $uri = sprintf($this->host( 'up') .'/mkblk/%s' , $needReadSize); + $response = $this->post($uri, $options); + $data = json_decode($response->getBody()->getContents(), true); + + array_push($ctxArr, $data['ctx']); + $uploadSize += $needReadSize; + } + + return $this->mkfile($stream, $bucket, $ctxArr); + } + + /** + * 创建文件 + * + * @time at 2019年01月26日 + * @param Stream $stream + * @param string $bucket + * @param array $ctx + * @throws \thinking\icloud\exception\NotFoundException + * @return mixed + */ + protected function mkfile(Stream $stream, string $bucket, array $ctx) + { + $file = $stream->getMetadata('uri'); + $key = self::urlSafeBase64Encode(sprintf('%s', basename($file))); + $mimetype = (new finfo(FILEINFO_MIME_TYPE))->file($file); + $filesize = $stream->getSize(); + $userVar = md5(time()); + + $options['headers'] = ['Authorization' => 'UpToken ' . $this->UploadToken($bucket, basename($file))]; + $options['body'] = implode(',', $ctx); + + $uri = sprintf($this->host( 'up') . '/mkfile/%s/key/%s/mimeType/%s/x:user-var/%s', $filesize, $key, self::urlSafeBase64Encode($mimetype), self::urlSafeBase64Encode($userVar)); + return $this->post($uri, $options); + } +} \ No newline at end of file diff --git a/extend/icloud/src/cloud/UpYunCloud.php b/extend/icloud/src/cloud/UpYunCloud.php new file mode 100644 index 0000000..4448622 --- /dev/null +++ b/extend/icloud/src/cloud/UpYunCloud.php @@ -0,0 +1,270 @@ +host( 'v0') . '/%s/', $bucket . $directory ); + + return $this->post($uri); + } + + /** + * 删除空间 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $directory + * @throws NotFoundException + * @return mixed + */ + public function drop(string $bucket, string $directory) + { + $uri = sprintf($this->host( 'v0') . '/%s/', $bucket . $directory ); + + return $this->delete($uri); + } + + /** + * 获取文件列表 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $directory + * @param array $options ['x-list-iter' => '分页开始位置', 'x-list-limit' => '获取文件数量', 'x-list-order' => '排序' ] + * @throws NotFoundException + * @return mixed + */ + public function list(string $bucket, string $directory, array $options = ['x-list-limit' => 1]) + { + $uri = sprintf($this->host( 'v0') . '/%s/', $bucket . $directory ); + + return $this->get($uri, $options); + } + + /** + * 获取服务容量 + * + * @time at 2019年01月26日 + * @param string $bucket + * @throws NotFoundException + * @return mixed + */ + public function usage(string $bucket) + { + $uri = sprintf($this->host( 'v0') . '/%s/?usage', $bucket ); + + return $this->get($uri); + } + + /** + * 删除文件 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $fileDir + * @throws NotFoundException + * @return mixed + */ + public function deleteFile(string $bucket, string $fileDir) + { + $uri = sprintf($this->host( 'v0') . '/%s/%s' , $bucket, $fileDir ); + + return $this->delete($uri); + } + + /** + * 下载文件 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $fileDir + * @throws NotFoundException + * @return mixed + */ + public function downloadFile(string $bucket, string $fileDir) + { + $uri = sprintf($this->host( 'v0') . '/%s/%s' , $bucket, $fileDir ); + + return $this->get($uri, ['stream' => true]); + } + + /** + * 上传文件 + * + * @time at 2019年01月26日 + * @param string $bucket + * @param string $fileDir + * @param $locationFile + * @param array $options => 参考http://docs.upyun.com/api/rest_api/#_2 + * @throws NotFoundException + * @return mixed + */ + public function uploadFile(string $bucket, string $fileDir, $locationFile, array $options = []) + { + if (!is_resource($locationFile)) { + throw new \Exception('$localfile Must Be Resource Type', 500); + } + $stream = new Stream($locationFile); + + $this->bucket = $bucket; + $this->fileDir = $fileDir; + $this->stream = $stream; + $this->options = $options; + $this->filename = basename($stream->getMetadata('uri')); + #上传文件大于限制文件大小, 则断点续传 + if ( $stream->getSize() > self::BLOCK_SIZE ) { + return $this->uploadComplete(); + } + + $uri = sprintf($this->host('v0') . '/%s/%s', $this->bucket, $this->fileDir . $this->filename); + + if (!empty($this->options)) $options['headers'] = $this->options; + $options['headers'] = ['Content-Length' => $stream->getSize()]; + $options['body'] = $this->stream; + + return $this->put($uri, $this->options); + } + + /** + * 初始化断电续传 + * + * @time at 2019年01月26日 + * @throws NotFoundException + * @return void + */ + protected function initUpload() + { + $mimeType = (new finfo(FILEINFO_MIME_TYPE))->file($this->stream->getMetadata('uri')); + + $headers = [ + 'x-upyun-multi-stage' => 'initiate', + 'x-upyun-multi-length' => $this->stream->getSize(), + 'x-upyun-multi-type' => $mimeType ? : 'application/octet-stream', + ]; + $this->options['headers'] = $headers; + + $uri = sprintf($this->host( 'v0') . '/%s/%s', $this->bucket, $this->fileDir . $this->filename); + $response = $this->put($uri, $this->options); + + if ( !($response->getStatusCode() == self::SUCCESS_CODE) ) { + throw new \Exception('Failed To Respond'); + } + + $headers = $response->getHeaders(); + + if (!isset($headers['x-upyun-multi-uuid'])) { + throw NotFoundException::NotFoundKey('Response Headers Not Found Key "x-upyun-multi-uuid"'); + } + + if (!isset($headers['x-upyun-next-part-id'])) { + throw NotFoundException::NotFoundKey('Response Headers Not Found Key "x-upyun-next-part-id"'); + } + + $this->multiuuid = $headers['x-upyun-multi-uuid']; + $this->nextpartid = $headers['x-upyun-next-part-id']; + } + + /** + * 上传分块 + * + * @time at 2019年01月26日 + * @throws NotFoundException + * @return void + */ + protected function uploading() + { + $uploadSize = 0; + + $filesize = $this->stream->getSize(); + while ($uploadSize < $filesize) { + //剩余文件大小 + $remainsize = $filesize - $uploadSize; + //需要读取的文件大小 + $needReadSize = $remainsize > self::BLOCK_SIZE ? self::BLOCK_SIZE : $remainsize; + $content = $this->stream->read($needReadSize); + + $headrs = [ + 'x-upyun-multi-stage' => 'upload', + 'x-upyun-multi-uuid' => $this->multiuuid, + 'x-upyun-part-id' => $this->nextpartid, + ]; + + $this->options['body'] = $content; + $this->options['headers'] = $headrs; + $uri = sprintf($this->host( 'v0') . '/%s/%s', $this->bucket, $this->fileDir . $this->filename); + $response = $this->put($uri, $this->options); + if ( !($response->getStatusCode() == self::SUCCESS_CODE) ) { + throw new \Exception('Failed To Respond'); + } + $headers = $response->getHeaders(); + if (!isset($headers['x-upyun-multi-uuid'])) { + throw NotFoundException::NotFoundKey('Response Headers Not Found Key "x-upyun-multi-uuid"'); + } + if (!isset($headers['x-upyun-next-part-id'])) { + throw NotFoundException::NotFoundKey('Response Headers Not Found Key "x-upyun-next-part-id"'); + } + $this->multiuuid = $headers['x-upyun-multi-uuid']; + $this->nextpartid = $headers['x-upyun-next-part-id']; + $uploadSize += $needReadSize; + } + } + + /** + * 完成上传 + * + * @time at 2019年01月26日 + * @throws NotFoundException + * @return mixed + */ + protected function uploadComplete() + { + //初始化 + $this->initUpload(); + //上传 + $this->uploading(); + //合并完成上传 + $headers = [ + 'x-upyun-multi-stage' => 'complete', + 'x-upyun-multi-uuid' => $this->multiuuid, + ]; + $this->options['headers'] = $headers; + + $uri = sprintf($this->host( 'v0') .'/%s/%s', $this->bucket, $this->fileDir . $this->filename); + return $this->put($uri, $this->options); + } +} \ No newline at end of file diff --git a/extend/icloud/src/exception/NotFoundException.php b/extend/icloud/src/exception/NotFoundException.php new file mode 100644 index 0000000..d75c227 --- /dev/null +++ b/extend/icloud/src/exception/NotFoundException.php @@ -0,0 +1,50 @@ +$name(...$arguments); + } + +} \ No newline at end of file