增加存储服务

This commit is contained in:
JaguarJack 2019-01-26 18:04:59 +08:00
parent 4cbd141416
commit 7ac093e814
9 changed files with 1177 additions and 0 deletions

View File

@ -0,0 +1,104 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 11:37
*/
namespace thinking\icloud;
use thinking\icloud\auth\AuthFactory;
use thinking\icloud\Utility;
use thinking\icloud\exception\NotFoundException;
class AbstractCloud
{
use Utility;
protected $api;
protected $host;
protected $namespace;
protected $response;
public function __construct()
{
$this->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);
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 10:37
*/
namespace thinking\icloud;
trait Utility
{
/**
* URL Base64 加密
*
* @time at 2019年01月26日
* @param string $string
* @return mixed
*/
public static function urlSafeBase64Encode(string $string)
{
return str_replace(['+','/'], ['-','_'], base64_encode($string));
}
/**
* 获取接口 HOST
*
* @time at 2019年01月26日
* @param string $host
* @param bool $isHttps
* @return string
*/
public static function getHost(string $host = 'rs', bool $isHttps = false)
{
return $isHttps ? 'https://' : 'http://' . config('icloud.host.'. strtolower($host));
}
/**
* csc32 校验
*
* @time at 2019年01月26日
* @param string $data
* @return string
*/
public static function crc32_data(string $data)
{
$hash = hash('crc32b', $data);
$array = unpack('N', pack('H*', $hash));
return sprintf('%u', $array[1]);
}
}

View File

@ -0,0 +1,135 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 10:30
*/
namespace thinking\icloud\auth;
use thinking\icloud\Utility;
final class QiniuAuth
{
use Utility;
/**
* 授权凭证
*
* @time at 2019年01月26日
* @param string $uri
* @param string $method
* @return array
*/
public static function authorization(string $uri, string $method)
{
return ['Authorization' => 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);
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 10:31
*/
namespace thinking\icloud\auth;
class UpYunAuth
{
/**
* 签名
*
* @time at 2019年01月26日
* @param string $uri
* @param string $method
* @param string $contentMD5
* @return array
*/
public static function authorization(string $uri, string $method, string $contentMD5= '')
{
$date = gmdate('D, d M Y H:i:s \G\M\T');
$singArr = [$method, parse_url($uri)['path'], $date];
if ($contentMD5) $singArr[] = $contentMD5;
$sign = base64_encode(hash_hmac('sha1', implode('&', $singArr), md5(config('cloud.upyun.password')), true));
return [
'Authorization' => 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);
}
}

View File

@ -0,0 +1,417 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 11:33
*/
namespace thinking\icloud\cloud;
use thinking\icloud\AbstractCloud;
use finfo;
use thinking\icloud\exception\NotFoundException;
use GuzzleHttp\Psr7\Stream;
class QiNiuCloud extends AbstractCloud
{
const BLOCK_SIZE = 4 * 1024 * 1024;
/**
* 获取 bucket 列表
*
* @time at 2019年01月26日
* @throws NotFoundException
* @return mixed
*/
public function buckets()
{
$uri = $this->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);
}
}

View File

@ -0,0 +1,270 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 11:34
*/
namespace thinking\icloud\cloud;
use thinking\icloud\AbstractCloud;
use thinking\icloud\exception\NotFoundException;
use GuzzleHttp\Psr7\Stream;
class UpYunCloud extends AbstractCloud
{
const BLOCK_SIZE = 1024 * 1024;
const SUCCESS_CODE = 204;
protected $bucket;
protected $fileDir;
protected $stream;
protected $options;
protected $filename;
//本次上传任务的标识,是初始化断点续传任务时响应信息中的
protected $multiuuid;
//指定此次分片的唯一 ID应严格等于上一次请求返回的
protected $nextpartid;
/**
* 创建文件夹
*
* @time at 2019年01月26日
* @param string $bucket
* @param string $directory
* @throws NotFoundException
* @return mixed
*/
public function create(string $bucket, string $directory)
{
$uri = sprintf($this->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);
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 11:38
*/
namespace thinking\icloud\exception;
class NotFoundException extends \Exception
{
/**
* key not found
*
* @time at 2019年01月26日
* @param string $msg
* @param int $code
* @return NotFoundException
*/
public static function NotFoundKey(string $msg, $code = 404)
{
return new static($msg, $code, null);
}
/**
* method not found
*
* @time at 2019年01月26日
* @param string $msg
* @param int $code
* @return NotFoundException
*/
public static function NotFoundMethod(string $msg, int $code = 404)
{
return new static($msg, $code, null);
}
/**
* extension not found
*
* @time at 2019年01月26日
* @param string $msg
* @param int $code
* @return NotFoundException
*/
public static function NotFoundExtension(string $msg, $code = 404)
{
return new static($msg, $code, null);
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 10:28
*/
namespace thinking\icloud\factory;
class AuthFactory
{
/**
* 认证驱动
*
* @time at 2019年01月26日
* @param string $name
* @param mixed ...$argument
* @return mixed
*/
public static function create(string $name, ...$argument)
{
$defaultDriver = config('cloud.driver.default');
$auth = config('cloud.driver.' . $defaultDriver . 'Auth');
return $auth::$name(...$argument);
}
/**
* 静态访问
*
* @time at 2019年01月26日
* @param string $name
* @param $argument
* @return mixed
*/
public static function __callstatic(string $name, $argument)
{
return self::create($name, ...$argument);
}
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/1/26
* Time: 10:23
*/
namespace thinking\icloud\factory;
class ICloudFactory
{
protected static $driver = null;
/**
* set driver
*
* @time at 2019年01月26日
* @param string $driver
* @return static
*/
public static function driver(string $driver)
{
self::$driver = $driver;
// 设置 config 驱动
config('cloud.driver.default', $driver);
return new static();
}
/**
* 静态访问
*
* @time at 2019年01月26日
* @param $name
* @param mixed ...$arguments
* @return mixed
*/
public static function __callStatic($name, ...$arguments)
{
$cloud = !self::$driver ? config('cloud.driver.' . config('cloud.driver.default')) : config('cloud.driver.' . self::$driver);
// TODO: Implement __callStatic() method.
return (new $cloud)->$name(...$arguments);
}
}