From 3a094e2bcb6572248be578f7d3ac81a380fc9504 Mon Sep 17 00:00:00 2001 From: Chaim Date: Fri, 12 Jun 2020 13:58:05 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E6=94=AF=E6=8C=81=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E7=9A=84=E4=BA=91=E5=AD=98=E5=82=A8=EF=BC=88=E9=87=91=E5=B1=B1?= =?UTF-8?q?=E4=BA=91=E3=80=81=E7=A7=BB=E5=8A=A8=E4=BA=91=E3=80=81=E7=BD=91?= =?UTF-8?q?=E6=98=93=E4=BA=91=E3=80=81=E4=BC=98=E5=88=BB=E5=BE=97=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 3 +- src/config.php | 33 + src/service/douyin/WatermarkService.php | 62 + src/service/ecloud/OnestService.php | 103 + src/service/ksyun/Ks3Service.php | 122 + src/service/ksyun/bin/Ks3Client.class.php | 370 +++ .../ksyun/bin/Ks3EncryptionClient.class.php | 129 + src/service/ksyun/bin/config/Consts.php | 54 + src/service/ksyun/bin/core/API.php | 271 ++ src/service/ksyun/bin/core/Builders.php | 102 + src/service/ksyun/bin/core/Handlers.php | 343 +++ src/service/ksyun/bin/core/Headers.php | 29 + .../ksyun/bin/core/Ks3Request.class.php | 84 + src/service/ksyun/bin/core/Logger.php | 46 + src/service/ksyun/bin/core/MessageHolder.php | 5 + src/service/ksyun/bin/core/Signers.php | 541 ++++ src/service/ksyun/bin/core/Utils.class.php | 235 ++ .../bin/encryption/EncryptionCallBack.php | 227 ++ .../bin/encryption/EncryptionHandlers.php | 358 +++ .../ksyun/bin/encryption/EncryptionUtil.php | 279 +++ .../ksyun/bin/exceptions/Exceptions.php | 34 + .../ksyun/bin/lib/RequestCore.class.php | 1028 ++++++++ src/service/ksyun/bin/readme.md | 1227 ++++++++++ src/service/ksyun/bin/samples/FormUpload.php | 48 + src/service/ksyun/bin/samples/Samples.php | 413 ++++ .../bin/samples/TestEncryptionClientFile.php | 170 ++ .../bin/samples/TestEncryptionClientMeta.php | 136 ++ src/service/ksyun/bin/samples/secret.key | 2 + src/service/ksyun/bin/unit/PUnit.php | 60 + src/service/ksyun/bin/unit/Test.php | 922 +++++++ src/service/ksyun/bin/unit/TestUtil.php | 53 + src/service/ksyun/bin/unit/cache/test_file | 2176 +++++++++++++++++ src/service/ksyun/bin/unit/secret.key | 2 + src/service/ksyun/bin/更新日志.txt | 24 + src/service/netease/NosService.php | 90 + src/service/ucloud/UfileService.php | 49 + src/service/ucloud/bin/CHANGELOG.md | 18 + src/service/ucloud/bin/README.md | 16 + src/service/ucloud/bin/v1/demo/append.php | 21 + src/service/ucloud/bin/v1/demo/delete.php | 17 + src/service/ucloud/bin/v1/demo/get.php | 39 + .../ucloud/bin/v1/demo/listobjects.php | 26 + src/service/ucloud/bin/v1/demo/multipart.php | 22 + src/service/ucloud/bin/v1/demo/mupload.php | 42 + src/service/ucloud/bin/v1/demo/put.php | 19 + src/service/ucloud/bin/v1/demo/uploadhit.php | 21 + src/service/ucloud/bin/v1/ucloud/conf.php | 15 + src/service/ucloud/bin/v1/ucloud/digest.php | 98 + src/service/ucloud/bin/v1/ucloud/http.php | 373 +++ .../ucloud/bin/v1/ucloud/mimetypes.php | 449 ++++ src/service/ucloud/bin/v1/ucloud/proxy.php | 361 +++ src/service/ucloud/bin/v1/ucloud/utils.php | 147 ++ 52 files changed, 11513 insertions(+), 1 deletion(-) create mode 100644 src/service/ecloud/OnestService.php create mode 100644 src/service/ksyun/Ks3Service.php create mode 100644 src/service/ksyun/bin/Ks3Client.class.php create mode 100644 src/service/ksyun/bin/Ks3EncryptionClient.class.php create mode 100644 src/service/ksyun/bin/config/Consts.php create mode 100644 src/service/ksyun/bin/core/API.php create mode 100644 src/service/ksyun/bin/core/Builders.php create mode 100644 src/service/ksyun/bin/core/Handlers.php create mode 100644 src/service/ksyun/bin/core/Headers.php create mode 100644 src/service/ksyun/bin/core/Ks3Request.class.php create mode 100644 src/service/ksyun/bin/core/Logger.php create mode 100644 src/service/ksyun/bin/core/MessageHolder.php create mode 100644 src/service/ksyun/bin/core/Signers.php create mode 100644 src/service/ksyun/bin/core/Utils.class.php create mode 100644 src/service/ksyun/bin/encryption/EncryptionCallBack.php create mode 100644 src/service/ksyun/bin/encryption/EncryptionHandlers.php create mode 100644 src/service/ksyun/bin/encryption/EncryptionUtil.php create mode 100644 src/service/ksyun/bin/exceptions/Exceptions.php create mode 100644 src/service/ksyun/bin/lib/RequestCore.class.php create mode 100644 src/service/ksyun/bin/readme.md create mode 100644 src/service/ksyun/bin/samples/FormUpload.php create mode 100644 src/service/ksyun/bin/samples/Samples.php create mode 100644 src/service/ksyun/bin/samples/TestEncryptionClientFile.php create mode 100644 src/service/ksyun/bin/samples/TestEncryptionClientMeta.php create mode 100644 src/service/ksyun/bin/samples/secret.key create mode 100644 src/service/ksyun/bin/unit/PUnit.php create mode 100644 src/service/ksyun/bin/unit/Test.php create mode 100644 src/service/ksyun/bin/unit/TestUtil.php create mode 100644 src/service/ksyun/bin/unit/cache/test_file create mode 100644 src/service/ksyun/bin/unit/secret.key create mode 100644 src/service/ksyun/bin/更新日志.txt create mode 100644 src/service/netease/NosService.php create mode 100644 src/service/ucloud/UfileService.php create mode 100644 src/service/ucloud/bin/CHANGELOG.md create mode 100644 src/service/ucloud/bin/README.md create mode 100644 src/service/ucloud/bin/v1/demo/append.php create mode 100644 src/service/ucloud/bin/v1/demo/delete.php create mode 100644 src/service/ucloud/bin/v1/demo/get.php create mode 100644 src/service/ucloud/bin/v1/demo/listobjects.php create mode 100644 src/service/ucloud/bin/v1/demo/multipart.php create mode 100644 src/service/ucloud/bin/v1/demo/mupload.php create mode 100644 src/service/ucloud/bin/v1/demo/put.php create mode 100644 src/service/ucloud/bin/v1/demo/uploadhit.php create mode 100644 src/service/ucloud/bin/v1/ucloud/conf.php create mode 100644 src/service/ucloud/bin/v1/ucloud/digest.php create mode 100644 src/service/ucloud/bin/v1/ucloud/http.php create mode 100644 src/service/ucloud/bin/v1/ucloud/mimetypes.php create mode 100644 src/service/ucloud/bin/v1/ucloud/proxy.php create mode 100644 src/service/ucloud/bin/v1/ucloud/utils.php diff --git a/composer.json b/composer.json index 93e80b9..7404d7f 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,8 @@ "qcloud/cos-sdk-v5": "^2.0", "qiniu/php-sdk": "^7.2", "upyun/sdk": "^3.4", - "jdcloud-api/jdcloud-sdk-php": "^5.2" + "netease/nos-php-sdk": "^1.0", + "aws/aws-sdk-php": "^3.142" }, "require-dev": { "symfony/var-dumper": "^4.2" diff --git a/src/config.php b/src/config.php index 005a7bc..958dbfa 100644 --- a/src/config.php +++ b/src/config.php @@ -163,4 +163,37 @@ return [ 'url' => '', ] ], + // 金山云 + 'ksyun' => [ + // 云存储 + 'ks3' => [ + 'access_key_iD' => '', + 'access_key_secret' => '', + 'endpoint' => '', + 'bucket' => '', + 'url' => '', + ] + ], + // 网易云 + 'netease' => [ + // 云存储 + 'ks3' => [ + 'access_key_id' => '', + 'access_key_secret' => '', + 'endpoint' => '', + 'bucket' => '', + 'url' => '', + ] + ], + // UCloud优刻得 + 'ucloud' => [ + // 云存储 + 'ufile' => [ + 'proxy_suffix' => '', + 'public_key' => '', + 'private_key' => '', + 'bucket' => '', + 'url' => '', + ] + ], ]; diff --git a/src/service/douyin/WatermarkService.php b/src/service/douyin/WatermarkService.php index bf37e19..5d6a374 100644 --- a/src/service/douyin/WatermarkService.php +++ b/src/service/douyin/WatermarkService.php @@ -22,9 +22,11 @@ use DtApp\ThinkLibrary\Service; use DtApp\ThinkLibrary\service\aliyun\OssService; use DtApp\ThinkLibrary\service\baidu\BosService; use DtApp\ThinkLibrary\service\huaweicloud\ObsService; +use DtApp\ThinkLibrary\service\ksyun\Ks3Service; use DtApp\ThinkLibrary\service\qiniu\KodoService; use DtApp\ThinkLibrary\service\StorageService; use DtApp\ThinkLibrary\service\tencent\CosService; +use DtApp\ThinkLibrary\service\ucloud\UfileService; use DtApp\ThinkLibrary\service\upyun\UssService; use Exception; use stdClass; @@ -463,6 +465,66 @@ class WatermarkService extends Service $backtrack['yun']['video_info']['playwm'] = UssService::instance() ->upload($yun_path . $backtrack['video_info']['vid'] . "_playwm" . ".mp4", $system_path . $backtrack['video_info']['vid'] . "_playwm" . ".mp4"); break; + case "ksyun": + // 作者头像 + $backtrack['yun']['author_info']['avatar'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['author_info']['uid'] . ".jpeg", $system_path . $backtrack['author_info']['uid'] . ".jpeg"); + // 音频头像 + $backtrack['yun']['music_info']['avatar'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['music_info']['mid'] . ".jpeg", $system_path . $backtrack['music_info']['mid'] . ".jpeg"); + // 音频文件 + if (!empty($backtrack['music_info']['play'])) $backtrack['yun']['music_info']['play'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['music_info']['mid'] . ".mp3", $system_path . $backtrack['music_info']['mid'] . ".mp3"); + else $backtrack['yun']['music_info']['play'] = ''; + // 音频封面 + $backtrack['yun']['music_info']['cover'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['music_info']['mid'] . "_cover" . ".jpeg", $system_path . $backtrack['music_info']['mid'] . "_cover" . ".jpeg"); + // 视频封面 + $backtrack['yun']['video_info']['dynamic'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_dynamic" . ".jpeg", $system_path . $backtrack['video_info']['vid'] . "_dynamic" . ".jpeg"); + // 视频封面 + $backtrack['yun']['video_info']['origin_cover'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_origin_cover" . ".jpeg", $system_path . $backtrack['video_info']['vid'] . "_origin_cover" . ".jpeg"); + // 视频封面 + $backtrack['yun']['video_info']['cover'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_cover" . ".jpeg", $system_path . $backtrack['video_info']['vid'] . "_cover" . ".jpeg"); + // 视频文件 + $backtrack['yun']['video_info']['play'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_play" . ".mp4", $system_path . $backtrack['video_info']['vid'] . "_play" . ".mp4"); + // 视频文件 + $backtrack['yun']['video_info']['playwm'] = Ks3Service::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_playwm" . ".mp4", $system_path . $backtrack['video_info']['vid'] . "_playwm" . ".mp4"); + break; + case "ucloud": + // 作者头像 + $backtrack['yun']['author_info']['avatar'] = UfileService::instance() + ->upload($yun_path . $backtrack['author_info']['uid'] . ".jpeg", $system_path . $backtrack['author_info']['uid'] . ".jpeg"); + // 音频头像 + $backtrack['yun']['music_info']['avatar'] = UfileService::instance() + ->upload($yun_path . $backtrack['music_info']['mid'] . ".jpeg", $system_path . $backtrack['music_info']['mid'] . ".jpeg"); + // 音频文件 + if (!empty($backtrack['music_info']['play'])) $backtrack['yun']['music_info']['play'] = UfileService::instance() + ->upload($yun_path . $backtrack['music_info']['mid'] . ".mp3", $system_path . $backtrack['music_info']['mid'] . ".mp3"); + else $backtrack['yun']['music_info']['play'] = ''; + // 音频封面 + $backtrack['yun']['music_info']['cover'] = UfileService::instance() + ->upload($yun_path . $backtrack['music_info']['mid'] . "_cover" . ".jpeg", $system_path . $backtrack['music_info']['mid'] . "_cover" . ".jpeg"); + // 视频封面 + $backtrack['yun']['video_info']['dynamic'] = UfileService::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_dynamic" . ".jpeg", $system_path . $backtrack['video_info']['vid'] . "_dynamic" . ".jpeg"); + // 视频封面 + $backtrack['yun']['video_info']['origin_cover'] = UfileService::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_origin_cover" . ".jpeg", $system_path . $backtrack['video_info']['vid'] . "_origin_cover" . ".jpeg"); + // 视频封面 + $backtrack['yun']['video_info']['cover'] = UfileService::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_cover" . ".jpeg", $system_path . $backtrack['video_info']['vid'] . "_cover" . ".jpeg"); + // 视频文件 + $backtrack['yun']['video_info']['play'] = UfileService::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_play" . ".mp4", $system_path . $backtrack['video_info']['vid'] . "_play" . ".mp4"); + // 视频文件 + $backtrack['yun']['video_info']['playwm'] = UfileService::instance() + ->upload($yun_path . $backtrack['video_info']['vid'] . "_playwm" . ".mp4", $system_path . $backtrack['video_info']['vid'] . "_playwm" . ".mp4"); + break; default: break; } diff --git a/src/service/ecloud/OnestService.php b/src/service/ecloud/OnestService.php new file mode 100644 index 0000000..d6e769f --- /dev/null +++ b/src/service/ecloud/OnestService.php @@ -0,0 +1,103 @@ +accessKey = $accessKey; + return $this; + } + + public function secretKey(string $secretKey) + { + $this->secretKey = $secretKey; + return $this; + } + + public function bucket(string $bucket) + { + $this->bucket = $bucket; + return $this; + } + + public function baseUrl(string $baseUrl) + { + $this->baseUrl = $baseUrl; + return $this; + } + + public function port(string $port) + { + $this->port = $port; + return $this; + } + + /** + * 获取配置信息 + * @return $this + */ + private function getConfig() + { + $this->accessKey = $this->app->config->get('dtapp.ecloud.onest.access_key'); + $this->secretKey = $this->app->config->get('dtapp.ecloud.onest.secret_key'); + $this->bucket = $this->app->config->get('dtapp.ecloud.onest.bucket'); + $this->baseUrl = $this->app->config->get('dtapp.ecloud.onest.base_url'); + $this->port = $this->app->config->get('dtapp.ecloud.onest.port'); + return $this; + } + + /** + * 上传文件 + * @param $object + * @param $filePath + * @return bool + */ + public function upload(string $object, string $filePath) + { + if (empty($this->accessKey)) $this->getConfig(); + if (empty($this->secretKey)) $this->getConfig(); + if (empty($this->baseUrl)) $this->getConfig(); + if (empty($this->port)) $this->getConfig(); + + $client = S3Client::factory([ + 'base_url' => $this->baseUrl, + 'port' => $this->port, + 'key' => $this->accessKey, + 'secret' => $this->secretKey, + S3Client::COMMAND_PARAMS => [ + 'PathStyle' => true, + ], + ]); + if (empty($this->bucket)) $this->getConfig(); + $acl = 'public'; + $client->upload($this->bucket, $object, fopen($filePath, 'rb'), $acl); + return $this->app->config->get('dtapp.ecloud.onest.url') . $object; + } +} diff --git a/src/service/ksyun/Ks3Service.php b/src/service/ksyun/Ks3Service.php new file mode 100644 index 0000000..24766f8 --- /dev/null +++ b/src/service/ksyun/Ks3Service.php @@ -0,0 +1,122 @@ +accessKeyID = $accessKeyID; + return $this; + } + + public function accessKeySecret(string $accessKeySecret) + { + $this->accessKeySecret = $accessKeySecret; + return $this; + } + + public function endpoint(string $endpoint) + { + $this->endpoint = $endpoint; + return $this; + } + + public function bucket(string $bucket) + { + $this->bucket = $bucket; + return $this; + } + + /** + * 获取配置信息 + * @return $this + */ + private function getConfig() + { + $this->accessKeyID = $this->app->config->get('dtapp.ksyun.ks3.access_key_iD'); + $this->accessKeySecret = $this->app->config->get('dtapp.ksyun.ks3.access_key_secret'); + $this->endpoint = $this->app->config->get('dtapp.ksyun.ks3.endpoint'); + $this->bucket = $this->app->config->get('dtapp.ksyun.ks3.bucket'); + return $this; + } + + /** + * 上传文件 + * @param string $object + * @param string $filePath + * @return bool|string + */ + public function upload(string $object, string $filePath) + { + if (empty($this->accessKeyID)) $this->getConfig(); + if (empty($this->accessKeySecret)) $this->getConfig(); + if (empty($this->endpoint)) $this->getConfig(); + //是否使用VHOST + define("KS3_API_VHOST", FALSE); + //是否开启日志(写入日志文件) + define("KS3_API_LOG", TRUE); + //是否显示日志(直接输出日志) + define("KS3_API_DISPLAY_LOG", TRUE); + //定义日志目录(默认是该项目log下) + define("KS3_API_LOG_PATH", ""); + //是否使用HTTPS + define("KS3_API_USE_HTTPS", FALSE); + //是否开启curl debug模式 + define("KS3_API_DEBUG_MODE", FALSE); + $client = new Ks3Client($this->accessKeyID, $this->accessKeySecret, $this->endpoint); + if (empty($this->bucket)) $this->getConfig(); + $content = fopen($filePath, "r"); + $args = [ + "Bucket" => $this->bucket, + "Key" => $object, + "Content" => [ + //要上传的内容 + "content" => $content,//可以是文件路径或者resource,如果文件大于2G,请提供文件路径 + "seek_position" => 0//跳过文件开头?个字节 + ], + "ACL" => "public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta" => [ + //设置object的元数据,可以设置"Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires"。当设置了Content-Length时,最后上传的为从seek_position开始向后Content-Length个字节的内容。当设置了Content-MD5时,系统会在服务端进行md5校验。 + "Content-Type" => "binay/ocet-stream" + //"Content-Length"=>4 + ], + "UserMeta" => [ + //可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test" => "test" + ] + ]; + try { + $client->putObjectByFile($args); + return $this->app->config->get('dtapp.ksyun.ks3.url') . $object; + } catch (Ks3ServiceException $e) { + return false; + } + } +} diff --git a/src/service/ksyun/bin/Ks3Client.class.php b/src/service/ksyun/bin/Ks3Client.class.php new file mode 100644 index 0000000..4195775 --- /dev/null +++ b/src/service/ksyun/bin/Ks3Client.class.php @@ -0,0 +1,370 @@ +accessKey = $accessKey; + $this->secretKey = $secretKey; + + if(empty($endpoint)){ + throw new Ks3ClientException("must set endpoint, please see http://ks3.ksyun.com/doc/api/index.html Region part"); + } + $this->endpoint = $endpoint; + + $this->signers = array(); + $this->log = new Logger(); + } + /** + 方法列表:(具体使用请参考readme.md) + listBuckets,罗列bucket + deleteBucket,删除bucket + deleteBucketCORS,删除bucket跨域配置 + createBucket,新建bucket + setBucketAcl,设置bucket访问权限 + setBucketCORS,设置bucket跨域配置 + setBucketLogging,设置bucket日志配置 + listObjects,罗列object + getBucketAcl,获取bucket访问权限 + getBucketCORS,获取bucket跨域配置 + getBucketLocation,获取bucket地点配置 + getBucketLogging,获取bucket日志配置 + bucketExists,判断bucket是否存在 + listMutipartUploads,罗列当前bucket下尚未结束的分块上传 + putObjectByContent,上传文件 + putObjectByFile,上传文件 + setObjectAcl,设置object访问权限 + copyObject,复制object + getObjectMeta,获取object元数据 + objectExists,判断object是否存在 + deleteObject,删除object + deleteObjects,删除多个object + getObject,下载object + getObjectAcl,获取object访问权限 + initMultipartUpload,初始化分块上传 + uploadPart,上传块 + abortMultipartUpload,终止分块上传 + listParts,罗列已经上传的块 + completeMultipartUpload,完成分块上传 + generatePresignedUrl,生成文件外链 + putAdp,添加异步数据处理任务 + getAdp,查询异步数据处理任务 + */ + public function __call($method,$args=array()){ + $holder = new MessageHolder(); + + $holder->msg = "------------------Logging Start-------------------------\r\n"; + $holder->msg .= "method->".$method." args->".serialize($args)."\r\n"; + $ex = NULL; + try{ + $result = $this->invoke($method,$args,$holder); + }catch(Exception $e){ + $holder->msg.=$e."\r\n"; + $ex = $e; + } + $holder->msg .= "------------------Logging End-------------------------\r\n"; + $this->log->info($holder->msg); + if($ex !=NULL) + throw $ex; + return $result; + } + private function invoke($method,$args=array(),$holder,$location=NULL){ + $api = API::$API[$method]; + if(!$api){ + throw new Ks3ClientException($method." Not Found API"); + } + if(count($args) !== 0){ + if(count($args)>1||!is_array($args[0])){ + throw new Ks3ClientException("this method only needs one array argument"); + } + $args = $args[0]; + } + if(isset($api["redirect"])){ + $api = API::$API[$api["redirect"]]; + } + $request = new Ks3Request(); + if(empty($args["Bucket"])){ + if($api["needBucket"]){ + throw new Ks3ClientException($method." this api need bucket"); + } + }else{ + $request->bucket = $args["Bucket"]; + } + $position = "Key"; + //position主要为queryadp接口用的 + if(isset($api["objectPostion"])){ + $position = $api["objectPostion"]; + } + if(empty($args[$position])){ + if($api["needObject"]){ + throw new Ks3ClientException($method." this api need ".$position); + } + }else{ + $key = $args[$position]; + $preEncoding = mb_detect_encoding($key, array("ASCII","UTF-8","GB2312","GBK","BIG5")); + $holder->msg.="key encoding ".$preEncoding."\r\n"; + if(strtolower($preEncoding) != "utf-8"){ + $key = iconv($preEncoding, "UTF-8",$key); + } + $request->key = $key; + } + $method = $api["method"]; + if($method == "Method"){ + if(empty($args["Method"])){ + $request->method="GET"; + }else{ + $request->method=$args["Method"]; + } + }else{ + $request->method=$api["method"]; + } + if(KS3_API_USE_HTTPS) + $request->scheme="https://"; + else + $request->scheme="http://"; + $request->endpoint=$this->endpoint; + //add subresource + if(!empty($api["subResource"])){ + $request->subResource=$api["subResource"]; + } + //add query params + if(isset($api["queryParams"] )){ + foreach ($api["queryParams"] as $key => $value) { + $required = FALSE; + if(substr($value,0,1)==="!"){ + $required = TRUE; + $value=substr($value,1); + } + $index = explode("->",$value); + $curIndexArg = $args; + $add = TRUE; + $curkey = ""; + foreach ($index as $key1 => $value1) { + if(!isset($curIndexArg[$value1])&&$value1 !== "*"){ + $add = FALSE; + }else{ + $curkey = $value1; + //星号表示所有,按照暂时的业务,默认星号后面就没了 + if($curkey == "*"){ + foreach ($curIndexArg as $queryK => $queryV) { + if(!is_array($queryV)){ + $request->addQueryParams($queryK,$queryV); + } + } + $add = FALSE; + $required = FALSE; + break; + }else{ + $curIndexArg = $curIndexArg[$value1]; + } + } + } + if(!empty($curIndexArg)&&$add){ + $request->addQueryParams($curkey,$curIndexArg); + continue; + } + if($required) + throw new Ks3ClientException($method." param ".$value." is required"); + } + } + if(isset($api["body"])){ + if(isset($api["body"]["builder"])){ + $builderName = $api["body"]["builder"]; + $builder = new $builderName(); + $request->body = $builder->build($args); + }else if(isset($api["body"]["position"])){ + $position = $api["body"]["position"]; + $index = explode("->",$position); + $curIndexArg = $args; + $add = TRUE; + $curkey = ""; + foreach ($index as $key1 => $value1) { + if(!isset($curIndexArg[$value1])){ + $add = FALSE; + }else{ + $curIndexArg = $curIndexArg[$value1]; + $curkey = $value1; + } + } + if(!empty($curIndexArg)&&$add){ + $request->body=$curIndexArg; + } + } + } + + //add ext headers + //TODO + //sign request + $signer = NULL; + if(isset($api["signer"])){ + $signers = explode("->",$api["signer"]); + foreach ($signers as $key => $value) { + $signer = new $value(); + $log = $signer->sign($request,array("accessKey"=>$this->accessKey,"secretKey"=>$this->secretKey,"args"=>$args)); + if(!empty($log)){ + $holder->msg.=$log."\r\n"; + } + } + } + + if($signer===NULL||!($signer instanceof QueryAuthSigner)){ + $url = $request->toUrl($this->endpoint); + if($location!=NULL) + $url = $location; + $httpRequest = new RequestCore($url); + if(KS3_API_DEBUG_MODE===TRUE) + $httpRequest->debug_mode=TRUE; + $httpRequest->set_method($request->method); + foreach ($request->headers as $key => $value) { + $httpRequest->add_header($key,$value); + } + $httpRequest->request_body=$request->body; + + if(isset($args["writeCallBack"])){ + $httpRequest->register_streaming_write_callback($args["writeCallBack"]); + } + if(isset($args["readCallBack"])){ + $httpRequest->register_streaming_read_callback($args["readCallBack"]); + } + + $read_stream = $request->read_stream; + $read_length = $request->getHeader(Headers::$ContentLength); + $seek_position = $request->seek_position; + if(isset($read_stream)) + { + $httpRequest->set_read_stream($read_stream,$read_length); + $httpRequest->set_seek_position($seek_position); + $httpRequest->remove_header(Headers::$ContentLength); + } + $write_stream = $request->write_stream; + if(isset($write_stream)){ + $httpRequest->set_write_stream($write_stream); + } + + $holder->msg.="request url->".serialize($httpRequest->request_url)."\r\n"; + $holder->msg.="request headers->".serialize($httpRequest->request_headers)."\r\n"; + $holder->msg.="request body->".$httpRequest->request_body."\r\n"; + $holder->msg.="request read stream length->".$read_length."\r\n"; + $holder->msg.="request read stream seek position->".$seek_position."\r\n"; + $httpRequest->send_request(); + //print_r($httpRequest); + $body = $httpRequest->get_response_body (); + $data = new ResponseCore ( $httpRequest->get_response_header() , Utils::replaceNS2($body), $httpRequest->get_response_code () ); + + if($data->status == 307){ + $respHeaders = $httpRequest->get_response_header(); + $location = $respHeaders["location"]; + if(substr($location,0,4) == "http"){ + $holder->msg.="response code->".$httpRequest->get_response_code ()."\r\n"; + $holder->msg.="response headers->".serialize($httpRequest->get_response_header())."\r\n"; + $holder->msg.="response body->".$body."\r\n"; + $holder->msg.="retry request to ".$location."\r\n"; + //array($args)详见invoke开头 + return $this->invoke($method,array($args),$holder,$location); + } + } + $holder->msg.="response code->".$httpRequest->get_response_code ()."\r\n"; + $holder->msg.="response headers->".serialize($httpRequest->get_response_header())."\r\n"; + $holder->msg.="response body->".$body."\r\n"; + $handlers = explode("->",$api["handler"]); + foreach ($handlers as $key => $value) { + $handler = new $value(); + $data = $handler->handle($data); + } + return $data; + }else{ + $url = $request->toUrl($this->endpoint); + $holder->msg.=$url."\r\n"; + return $url; + } + } + //用于生产表单上传时的签名信息 + public function postObject($bucket ,$postFormData=array(),$unknowValueFormFiled=array(),$filename=NULL,$expire=18000){ + $policy = array(); + + $expireTime = Utils::iso8601(time()+$expire); + $policy["expiration"] = $expireTime; + $postFormData["bucket"]=$bucket; + $conditions = array(); + foreach ($postFormData as $key => $value) { + $condition = array(); + $condition[$key] = str_replace("\${filename}",$filename, $value); + array_push($conditions,$condition); + } + foreach ($unknowValueFormFiled as $key => $value) { + $condition = array(); + array_push($condition,"starts-with"); + array_push($condition,"\$".$value); + array_push($condition,""); + array_push($conditions,$condition); + } + $policy["conditions"] = $conditions; + $json = json_encode($policy); + $signature = base64_encode(hash_hmac('sha1', base64_encode($json), $this->secretKey, true)); + $result = array(); + $result["Policy"] = base64_encode($json); + $result["Signature"] = $signature; + $result["KSSAccessKeyId"] = $this->accessKey; + return $result; + } +} + +?> diff --git a/src/service/ksyun/bin/Ks3EncryptionClient.class.php b/src/service/ksyun/bin/Ks3EncryptionClient.class.php new file mode 100644 index 0000000..158b3a7 --- /dev/null +++ b/src/service/ksyun/bin/Ks3EncryptionClient.class.php @@ -0,0 +1,129 @@ +encryptionMaterials = $encryptionMaterials; + if(ENCRYPTPTION_MODE == "EO"){ + $this->encryptionHandler = new EncryptionEO($ks3client,$encryptionMaterials); + }elseif (ENCRYPTPTION_MODE == "AE") { + throw new Ks3ClientException("Authenticated encryption will be supported in the futher"); + } + else{ + throw new Ks3ClientException("unsupported encryption mode :".ENCRYPTPTION_MODE); + } + if(ENCRYPTPTION_STORAGE_MODE != "ObjectMetadata"&&ENCRYPTPTION_STORAGE_MODE!="InstructionFile"){ + throw new Ks3ClientException("unsupported encryption storage mode :".ENCRYPTPTION_STORAGE_MODE); + } + } + + public function putObjectByContent($args=array()){ + return $this->encryptionHandler->putObjectByContentSecurely($args); + } + public function putObjectByFile($args=array()){ + return $this->encryptionHandler->putObjectByFileSecurely($args); + } + public function getObject($args=array()){ + return $this->encryptionHandler->getObjectSecurely($args); + } + public function initMultipartUpload($args=array()){ + return $this->encryptionHandler->initMultipartUploadSecurely($args); + } + public function uploadPart($args=array()){ + return $this->encryptionHandler->uploadPartSecurely($args); + } + public function abortMultipartUpload($args=array()){ + return $this->encryptionHandler->abortMultipartUploadSecurely($args); + } + public function completeMultipartUpload($args=array()){ + return $this->encryptionHandler->completeMultipartUploadSecurely($args); + } + public function deleteObject($args=array()){ + $result = parent::deleteObject($args); + $args["Key"] = $args["Key"].EncryptionUtil::$INSTRUCTION_SUFFIX; + try { + parent::deleteObject($args); + } catch (Exception $e) { + //do nothing + } + return $result; + } + public function copyObject($args=array()){ + if(parent::objectExists(array( + "Bucket"=>$args["Bucket"], + "Key"=>$args["Key"] + ))){ + throw new Ks3ClientException("copy object faild,destination object exists"); + } + if(parent::objectExists(array( + "Bucket"=>$args["CopySource"]["Bucket"], + "Key"=>$args["CopySource"]["Key"].EncryptionUtil::$INSTRUCTION_SUFFIX + ))){ + parent::copyObject( + array( + "Bucket"=>$args["Bucket"], + "Key"=>$args["Key"].EncryptionUtil::$INSTRUCTION_SUFFIX, + "CopySource"=>array( + "Bucket"=>$args["CopySource"]["Bucket"], + "Key"=>$args["CopySource"]["Key"].EncryptionUtil::$INSTRUCTION_SUFFIX + ) + ) + ); + } + return parent::copyObject($args); + } +} + +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/config/Consts.php b/src/service/ksyun/bin/config/Consts.php new file mode 100644 index 0000000..603fc5e --- /dev/null +++ b/src/service/ksyun/bin/config/Consts.php @@ -0,0 +1,54 @@ +"Cache-Control", + "content-disposition"=>"Content-Disposition", + "content-encoding"=>"Content-Encoding", + "etag"=>"ETag", + "content-type"=>"Content-Type", + "expires"=>"Expires", + "last-modified"=>"Last-Modified", + "content-range"=>"Content-Range", + "content-length"=>"Content-Length", + "x-kss-server-side-encryption"=>"SSEAlgm", + "x-kss-server-side-encryption-kss-kms-key-id"=>"SSEKMSId", + "x-kss-server-side-encryption-customer-algorithm"=>"SSECAlgm", + "x-kss-server-side-encryption-customer-key-md5"=>"SSECKeyMD5" + ); + static $PartsElement = array("PartNumber","ETag"); + static $UploadHandler = array( + "etag"=>"ETag", + "taskid"=>"TaskID", + "x-kss-server-side-encryption"=>"SSEAlgm", + "x-kss-server-side-encryption-kss-kms-key-id"=>"SSEKMSId", + "x-kss-server-side-encryption-customer-algorithm"=>"SSECAlgm", + "x-kss-server-side-encryption-customer-key-md5"=>"SSECKeyMD5" + ); + static $SSEHandler = array( + "x-kss-server-side-encryption"=>"SSEAlgm", + "x-kss-server-side-encryption-kss-kms-key-id"=>"SSEKMSId", + "x-kss-server-side-encryption-customer-algorithm"=>"SSECAlgm", + "x-kss-server-side-encryption-customer-key-md5"=>"SSECKeyMD5" + ); + static $Permission_Read = "READ"; + static $Permission_Write = "WRITE"; + static $Grantee_Group_All = "http://acs.ksyun.com/groups/global/AllUsers"; + static $ResponseOverrides = array("response-expires","response-content-encoding","response-content-disposition", + "response-content-language","response-content-type","response-cache-control"); + static $CallBackMagics = array("bucket","key","etag","objectSize","mimeType","createTime"); + static $UserAgent = "ks3-kss-php-sdk"; + static $SSEDefaultAlgm = "AES256"; +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/core/API.php b/src/service/ksyun/bin/core/API.php new file mode 100644 index 0000000..e0d21e7 --- /dev/null +++ b/src/service/ksyun/bin/core/API.php @@ -0,0 +1,271 @@ +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->CallBackSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->getObjectHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"Method", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "queryParams"=>array("!Options->Expires","Options->*"), + "signer"=>"AllHeaderSigner->QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> diff --git a/src/service/ksyun/bin/core/Builders.php b/src/service/ksyun/bin/core/Builders.php new file mode 100644 index 0000000..166514f --- /dev/null +++ b/src/service/ksyun/bin/core/Builders.php @@ -0,0 +1,102 @@ +'); + $xml->addChild("LocationConstraint",$args["Location"]); + return $xml->asXml(); + } + } +} +class CORSBuilder{ + function build($args){ + if(isset($args["CORS"])){ + $cors = $args["CORS"]; + $xml = new SimpleXmlElement(''); + if(is_array($cors)){ + foreach ($cors as $key => $rule) { + $ruleXml = $xml->addChild("CORSRule"); + if(is_array($rule)){ + foreach ($rule as $key => $value) { + if(in_array($key,Consts::$CORSElements)){ + if(is_array($value)){ + foreach ($value as $ele) { + $ruleXml->addChild($key,$ele); + } + }else{ + $ruleXml->addChild($key,$value); + } + + } + } + } + } + } + return $xml->asXml(); + } + } +} +class BucketLoggingBuilder{ + function build($args){ + if(isset($args["BucketLogging"])){ + $logging = $args["BucketLogging"]; + $xml = new SimpleXmlElement(''); + if(is_array($logging)){ + + if(!isset($logging["Enable"])) + throw new Ks3ClientException("bucket logging must provide Enable argument"); + + if($logging["Enable"]){ + if(!isset($logging["TargetBucket"])) + throw new Ks3ClientException("bucket logging must provide TargetBucket argument"); + $loggingConfig = $xml->addChild("LoggingEnabled"); + foreach ($logging as $key => $value) { + if(in_array($key,Consts::$BucketLoggingElements)){ + $loggingConfig->addChild($key,$value); + } + } + } + } + return $xml->asXml(); + } + } +} +class DeleteObjectsBuilder{ + function build($args){ + if(isset($args["DeleteKeys"])){ + $keys = $args["DeleteKeys"]; + $xml = new SimpleXmlElement(''); + if(is_array($keys)){ + foreach ($keys as $key => $value) { + $object = $xml->addChild("Object"); + $object->addChild("Key",$value); + } + } + return $xml->asXml(); + } + } +} +class CompleteMultipartUploadBuilder{ + function build($args){ + if(isset($args["Parts"])){ + $parts = $args["Parts"]; + $xml = new SimpleXmlElement(''); + if(is_array($parts)){ + foreach ($parts as $part) { + $partXml = $xml->addChild("Part"); + foreach ($part as $key => $value) { + if(in_array($key,Consts::$PartsElement)){ + $partXml->addChild($key,$value); + } + } + } + } + return $xml->asXml(); + } + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/core/Handlers.php b/src/service/ksyun/bin/core/Handlers.php new file mode 100644 index 0000000..ce5e7dc --- /dev/null +++ b/src/service/ksyun/bin/core/Handlers.php @@ -0,0 +1,343 @@ +status; + if($code >= 400){ + $exception = new Ks3ServiceException(); + $exception->statusCode=$code; + if(!empty($response->body)){ + $xml = new SimpleXMLElement($response->body); + $exception ->requestId = $xml->RequestId->__toString(); + $exception->errorCode = $xml->Code->__toString(); + $exception->errorMessage=$xml->Message->__toString(); + $exception->resource=$xml->Resource->__toString(); + } + throw $exception; + }else{ + return $response; + } + } +} +class ListBucketsHandler implements Handler{ + + public function handle(ResponseCore $response){ + $result = array(); + $xml = new SimpleXMLElement($response->body); + foreach ($xml->Buckets->Bucket as $bucketXml) { + $bucket = array(); + foreach ($bucketXml->children() as $key => $value) { + $bucket[$key]=$value->__toString(); + } + array_push($result, $bucket); + } + return $result; + } +} +class ListObjectsHandler implements Handler{ + public function handle(ResponseCore $response){ + $result = array(); + $xml = new SimpleXMLElement($response->body); + $result["Name"]=$xml->Name->__toString(); + $result["Prefix"]=$xml->Prefix->__toString(); + $result["Marker"]=$xml->Marker->__toString(); + $result["Delimiter"]=$xml->Delimiter->__toString(); + $result["MaxKeys"]=$xml->MaxKeys->__toString(); + $result["IsTruncated"]=$xml->IsTruncated->__toString(); + $result["NextMarker"]=$xml->NextMarker->__toString(); + $contents = array(); + foreach ($xml->Contents as $contentXml) { + $content = array(); + foreach ($contentXml->children() as $key => $value) { + $owner = array(); + if($key === "Owner"){ + foreach ($value->children() as $ownerkey => $ownervalue) { + $owner[$ownerkey]=$ownervalue->__toString(); + } + $content["Owner"] = $owner; + }else{ + $content[$key]=$value->__toString(); + } + } + array_push($contents, $content); + } + $result["Contents"] = $contents; + + $commonprefix = array(); + foreach ($xml->CommonPrefixes as $commonprefixXml) { + foreach ($commonprefixXml->children() as $key => $value) { + array_push($commonprefix, $value->__toString()); + } + } + $result["CommonPrefixes"] = $commonprefix; + return $result; + } +} +class GetBucketCORSHandler implements Handler{ + public function handle(ResponseCore $response){ + $xml = new SimpleXMLElement($response->body); + $cors = array(); + foreach ($xml->CORSRule as $rule) { + $acors = array(); + foreach ($rule as $key => $value) { + if($key === "MaxAgeSeconds") + { + $acors[$key] = $value->__toString(); + }else{ + if(!isset($acors[$key])){ + $acors[$key] = array(); + } + array_push($acors[$key],$value->__toString()); + } + } + array_push($cors,$acors); + } + return $cors; + } +} +class GetBucketLocationHandler implements Handler{ + public function handle(ResponseCore $response){ + $xml = new SimpleXMLElement($response->body); + $location = $xml->__toString(); + + return $location; + } +} +class GetBucketLoggingHandler implements Handler{ + public function handle(ResponseCore $response){ + $logging = array(); + $xml = new SimpleXMLElement($response->body); + $loggingXml = $xml->LoggingEnabled; + if($loggingXml&&$loggingXml!==NULL) + { + foreach ($loggingXml->children() as $key => $value) { + $logging["Enable"] = TRUE; + $logging[$key] = $value->__toString(); + } + }else{ + $logging["Enable"] = FALSE; + } + return $logging; + } +} +class ObjectMetaHandler implements Handler{ + public function handle(ResponseCore $response){ + $ObjectMeta = array(); + $UserMeta = array(); + foreach ($response->header as $key => $value) { + if (substr(strtolower($key), 0, 10) === Consts::$UserMetaPrefix){ + $UserMeta[$key]=$value; + }else if(isset(Consts::$ResponseObjectMeta[strtolower($key)])){ + $ObjectMeta[Consts::$ResponseObjectMeta[strtolower($key)]]=$value; + } + } + $Meta = array( + "ObjectMeta"=>$ObjectMeta, + "UserMeta"=>$UserMeta + ); + return $Meta; + } +} +class getObjectHandler implements Handler{ + public function handle(ResponseCore $response){ + $ObjectMeta = array(); + $UserMeta = array(); + foreach ($response->header as $key => $value) { + if (substr(strtolower($key), 0, 10) === Consts::$UserMetaPrefix){ + $UserMeta[$key]=$value; + }else if(isset(Consts::$ResponseObjectMeta[strtolower($key)])){ + $ObjectMeta[Consts::$ResponseObjectMeta[strtolower($key)]]=$value; + } + } + $Meta = array( + "ObjectMeta"=>$ObjectMeta, + "UserMeta"=>$UserMeta + ); + $ks3Object = array( + "Content"=>$response->body, + "Meta"=>$Meta + ); + return $ks3Object; + } +} +class CopyHandler implements Handler{ + public function handle(ResponseCore $response){ + $headers = array(); + + foreach ($response->header as $key => $value) { + if(isset(Consts::$SSEHandler[strtolower($key)])&&!empty($value)){ + $headers[Consts::$SSEHandler[strtolower($key)]]=$value; + } + } + + return $headers; + } +} +class InitMultipartUploadHandler implements Handler{ + public function handle(ResponseCore $response){ + $upload = array(); + $xml = new SimpleXMLElement($response->body); + foreach ($xml->children() as $key => $value) { + $upload[$key] = $value->__toString(); + } + + foreach ($response->header as $key => $value) { + if(isset(Consts::$SSEHandler[strtolower($key)])&&!empty($value)){ + $upload[Consts::$SSEHandler[strtolower($key)]]=$value; + } + } + + return $upload; + } +} +class ListPartsHandler implements Handler{ + public function handle(ResponseCore $response){ + $listParts = array(); + $xml = new SimpleXMLElement($response->body); + + $listParts["Bucket"]=$xml->Bucket->__toString(); + $listParts["Key"]=$xml->Key->__toString(); + $listParts["UploadId"]=$xml->UploadId->__toString(); + $listParts["StorageClass"]=$xml->StorageClass->__toString(); + $listParts["PartNumberMarker"]=$xml->PartNumberMarker->__toString(); + $listParts["NextPartNumberMarker"]=$xml->NextPartNumberMarker->__toString(); + $listParts["MaxParts"]=$xml->MaxParts->__toString(); + $listParts["IsTruncated"]=$xml->IsTruncated->__toString(); + + $initer = array(); + $owner = array(); + + foreach ($xml->Initiator->children() as $key => $value) { + $initer[$key] = $value->__toString(); + } + foreach ($xml->Owner->children() as $key => $value) { + $owner[$key] = $value->__toString(); + } + $listParts["Owner"] = $owner; + $listParts["Initiator"]=$initer; + + $parts = array(); + foreach ($xml->Part as $partxml) { + $part = array(); + foreach ($partxml->children() as $key => $value) { + $part[$key] = $value->__toString(); + } + array_push($parts,$part); + } + $listParts["Parts"] = $parts; + return $listParts; + } +} +class UploadHandler implements Handler{ + public function handle(ResponseCore $response){ + $Headers = array(); + foreach ($response->header as $key => $value) { + if(isset(Consts::$UploadHandler[strtolower($key)])&&!empty($value)){ + $Headers[Consts::$UploadHandler[strtolower($key)]]=$value; + } + } + return $Headers; + } +} +class GetAclHandler implements Handler{ + public function handle(ResponseCore $response){ + $hasread = FALSE; + $haswrite = FALSE; + $xml = new SimpleXMLElement($response->body); + $acl = $xml->AccessControlList; + foreach ($acl->children() as $grant) { + $permission = $grant->Permission->__toString(); + $hasURI = FALSE; + $grantee = $grant->Grantee; + foreach ($grantee->children() as $key => $value) { + if($key === "URI"&&$value->__toString() === Consts::$Grantee_Group_All){ + $hasURI = TRUE; + } + } + if($hasURI){ + if($permission===Consts::$Permission_Read){ + $hasread = TRUE; + }elseif($permission===Consts::$Permission_Write){ + $haswrite = TRUE; + } + } + } + if($hasread&&$haswrite){ + return "public-read-write"; + }else{ + if($hasread) + return "public-read"; + else + return "private"; + } + } +} +class ListMutipartUploadsHandler implements Handler{ + public function handle(ResponseCore $response){ + $mutiUploads = array(); + $xml = new SimpleXMLElement($response->body); + + $mutiUploads["Bucket"]=$xml->Bucket->__toString(); + $mutiUploads["KeyMarker"]=$xml->KeyMarker->__toString(); + $mutiUploads["UploadIdMarker"]=$xml->UploadIdMarker->__toString(); + $mutiUploads["NextKeyMarker"]=$xml->NextKeyMarker->__toString(); + $mutiUploads["NextUploadIdMarker"]=$xml->NextUploadIdMarker->__toString(); + $mutiUploads["MaxUploads"]=$xml->MaxUploads->__toString(); + $mutiUploads["IsTruncated"]=$xml->IsTruncated->__toString(); + + + $uploads = array(); + foreach ($xml->Upload as $uploadxml) { + $upload = array(); + foreach ($uploadxml->children() as $key => $value) { + if($key === "Initiator"){ + $initer = array(); + foreach ($value->children() as $key1 => $value1) { + $initer[$key1] = $value1->__toString(); + } + $upload["Initiator"] = $initer; + }elseif($key === "Owner"){ + $owner = array(); + foreach ($value->children() as $key1 => $value1) { + $owner[$key1] = $value1->__toString(); + } + $upload["Owner"] = $owner; + }else{ + $upload[$key] = $value->__toString(); + } + } + array_push($uploads,$upload); + } + $mutiUploads["Uploads"] = $uploads; + return $mutiUploads; + } +} +class AdpHandler implements Handler{ + public function handle(ResponseCore $response){ + return $response->body; + } +} +class BooleanHandler implements Handler{ + public function handle(ResponseCore $response){ + if($response->isOk()){ + return TRUE; + }else{ + return FALSE; + } + } +} +class ExistsHandler implements Handler{ + public function handle(ResponseCore $response){ + $status = $response->status; + if($status === 404){ + return FALSE; + }else{ + return TRUE; + } + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/core/Headers.php b/src/service/ksyun/bin/core/Headers.php new file mode 100644 index 0000000..1ff71d2 --- /dev/null +++ b/src/service/ksyun/bin/core/Headers.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/src/service/ksyun/bin/core/Ks3Request.class.php b/src/service/ksyun/bin/core/Ks3Request.class.php new file mode 100644 index 0000000..eac52df --- /dev/null +++ b/src/service/ksyun/bin/core/Ks3Request.class.php @@ -0,0 +1,84 @@ +$property_name=$value; + } + public function __get($property_name){ + if(isset($this->$property_name)) + { + return($this->$property_name); + }else + { + return(NULL); + } + } + public function getHeader($key){ + if(isset($this->headers[$key])){ + return $this->headers[$key]; + }else{ + return(NULL); + } + } + public function addHeader($key,$value){ + $this->headers[$key] = $value; + } + + public function getQueryParams($key){ + if(isset($this->queryParams[$key])){ + return $this->queryParams[$key]; + }else{ + return(NULL); + } + } + public function addQueryParams($key,$value){ + $this->queryParams[$key] = $value; + } + public function toUrl($endpoint){ + $url = ""; + $bucket = $this->bucket; + $key = $this->key; + $subResource = $this->subResource; + if(!empty($bucket)){ + if(KS3_API_VHOST){ + $url.=$bucket.".".$endpoint; + }else{ + $url.=$endpoint."/".$bucket; + } + }else{ + $url.=$endpoint; + } + if(!empty($key)){ + $url.="/".Utils::encodeUrl($key); + } + $url = str_replace("//","/%2F", $url); + $queryString = ""; + if(!empty($subResource)){ + $queryString.="&".$subResource; + } + foreach ($this->queryParams as $key => $value) { + $queryString.="&".$key."=".rawurlencode($value); + } + $queryString = substr($queryString, 1); + if(!empty($queryString)){ + $url.="?".$queryString; + } + $url = $this->scheme.$url; + return $url; + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/core/Logger.php b/src/service/ksyun/bin/core/Logger.php new file mode 100644 index 0000000..4c27fa1 --- /dev/null +++ b/src/service/ksyun/bin/core/Logger.php @@ -0,0 +1,46 @@ +log("INFO",$msg); + } + function error($msg){ + $this->log("ERROR",$msg); + } + function warn($msg){ + $this->log("WARN",$msg); + } + function debug($msg){ + $this->log("DEBUG",$msg); + } + private function log($level,$msg){ + $date = gmdate('D, d M Y H:i:s \G\M\T'); + $log = $date." ".$level."\r\n".$msg."\r\n"; + if(defined('KS3_API_LOG_PATH') ){ + $log_path = KS3_API_LOG_PATH; + if(empty($log_path)){ + $log_path = KS3_API_PATH.DIRECTORY_SEPARATOR.'log'.DIRECTORY_SEPARATOR; + } + }else{ + $log_path = KS3_API_PATH.DIRECTORY_SEPARATOR.'log'.DIRECTORY_SEPARATOR; + } + + //检测日志目录是否存在 + if(!file_exists($log_path)){ + mkdir($log_path); + } + + $log_name = $log_path.'ks3_php_sdk_'.date('Y-m-d').'.log'; + + if(KS3_API_DISPLAY_LOG){ + echo $log; + } + + if(KS3_API_LOG){ + if(!error_log($log,3,$log_name)){ + throw new Ks3ClientException("write to log file error"); + } + } + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/core/MessageHolder.php b/src/service/ksyun/bin/core/MessageHolder.php new file mode 100644 index 0000000..200253e --- /dev/null +++ b/src/service/ksyun/bin/core/MessageHolder.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/src/service/ksyun/bin/core/Signers.php b/src/service/ksyun/bin/core/Signers.php new file mode 100644 index 0000000..8024aeb --- /dev/null +++ b/src/service/ksyun/bin/core/Signers.php @@ -0,0 +1,541 @@ +addHeader(Headers::$UserAgent,Consts::$UserAgent); + } +} +class DefaultContentTypeSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $contentType = $request->getHeader(Headers::$ContentType); + if(empty($contentType)){ + $request->addHeader(Headers::$ContentType,"application/xml"); + } + } +} +class StreamContentTypeSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $contentType = $request->getHeader(Headers::$ContentType); + if(empty($contentType)){ + $request->addHeader(Headers::$ContentType,"application/ocet-stream"); + } + } +} +class SuffixContentTypeSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $key = $request->key; + $objArr = explode('/', $key); + $basename = array_pop($objArr); + $extension = explode ( '.', $basename ); + $extension = array_pop ( $extension ); + $content_type = Utils::get_mimetype(strtolower($extension)); + $request->addHeader(Headers::$ContentType,$content_type); + } +} +class HeaderAuthSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $log = "stringToSing->\r\n"; + $date = gmdate('D, d M Y H:i:s \G\M\T'); + $request->addHeader(Headers::$Date, $date); + + $ak = $args["accessKey"]; + $sk = $args["secretKey"]; + if(empty($ak)){ + throw new Ks3ClientException("you should provide accessKey"); + } + if(empty($sk)){ + throw new Ks3ClientException("you should provide secretKey"); + } + $authration = "KSS "; + $signList = array( + $request->method, + $request->getHeader(Headers::$ContentMd5), + $request->getHeader(Headers::$ContentType), + $date + ); + $headers = AuthUtils::canonicalizedKssHeaders($request); + $resource = AuthUtils::canonicalizedResource($request); + if(!empty($headers)){ + array_push($signList,$headers); + } + array_push($signList,$resource); + $stringToSign = join("\n",$signList); + $log.= $stringToSign; + $signature = base64_encode(hash_hmac('sha1', $stringToSign, $sk, true)); + + $authration.=$ak.":".$signature; + $request->addHeader(Headers::$Authorization, $authration); + return $log; + } +} +class QueryAuthSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $log = "stringToSing->\r\n"; + $ak = $args["accessKey"]; + $sk = $args["secretKey"]; + $expires = $args["args"]["Options"]["Expires"]; + $expiresSencond = time()+$expires; + + $resource = AuthUtils::canonicalizedResource($request); + $signList = array( + $request->method, + $request->getHeader(Headers::$ContentMd5), + $request->getHeader(Headers::$ContentType), + $expiresSencond + ); + $headers = AuthUtils::canonicalizedKssHeaders($request); + $resource = AuthUtils::canonicalizedResource($request); + if(!empty($headers)){ + array_push($signList,$headers); + } + array_push($signList,$resource); + + $stringToSign = join("\n",$signList); + $log.= $stringToSign; + $signature = base64_encode(hash_hmac('sha1', $stringToSign, $sk, true)); + $request->addQueryParams("KSSAccessKeyId",$ak); + $request->addQueryParams("Signature",$signature); + $request->addQueryParams("Expires",$expiresSencond); + return $log; + } +} +class ACLSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["ACL"])){ + $acl = $args["ACL"]; + if(!in_array($acl, Consts::$Acl)){ + throw new Ks3ClientException("unsupport acl :".$acl); + }else{ + $request->addHeader(Headers::$Acl,$acl); + } + } + if(isset($args["ACP"])){ + + } + } +} +class ContentMD5Signer implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + $contentmd5 = ""; + if(isset($args["ObjectMeta"][Headers::$ContentMd5])){ + $contentmd5 = $args["ObjectMeta"][Headers::$ContentMd5]; + } + if(empty($contentmd5)){ + $body = $request->body; + if(!empty($body)){ + $length = $request->getHeader(Headers::$ContentLength); + if(empty($length)){ + if(isset($args["ObjectMeta"][Headers::$ContentLength])) + $length = $args["ObjectMeta"][Headers::$ContentLength]; + } + if(!empty($length)){ + $body = substr($body,0,$length); + } + $contentmd5 = Utils::hex_to_base64(md5($body)); + } + } + if(!empty($contentmd5)) + $request->addHeader(Headers::$ContentMd5,$contentmd5); + } +} +class ContentLengthSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + $contentlength = ""; + if(isset($args["ObjectMeta"][Headers::$ContentLength])){ + $contentlength = $args["ObjectMeta"][Headers::$ContentLength]; + } + if(empty($contentlength)){ + $body = $request->body; + if(!empty($body)){ + $contentlength = strlen($body); + } + } + if(!empty($contentlength)) + $request->addHeader(Headers::$ContentLength,$contentlength); + } +} +class ObjectMetaSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["ObjectMeta"])){ + $ObjectMeta = $args["ObjectMeta"]; + if(is_array($ObjectMeta)){ + foreach ($ObjectMeta as $key => $value) { + if(in_array($key,Consts::$ObjectMeta)&&!empty($value)){ + $request->addHeader($key,$value); + } + } + } + } + } +} +class MultipartObjectMetaSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["ObjectMeta"])){ + $ObjectMeta = $args["ObjectMeta"]; + if(is_array($ObjectMeta)){ + foreach ($ObjectMeta as $key => $value) { + if(in_array($key,Consts::$MultipartObjectMeta)&&!empty($value)){ + $request->addHeader($key,$value); + } + } + } + } + } +} +class UserMetaSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["UserMeta"])){ + $UserMeta = $args["UserMeta"]; + if(is_array($UserMeta)){ + foreach ($UserMeta as $key => $value) { + if (substr(strtolower($key), 0, 10) === Consts::$UserMetaPrefix){ + $request->addHeader($key,$value); + } + } + } + } + } +} +class CopySourceSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["CopySource"])){ + $CopySource = $args["CopySource"]; + if(is_array($CopySource)){ + if(!isset($CopySource["Bucket"])) + throw new Ks3ClientException("you should provide copy source bucket"); + if(!isset($CopySource["Key"])) + throw new Ks3ClientException("you should provide copy source key"); + $bucket = $CopySource["Bucket"]; + $key = Utils::encodeUrl($CopySource["Key"]); + $request->addHeader(Headers::$CopySource,"/".$bucket."/".$key); + } + } + } +} +class StreamUploadSigner implements Signer{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["Content"])&&is_array($args["Content"])&&isset($args["Content"]["content"])){ + $content = $args["Content"]["content"]; + $seek_position = 0; + $resourceLength = 0; + $length = -1; + $isFile = FALSE; + + if (!is_resource($content)){ + $isFile = TRUE; + //如果之前用户已经转化为GBK则不转换 + if(Utils::chk_chinese($content)&&!Utils::check_char($content)){ + $content = iconv('utf-8','gbk',$content); + } + if(!file_exists($content)) + throw new Ks3ClientException("the specified file does not exist "); + $length = Utils::getFileSize($content); + $content = fopen($content,"r"); + }else{ + $stats = fstat($content); + if ($stats && $stats["size"] >= 0){ + $length = $stats["size"]; + } + } + //之所以取resourceLength是为了防止Content-Length大于实际数据的大小,导致一直等待。 + $resourceLength = $length; + //优先取用户设置seek_position,没有的话取ftell + if(isset($args["Content"]["seek_position"])&&$args["Content"]["seek_position"]>0){ + $seek_position = $args["Content"]["seek_position"]; + }else if(!$isFile){ + $seek_position = ftell($content); + if($seek_position<0) + $seek_position = 0; + fseek($content,0); + } + + $lengthInMeta = -1; + if(isset($args["ObjectMeta"]["Content-Length"])){ + $lengthInMeta = $args["ObjectMeta"]["Content-Length"]; + } + if($lengthInMeta > 0){ + $length = $lengthInMeta; + }else if($resourceLength > 0){ + //根据seek_position计算实际长度 + $length = $resourceLength - $seek_position; + } + if($length <= 0) + throw new Ks3ClientException("calculate content length failed,unexpected contetn length ".$length); + $request->read_stream = $content; + $request->addHeader(Headers::$ContentLength,$length); + $request->seek_position = $seek_position; + }else{ + throw new Ks3ClientException("please specifie upload content in args"); + } + } +} +class RangeSigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["Range"])){ + $Range = $args["Range"]; + if(is_array($Range)){ + $start = $Range["start"]; + $end = $Range["end"]; + $range = "bytes=".$start."-".$end; + $request->addHeader(Headers::$Range,$range); + }else + $request->addHeader(Headers::$Range,$Range); + } + } +} +class GetObjectSigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["WriteTo"])){ + $WriteTo = $args["WriteTo"]; + if(is_resource($WriteTo)){ + $request->write_stream = $WriteTo; + }else{ + //如果之前用户已经转化为GBK则不转换 + if(Utils::chk_chinese($WriteTo)&&!Utils::check_char($WriteTo)){ + $WriteTo = iconv('utf-8','gbk',$WriteTo); + } + $request->write_stream = fopen($WriteTo,"w"); + } + } + } +} +class AdpSigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["Adp"])){ + $AdpConf = $args["Adp"]; + if(is_array($AdpConf)){ + if(isset($AdpConf["NotifyURL"])){ + $NotifyURL = $AdpConf["NotifyURL"]; + }else{ + throw new Ks3ClientException("adp should provide NotifyURL"); + } + if(isset($AdpConf["Adps"])){ + $Adps = $AdpConf["Adps"]; + }else{ + throw new Ks3ClientException("adp should provide Adps"); + } + $AdpString = ""; + foreach ($Adps as $Adp) { + if(is_array($Adp)){ + if(!isset($Adp["Command"])){ + throw new Ks3ClientException("command is needed in adp"); + } + $command = $Adp["Command"]; + $bucket = NULL; + $key = NULL; + if(isset($Adp["Bucket"])){ + $bucket = $Adp["Bucket"]; + } + if(isset($Adp["Key"])){ + $key = $Adp["Key"]; + } + $AdpString.=$command; + if(!(empty($bucket)&&empty($key))){ + if(empty($bucket)){ + $AdpString.="|tag=saveas&object=".base64_encode($key); + }elseif (empty($key)) { + $AdpString.="|tag=saveas&bucket=".$bucket; + }else{ + $AdpString.="|tag=saveas&bucket=".$bucket."&"."object=".base64_encode($key); + } + } + $AdpString.=";"; + } + } + if(!empty($AdpString)&&!empty($NotifyURL)){ + $request->addHeader(Headers::$AsynchronousProcessingList,$AdpString); + $request->addHeader(Headers::$NotifyURL,$NotifyURL); + } + } + } + } +} +class CallBackSigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["CallBack"])&&is_array($args["CallBack"])){ + $CallBackConf = $args["CallBack"]; + $url = NULL; + $body = NULL; + if(isset($CallBackConf["Url"])){ + $url = $CallBackConf["Url"]; + } + if(empty($url)) + throw new Ks3ClientException("Url is needed in CallBack"); + if(isset($CallBackConf["BodyMagicVariables"])){ + if(is_array($CallBackConf["BodyMagicVariables"])){ + $magics = $CallBackConf["BodyMagicVariables"]; + foreach ($magics as $key => $value) { + if(in_array($value,Consts::$CallBackMagics)) + $body.=$key."=\${".$value."}&"; + } + } + } + if(isset($CallBackConf["BodyVariables"])){ + if(is_array($CallBackConf["BodyVariables"])){ + $variables = $CallBackConf["BodyVariables"]; + foreach ($variables as $key => $value) { + $body.=$key."=\${kss-".$key."}&"; + $request->addHeader("kss-".$key,$value); + } + } + } + if(!empty($body)){ + $body=substr($body,0,strlen($body)-1); + $request->addHeader(Headers::$XKssCallbackBody,$body); + } + $request->addHeader(Headers::$XKssCallbackUrl,$url); + } + } +} +class SSESigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["SSE"])){ + if(isset($args["SSE"]["Algm"])) + $algm = $args["SSE"]["Algm"]; + if(isset($args["SSE"]["KMSId"])) + $id = $args["SSE"]["KMSId"]; + if(!empty($algm)){ + $request->addHeader(Headers::$SSEAlgm,$algm); + if(!empty($id)) + $request->addHeader(Headers::$SSEKMSId,$id); + } + } + } +} +class SSECSigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["SSEC"])){ + if(isset($args["SSEC"]["Algm"])) + $algm = $args["SSEC"]["Algm"]; + if(isset($args["SSEC"]["Key"])) + $key = $args["SSEC"]["Key"]; + if(isset($args["SSEC"]["KeyBase64"])) + $keybase64 = $args["SSEC"]["KeyBase64"]; + if(isset($args["SSEC"]["KeyMD5"])) + $md5 = $args["SSEC"]["KeyMD5"]; + if(!empty($key)||!empty($keybase64)){ + if(empty($key)) + $key = base64_decode($keybase64); + if(empty($algm)) + $algm = Consts::$SSEDefaultAlgm; + if(empty($md5)) + $md5 = Utils::hex_to_base64(md5($key)); + + $request->addHeader(Headers::$SSECAlgm,$algm); + $request->addHeader(Headers::$SSECKey,base64_encode($key)); + $request->addHeader(Headers::$SSECMD5,$md5); + } + } + } +} +class SSECSourceSigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + if(isset($args["SSECSource"])){ + if(isset($args["SSECSource"]["Algm"])) + $algm = $args["SSECSource"]["Algm"]; + if(isset($args["SSECSource"]["Key"])) + $key = $args["SSECSource"]["Key"]; + if(isset($args["SSECSource"]["KeyBase64"])) + $keybase64 = $args["SSECSource"]["KeyBase64"]; + if(isset($args["SSECSource"]["KeyMD5"])) + $md5 = $args["SSECSource"]["KeyMD5"]; + if(!empty($key)||!empty($keybase64)){ + if(empty($key)) + $key = base64_decode($keybase64); + if(empty($algm)) + $algm = Consts::$SSEDefaultAlgm; + if(empty($md5)) + $md5 = Utils::hex_to_base64(md5($key)); + + $request->addHeader(Headers::$SSECSourceAlgm,$algm); + $request->addHeader(Headers::$SSECSourceKey,base64_encode($key)); + $request->addHeader(Headers::$SSECSourceMD5,$md5); + } + } + } +} +class AllHeaderSigner{ + public function sign(Ks3Request $request,$args=array()){ + $args = $args["args"]; + $headers = isset($args["Headers"])?$args["Headers"]:""; + if(!empty($headers)&&is_array($headers)){ + foreach ($headers as $key => $value) { + $request->addHeader($key,$value); + } + } + } +} +class AuthUtils{ + public static function canonicalizedKssHeaders(Ks3Request $request){ + $header = ""; + $headers = $request->headers; + ksort($headers,SORT_STRING); + foreach ( $headers as $header_key => $header_value ) { + if (substr(strtolower($header_key), 0, 6) === Consts::$KS3HeaderPrefix){ + $header .= "\n".strtolower($header_key) . ':' .$header_value; + } + } + $header = substr($header, 1); + return $header; + } + public static function canonicalizedResource(Ks3Request $request){ + $resource = "/"; + $bucket = $request->bucket; + $key = $request->key; + $subResource = $request->subResource; + if(!empty($bucket)){ + $resource.=$request->bucket."/"; + } + if(!empty($key)){ + $resource.=Utils::encodeUrl($request->key); + } + + $encodeParams = ""; + $querys = $request->queryParams; + if(!empty($subResource)){ + $querys[$subResource] = NULL; + } + ksort($querys,SORT_STRING); + foreach ($querys as $key => $value) { + if(in_array($key,Consts::$SubResource)||in_array($key,Consts::$QueryParam)){ + if(empty($value)){ + $encodeParams.="&".$key; + }else{ + $encodeParams.="&".$key."=".$value; + } + } + } + $encodeParams = substr($encodeParams,1); + + $resource = str_replace("//","/%2F", $resource); + + if(!empty($encodeParams)){ + $resource.="?".$encodeParams; + } + return $resource; + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/core/Utils.class.php b/src/service/ksyun/bin/core/Utils.class.php new file mode 100644 index 0000000..9fcbc4b --- /dev/null +++ b/src/service/ksyun/bin/core/Utils.class.php @@ -0,0 +1,235 @@ + 'application/vnd.android.package-archive', + '3gp' => 'video/3gpp', 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', 'asc' => 'text/plain', + 'atom' => 'application/atom+xml', 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', 'bcpio' => 'application/x-bcpio', + 'bin' => 'application/octet-stream', 'bmp' => 'image/bmp', + 'cdf' => 'application/x-netcdf', 'cgm' => 'image/cgm', + 'class' => 'application/octet-stream', + 'cpio' => 'application/x-cpio', + 'cpt' => 'application/mac-compactpro', + 'csh' => 'application/x-csh', 'css' => 'text/css', + 'dcr' => 'application/x-director', 'dif' => 'video/x-dv', + 'dir' => 'application/x-director', 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/octet-stream', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'doc' => 'application/msword', 'dtd' => 'application/xml-dtd', + 'dv' => 'video/x-dv', 'dvi' => 'application/x-dvi', + 'dxr' => 'application/x-director', + 'eps' => 'application/postscript', 'etx' => 'text/x-setext', + 'exe' => 'application/octet-stream', + 'ez' => 'application/andrew-inset', 'flv' => 'video/x-flv', + 'gif' => 'image/gif', 'gram' => 'application/srgs', + 'grxml' => 'application/srgs+xml', + 'gtar' => 'application/x-gtar', 'gz' => 'application/x-gzip', + 'hdf' => 'application/x-hdf', + 'hqx' => 'application/mac-binhex40', 'htm' => 'text/html', + 'html' => 'text/html', 'ice' => 'x-conference/x-cooltalk', + 'ico' => 'image/x-icon', 'ics' => 'text/calendar', + 'ief' => 'image/ief', 'ifb' => 'text/calendar', + 'iges' => 'model/iges', 'igs' => 'model/iges', + 'jnlp' => 'application/x-java-jnlp-file', 'jp2' => 'image/jp2', + 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', 'js' => 'application/x-javascript', + 'kar' => 'audio/midi', 'latex' => 'application/x-latex', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'm3u' => 'audio/x-mpegurl', 'm4a' => 'audio/mp4a-latm', + 'm4p' => 'audio/mp4a-latm', 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/x-m4v', 'mac' => 'image/x-macpaint', + 'man' => 'application/x-troff-man', + 'mathml' => 'application/mathml+xml', + 'me' => 'application/x-troff-me', 'mesh' => 'model/mesh', + 'mid' => 'audio/midi', 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', + 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', 'mpga' => 'audio/mpeg', + 'ms' => 'application/x-troff-ms', 'msh' => 'model/mesh', + 'mxu' => 'video/vnd.mpegurl', 'nc' => 'application/x-netcdf', + 'oda' => 'application/oda', 'ogg' => 'application/ogg', + 'ogv' => 'video/ogv', 'pbm' => 'image/x-portable-bitmap', + 'pct' => 'image/pict', 'pdb' => 'chemical/x-pdb', + 'pdf' => 'application/pdf', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', 'pic' => 'image/pict', + 'pict' => 'image/pict', 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'pnt' => 'image/x-macpaint', 'pntg' => 'image/x-macpaint', + 'ppm' => 'image/x-portable-pixmap', + 'ppt' => 'application/vnd.ms-powerpoint', + 'ps' => 'application/postscript', 'qt' => 'video/quicktime', + 'qti' => 'image/x-quicktime', 'qtif' => 'image/x-quicktime', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', 'ras' => 'image/x-cmu-raster', + 'rdf' => 'application/rdf+xml', 'rgb' => 'image/x-rgb', + 'rm' => 'application/vnd.rn-realmedia', + 'roff' => 'application/x-troff', 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', 'silo' => 'model/mesh', + 'sit' => 'application/x-stuffit', + 'skd' => 'application/x-koan', 'skm' => 'application/x-koan', + 'skp' => 'application/x-koan', 'skt' => 'application/x-koan', + 'smi' => 'application/smil', 'smil' => 'application/smil', + 'snd' => 'audio/basic', 'so' => 'application/octet-stream', + 'spl' => 'application/x-futuresplash', + 'src' => 'application/x-wais-source', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', 'svg' => 'image/svg+xml', + 'swf' => 'application/x-shockwave-flash', + 't' => 'application/x-troff', 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', 'tr' => 'application/x-troff', + 'tsv' => 'text/tab-separated-values', 'txt' => 'text/plain', + 'ustar' => 'application/x-ustar', + 'vcd' => 'application/x-cdlink', 'vrml' => 'model/vrml', + 'vxml' => 'application/voicexml+xml', 'wav' => 'audio/x-wav', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbxml' => 'application/vnd.wap.wbxml', 'webm' => 'video/webm', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', 'wrl' => 'model/vrml', + 'xbm' => 'image/x-xbitmap', 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xls' => 'application/vnd.ms-excel', + 'xml' => 'application/xml', 'xpm' => 'image/x-xpixmap', + 'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xwd' => 'image/x-xwindowdump', 'xyz' => 'chemical/x-xyz', + 'zip' => 'application/zip' ); + + public static function get_mimetype($ext) { + return (isset ( self::$mime_types [$ext] ) ? self::$mime_types [$ext] : 'application/octet-stream'); + } + /** + * 检测是否含有中文 + * @param string $subject + * @return boolean + */ + public static function chk_chinese($str){ + return preg_match('/[\x80-\xff]./', $str); + } + + /** + * 检测是否GB2312编码 + * @param string $str + * @return boolean false UTF-8编码 TRUE GB2312编码 + */ + public static function is_gb2312($str) { + for($i=0; $i 127) { + if( ($v >= 228) && ($v <= 233) ){ + if( ($i+2) >= (strlen($str) - 1)) return true; // not enough characters + $v1 = ord( $str[$i+1] ); + $v2 = ord( $str[$i+2] ); + if( ($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191) ) + return false; //UTF-8编码 + else + return true; //GB编码 + } + } + } + } + + + /** + * 检测是否GBK编码 + * @param string $str + * @param boolean $gbk + * @return boolean + */ + public static function check_char($str, $gbk = true){ + for($i=0; $i 127){ + if( ($v >= 228) && ($v <= 233) ){ + if(($i+2)>= (strlen($str)-1)) return $gbk?true:FALSE; // not enough characters + $v1 = ord( $str[$i+1] ); $v2 = ord( $str[$i+2] ); + if($gbk){ + return (($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191))?FALSE:TRUE;//GBK + }else{ + return (($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191))?TRUE:FALSE; + } + } + } + } + return $gbk?TRUE:FALSE; + } + public static function iso8601($time=false) { + if ($time === false) $time = time(); + $date = date('Y-m-d\TH:i:s\.Z', $time); + return (substr($date, 0, strlen($date)-2).'Z'); + } + public static function getFileSize($path){ + $success = FALSE; + $isresource = FALSE; + if(!is_resource($path)){ + $isresource = FALSE; + $resource = fopen($path,"r"); + }else{ + $isresource = TRUE; + $resource = $path; + } + $stat = fstat($resource); + $size = $stat["size"]; + if($size<0){ + $success = FALSE; + }else{ + $success = TRUE; + } + if($success) + return $size; + else if($isresource) + throw new Ks3ClientException("please use file path instead resource"); + if(!((strtoupper(substr(PHP_OS,0,3))=="WIN"))){//如果不是windows系统,尝试使用stat命令 + $size=trim(`stat -c%s $path`); + }else{//如果是windows系统,尝试cmd命令 + if(!class_exists("COM")){ + throw new Ks3ClientException("please add 'extension=php_com_dotnet.dll' and set 'com.allow_dcom = true' in php.ini and restart"); + } + $fs = new COM("Scripting.FileSystemObject"); + $size=$fs->GetFile($path)->Size; + } + return $size; + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/encryption/EncryptionCallBack.php b/src/service/ksyun/bin/encryption/EncryptionCallBack.php new file mode 100644 index 0000000..a621a71 --- /dev/null +++ b/src/service/ksyun/bin/encryption/EncryptionCallBack.php @@ -0,0 +1,227 @@ +$property_name=$value; + } + public function __get($property_name){ + if(isset($this->$property_name)) + { + return($this->$property_name); + }else + { + return(NULL); + } + } + //最后的数据大小肯定是blocksize的倍数,所以最后buffer中不会有未解密的内容。否则可以认为该文件是错误的 + public function streaming_write_callback($curl_handle,$data,$write_stream){ + $data = $this->buffer.$data; + + $length = strlen($data); + //不能把上次的没读完的长度算在这次里,应该算在上次 + $written_total = 0-strlen($this->buffer); + $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC); + if($length<$blocksize) + $this->buffer = $data; + else{ + //如果期望的范围之后还有数据,则认为数据已经接收完毕。不做任何处理 + if($this->expectedRange["end"] < $this->expectedRange["start"]){ + return $written_total+strlen($data); + } + $this->buffer = substr($data,$length - $length%$blocksize); + $data = substr($data,0,$length - $length%$blocksize); + + $ivoffset = 0; + //range get时,如果不是从刚开始,则应该取加密后数据的前16个字节作为之后解密的iv + if($this->firstWrite){ + $this->firstWrite = FALSE; + if(!$this->isBegin()){ + $this->iv = substr($data,0,$blocksize); + $data = substr($data,$blocksize); + $ivoffset = $blocksize; + } + //初始化当前位置 + if(isset($this->adjustedRange)) + $this->currentIndex = $ivoffset+$this->adjustedRange["start"]; + else + $this->currentIndex = $ivoffset; + } + $written_total+=$ivoffset; + if(strlen($data) == 0){ + $decoded = ""; + return $written_total; + }else{ + $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); + mcrypt_generic_init($td,$this->cek,$this->iv); + $decoded = mdecrypt_generic($td,$data); + mcrypt_generic_deinit($td); + mcrypt_module_close($td); + } + + $this->iv = substr($data,strlen($data)-$blocksize); + //判断是否需要删除最后填充的字符,以及获取填充的字符 + $needRemovePad = FALSE; + $pad = NULL; + + if($this->currentIndex+strlen($decoded) >=$this->contentLength){ + $needRemovePad = TRUE; + $pad = ord(substr($decoded,strlen($decoded)-1,1)); + if($pad<=0||$pad>$blocksize) + { + //invalid pad + $needRemovePad = FALSE; + } + } + + //将解密后的数据截取到期望的长度 + $startOffset = 0; + $endOffset = 0; + if(isset($this->expectedRange)){ + $trueEnd = $expectedEnd = $this->expectedRange["end"]; + + if($this->currentIndex+strlen($decoded)>$expectedEnd){ + $preLength = strlen($decoded); + $decoded = substr($decoded, 0,$expectedEnd-$this->currentIndex+1); + $endOffset = $preLength-strlen($decoded); + }else{ + //因为range是开始结束都计算的,range=1-2。currentIndex=1,长度是2,end=currentIndex+2-1 + $trueEnd = $this->currentIndex+strlen($decoded)-1; + } + $expectedStart = $this->expectedRange["start"]; + if($this->currentIndex<$expectedStart){ + $decoded = substr($decoded,$expectedStart - $this->currentIndex); + $startOffset = $expectedStart - $this->currentIndex; + } + //调整下次期望的开始 + $this->expectedRange["start"] = $trueEnd+1; + } + + $padOffset = 0; + //再次根据截取的长度判断是否需要删除最后填充的字符 + if($needRemovePad&&$endOffset > $pad){ + $needRemovePad = FALSE; + } + $actualWriteCount = 0; + if($needRemovePad){ + $padOffset = $pad-$endOffset; + $actualWriteCount = strlen($decoded)-$padOffset; + if($actualWriteCount <= 0)//负数的情况就是用户期望的range里全是填充的 + $decoded = ""; + else + $decoded = substr($decoded,0,strlen($decoded)-$padOffset); + } + $count = fwrite($write_stream, $decoded); + if($count == 0) + $count = $actualWriteCount; + $count += $padOffset; + $count += $startOffset; + $count += $endOffset; + $this->currentIndex += $count; + $written_total+=$count; + } + //否则curl框架会报错 + $written_total+=strlen($this->buffer); + return $written_total; + } + //是的话则使用初始化IV + private function isBegin(){ + $beginIndex = 0; + if(isset($this->adjustedRange["start"])) + $beginIndex = $this->adjustedRange["start"]; + if($beginIndex == 0) + return TRUE; + else + return FALSE; + } +} +//上传 +class AESCBCStreamReadCallBack{ + private $iv; + private $cek; + private $contentLength; + private $buffer; + private $hasread = 0; + private $mutipartUpload =FALSE; + private $isLastPart = FALSE; + public function __set($property_name, $value){ + $this->$property_name=$value; + } + public function __get($property_name){ + if(isset($this->$property_name)) + { + return($this->$property_name); + }else + { + return(NULL); + } + } + public function streaming_read_callback($curl_handle,$file_handle,$length,$read_stream,$seek_position){ + // Once we've sent as much as we're supposed to send... + if ($this->hasread >= $this->contentLength) + { + // Send EOF + return ''; + } + // If we're at the beginning of an upload and need to seek... + if ($this->hasread == 0 && $seek_position>0 && $seek_position !== ftell($read_stream)) + { + if (fseek($read_stream, $seek_position) !== 0) + { + throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.'); + } + } + + + $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_ECB); + $needRead = min($this->contentLength - $this->hasread,$length); + $read = fread($read_stream,$needRead); + $this->hasread += strlen($read); + $isLast = FALSE; + if($this->hasread >= $this->contentLength){ + $isLast = TRUE; + } + $data = $this->buffer.$read; + + $dataLength = strlen($data); + + if(!$isLast){ + $this->buffer = substr($data,$dataLength-$dataLength%$blocksize); + $data = substr($data, 0,$dataLength-$dataLength%$blocksize); + }else{ + //分块上传除最后一块外肯定是blocksize大小的倍数,所以不需要填充。 + if($this->mutipartUpload){ + if($this->isLastPart){ + $this->buffer = NULL; + $data = EncryptionUtil::PKCS5Padding($data,$blocksize); + }else{ + //donothing + } + }else{ + $this->buffer = NULL; + $data = EncryptionUtil::PKCS5Padding($data,$blocksize); + } + } + $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); + mcrypt_generic_init($td,$this->cek,$this->iv); + $encrypted = mcrypt_generic($td,$data); + mcrypt_generic_deinit($td); + //去除自动填充的16个字节//php的当恰好为16的倍数时竟然不填充? + //$encrypted = substr($encrypted,0,strlen($encrypted)-$blocksize); + //取最后一个block作为下一次的iv + $this->iv = substr($encrypted, strlen($encrypted)-$blocksize); + return $encrypted; + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/encryption/EncryptionHandlers.php b/src/service/ksyun/bin/encryption/EncryptionHandlers.php new file mode 100644 index 0000000..9226fde --- /dev/null +++ b/src/service/ksyun/bin/encryption/EncryptionHandlers.php @@ -0,0 +1,358 @@ +encryptionMaterials = $encryptionMaterials; + $this->ks3client = $ks3client; + } + public function putObjectByContentSecurely($args=array()){ + $sek = EncryptionUtil::genereateOnceUsedKey(); + $encryptedSek = EncryptionUtil::encodeCek($this->encryptionMaterials,$sek); + $content = $args["Content"]; + if(empty($content)) + throw new Ks3ClientException("please specifie Content in request args"); + $metaContentLength = EncryptionUtil::metaTextLength($args); + $plainTextLength = strlen($content); + if($metaContentLength > 0 && $metaContentLength < $plainTextLength){ + $plainTextLength = $metaContentLength; + } + if($plainTextLength > 0) + $args["UserMeta"]["x-kss-meta-x-kss-unencrypted-content-length"] = $plainTextLength; + else + throw new Ks3ClientException("unexpected content length ".$plainTextLength); + + $content = substr($content, 0,$plainTextLength); + + + $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); + $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td),MCRYPT_RAND); + mcrypt_generic_init($td,$sek,$iv); + //对content进行pkcs5填充 + $content = EncryptionUtil::PKCS5Padding($content,mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC)); + $encrypted = mcrypt_generic($td,$content); + mcrypt_generic_deinit($td); + + $args["ObjectMeta"]["Content-Length"] = strlen($encrypted); + $args["Content"] = $encrypted; + + $args = EncryptionUtil::updateContentMD5Header($args); + + //TODO + $matdesc = "{}"; + if(ENCRYPTPTION_STORAGE_MODE == "ObjectMetadata"){ + $args["UserMeta"]["x-kss-meta-x-kss-key"] = base64_encode($encryptedSek); + $args["UserMeta"]["x-kss-meta-x-kss-iv"] = base64_encode($iv); + $args["UserMeta"]["x-kss-meta-x-kss-matdesc"] = $matdesc; + } + + $result = $this->ks3client->putObjectByContent($args); + + if(ENCRYPTPTION_STORAGE_MODE == "InstructionFile"){ + $req = EncryptionUtil::createInstructionFile($args["Bucket"],$args["Key"], + base64_encode($encryptedSek),base64_encode($iv),$matdesc); + $this->ks3client->putObjectByContent($req); + } + + return $result; + } + public function putObjectByFileSecurely($args=array()){ + $sek = EncryptionUtil::genereateOnceUsedKey(); + $encryptedSek = EncryptionUtil::encodeCek($this->encryptionMaterials,$sek); + if(!isset($args["Content"])||!is_array($args["Content"]) + ||!isset($args["Content"]["content"]) + ||empty($args["Content"]["content"])) + throw new Ks3ClientException("please specifie file content in request args"); + $content = $args["Content"]; + $plainTextLength = EncryptionUtil::plainTextLength($args); + if($plainTextLength <= 0){ + throw new Ks3ClientException("get content length failed ,unexpected content length ".$plainTextLength); + } + $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); + $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td),MCRYPT_RAND); + + $args = EncryptionUtil::updateContentMD5Header($args); + $encryptedLength = EncryptionUtil::getPKCS5EncrypedLength($plainTextLength,mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC)); + + $args["ObjectMeta"]["Content-Length"] = $encryptedLength; + $args["UserMeta"]["x-kss-meta-x-kss-unencrypted-content-length"] = $plainTextLength; + + $readCallBack = new AESCBCStreamReadCallBack(); + $readCallBack->iv = $iv; + $readCallBack->cek = $sek; + $readCallBack->contentLength = $plainTextLength; + $args["readCallBack"] = $readCallBack; + + //TODO + $matdesc = "{}"; + if(ENCRYPTPTION_STORAGE_MODE == "ObjectMetadata"){ + $args["UserMeta"]["x-kss-meta-x-kss-key"] = base64_encode($encryptedSek); + $args["UserMeta"]["x-kss-meta-x-kss-iv"] = base64_encode($iv); + $args["UserMeta"]["x-kss-meta-x-kss-matdesc"] = $matdesc; + } + + $result = $this->ks3client->putObjectByFile($args); + + if(ENCRYPTPTION_STORAGE_MODE == "InstructionFile"){ + $req = EncryptionUtil::createInstructionFile($args["Bucket"],$args["Key"], + base64_encode($encryptedSek),base64_encode($iv),$matdesc); + $this->ks3client->putObjectByContent($req); + } + + return $result; + } + public function getObjectSecurely($args=array()){ + $meta = $this->ks3client->getObjectMeta($args); + if(isset($meta["UserMeta"]["x-kss-meta-x-kss-key"])&&isset($meta["UserMeta"]["x-kss-meta-x-kss-iv"])){ + $encryptedInMeta = TRUE; + }else{ + $encryptedInMeta = FALSE; + } + $encrypted = TRUE; + $encryptionInfo = array(); + if($encryptedInMeta){ + $encryptionInfo["iv"] = base64_decode($meta["UserMeta"]["x-kss-meta-x-kss-iv"]); + $matdesc =$meta["UserMeta"]["x-kss-meta-x-kss-matdesc"]; + $encryptionInfo["matdesc"] = $matdesc; + $cekEncrypted = base64_decode($meta["UserMeta"]["x-kss-meta-x-kss-key"]); + $encryptionInfo["cek"] = $cek = EncryptionUtil::decodeCek($this->encryptionMaterials,$cekEncrypted); + }else{ + if($this->ks3client->objectExists(array( + "Bucket"=>$args["Bucket"], + "Key"=>$args["Key"].EncryptionUtil::$INSTRUCTION_SUFFIX) + ) + ){ + $insKey = $args["Key"].EncryptionUtil::$INSTRUCTION_SUFFIX; + $getIns = array( + "Bucket"=>$args["Bucket"], + "Key"=>$insKey, + ); + $s3Object = $this->ks3client->getObject($getIns); + if(!EncryptionUtil::isInstructionFile($s3Object)) + throw new Ks3ClientException($insKey." is not an InstructionFile"); + + $content = $s3Object["Content"]; + $content = json_decode($content,TRUE); + $encryptionInfo["iv"] = base64_decode($content["x-kss-iv"]); + $matdesc =$content["x-kss-matdesc"]; + $encryptionInfo["matdesc"] = $matdesc; + $cekEncrypted = base64_decode($content["x-kss-key"]); + $encryptionInfo["cek"] = $cek = EncryptionUtil::decodeCek($this->encryptionMaterials,$cekEncrypted); + }else{ + $encrypted =FALSE; + } + } + //是否为下载到文件中 + $isWriteToFile=FALSE; + if($encrypted) + { + $iv = $encryptionInfo["iv"]; + $cek = $encryptionInfo["cek"]; + + if(empty($iv)) + throw new Ks3ClientException("can not find iv in UserMeta or InstructionFile"); + if(empty($cek)) + throw new Ks3ClientException("can not find cek in UserMeta or InstructionFile"); + + if(isset($args["Range"])){ + $range = $args["Range"]; + if(!is_array($range)){ + if(preg_match('/^bytes=[0-9]*-[0-9]*$/', $range)){ + $ranges = explode("-",substr($range,strlen("bytes="))); + $a = $ranges[0]; + $b = $ranges[1]; + if($a > $b){ + throw new Ks3ClientException("Invalid range ".$range); + } + $range = array("start"=>$a,"end"=>$b); + }else{ + throw new Ks3ClientException("Invalid range ".$range); + } + }else{ + if(!isset($range["start"])||!isset($range["end"])){ + throw new Ks3ClientException("Invalid range ".serialize($range)); + } + if($range["start"] > $range["end"]){ + throw new Ks3ClientException("Invalid range ".serialize($range)); + } + } + } + + $isWriteToFile = isset($args["WriteTo"]); + $contentLength = $meta["ObjectMeta"]["Content-Length"]; + if($isWriteToFile){ + $writeCallBack = new AESCBCStreamWriteCallBack(); + $writeCallBack->iv=$iv; + $writeCallBack->cek=$cek; + $writeCallBack->contentLength = $contentLength; + if(isset($range)){ + $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC); + $adjustedRange = EncryptionUtil::getAdjustedRange($range,$blocksize); + $writeCallBack->expectedRange = $range; + $writeCallBack->adjustedRange = $adjustedRange; + $args["Range"]=$adjustedRange; + } + $args["writeCallBack"] = $writeCallBack; + return $this->ks3client->getObject($args); + }else{ + $offset = 0; + $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC); + if(isset($range)){ + $adjustedRange = EncryptionUtil::getAdjustedRange($range,$blocksize); + $args["Range"]=$adjustedRange; + } + $s3Object = $this->ks3client->getObject($args); + $content = $s3Object["Content"]; + + if(isset($range)){ + if($adjustedRange["start"] > 0){ + $iv = substr($content,0,$blocksize); + $content = substr($content,$blocksize); + $offset = $blocksize+$adjustedRange["start"]; + } + } + if(!empty($content)){ + $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); + mcrypt_generic_init($td,$cek,$iv); + $decoded = mdecrypt_generic($td,$content); + mcrypt_generic_deinit($td); + mcrypt_module_close($td); + }else{ + $decoded = ""; + } + + //判断是否需要删除最后填充的字符,以及获取填充的字符 + $needRemovePad = FALSE; + $pad = NULL; + if($offset+strlen($decoded) >=$contentLength){ + $needRemovePad = TRUE; + $pad = ord(substr($decoded,strlen($decoded)-1,1)); + if($pad<=0||$pad>$blocksize) + { + //invalid pad + $needRemovePad = FALSE; + } + } + $endOffset = 0; + if(isset($range)){ + if($offset+strlen($decoded)>$range["end"]){ + $preLength = strlen($decoded); + $decoded = substr($decoded, 0,$range["end"]-$offset+1); + $endOffset = $preLength-strlen($decoded); + } + if($offset<$range["start"]){ + $decoded = substr($decoded,$range["start"] - $offset); + } + } + //再次根据截取的长度判断是否需要删除最后填充的字符 + if($needRemovePad&&$endOffset > $pad){ + $needRemovePad = FALSE; + } + if($needRemovePad){ + $padOffset = $pad-$endOffset; + $actualWriteCount = strlen($decoded)-$padOffset; + if($actualWriteCount <= 0)//负数的情况就是用户期望的range里全是填充的 + $decoded = ""; + else + $decoded = substr($decoded,0,strlen($decoded)-$padOffset); + } + $s3Object["Content"] = $decoded; + return $s3Object; + } + }else{ + return $this->ks3client->getObject($args); + } + } + public function initMultipartUploadSecurely($args=array()){ + $sek = EncryptionUtil::genereateOnceUsedKey(); + $encryptedSek = EncryptionUtil::encodeCek($this->encryptionMaterials,$sek); + $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,''); + $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td),MCRYPT_RAND); + + $matdesc = "{}"; + if(ENCRYPTPTION_STORAGE_MODE == "ObjectMetadata"){ + $args["UserMeta"]["x-kss-meta-x-kss-key"] = base64_encode($encryptedSek); + $args["UserMeta"]["x-kss-meta-x-kss-iv"] = base64_encode($iv); + $args["UserMeta"]["x-kss-meta-x-kss-matdesc"] = $matdesc; + } + + $initResult = $this->ks3client->initMultipartUpload($args); + + EncryptionUtil::initMultipartUploadContext($initResult,$iv,$sek,$encryptedSek,$matdesc); + + return $initResult; + } + public function uploadPartSecurely($args=array()){ + $uploadId = $args["Options"]["uploadId"]; + $isLastPart = FALSE; + $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC); + if(isset($args["LastPart"])) + $isLastPart = $args["LastPart"]; + $exists = EncryptionUtil::multipartUploadContextExists($uploadId); + if(!$exists){ + throw new Ks3ClientException("no such upload in cache/encryption/"); + } + $context = EncryptionUtil::getMultipartUploadContext($uploadId); + if($context["lastPart"]){ + throw new Ks3ClientException("this upload with uploadId ".$uploadId," has been upload last part"); + } + $plainTextLength = EncryptionUtil::plainTextLength($args); + if($plainTextLength <= 0){ + throw new Ks3ClientException("get content length failed ,unexpected content length ".$plainTextLength); + } + if(!$isLastPart){ + if($plainTextLength % $blocksize != 0) + throw new Ks3ClientException("Invalid part size,part size (".$plainTextLength.") must be multiples of the block size ".$blocksize); + }else{ + $args["ObjectMeta"]["Content-Length"] = $plainTextLength + ($blocksize - $plainTextLength%$blocksize); + } + $readCallBack = new AESCBCStreamReadCallBack(); + $readCallBack->iv = base64_decode($context["nextIv"]); + $readCallBack->cek = base64_decode($context["cek"]); + $readCallBack->contentLength = $plainTextLength; + $readCallBack->mutipartUpload = TRUE; + $readCallBack->isLastPart = $isLastPart; + $args["readCallBack"] = $readCallBack; + + $upResult = $this->ks3client->uploadPart($args); + EncryptionUtil::updateMultipartUploadContext($uploadId,$readCallBack->iv,$isLastPart); + return $upResult; + } + public function abortMultipartUploadSecurely($args=array()){ + $uploadId = $args["Options"]["uploadId"]; + EncryptionUtil::deleteMultipartUploadContext($uploadId); + return $this->ks3client->abortMultipartUpload($args); + } + public function completeMultipartUploadSecurely($args=array()){ + $uploadId = $args["Options"]["uploadId"]; + $exists = EncryptionUtil::multipartUploadContextExists($uploadId); + if(!$exists){ + throw new Ks3ClientException("no such upload in cache/encryption/"); + } + $context = EncryptionUtil::getMultipartUploadContext($uploadId); + if(!$context["lastPart"]){ + throw new Ks3ClientException("Unable to complete an encrypted multipart upload without being told which part was the last. when upload part you can add item in args like args[\"LastPart\"]=TRUE"); + } + $result = $this->ks3client->completeMultipartUpload($args); + if(ENCRYPTPTION_STORAGE_MODE=="InstructionFile"){ + $req = EncryptionUtil::createInstructionFile($args["Bucket"],$args["Key"], + $context["encryptedCek"],$context["firstIv"],$context["matdesc"]); + $this->ks3client->putObjectByContent($req); + } + EncryptionUtil::deleteMultipartUploadContext($uploadId); + return $result; + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/encryption/EncryptionUtil.php b/src/service/ksyun/bin/encryption/EncryptionUtil.php new file mode 100644 index 0000000..b0b8195 --- /dev/null +++ b/src/service/ksyun/bin/encryption/EncryptionUtil.php @@ -0,0 +1,279 @@ +$a,"end"=>$b); + } + public static function encodeCek($encryptionMaterials,$cek){ + $encrypKeyAlg = EncryptionUtil::getKeyEncryptionAlgm($encryptionMaterials); + if($encrypKeyAlg === "AES"){ + $secretKey = $encryptionMaterials; + $encryptedSek = EncryptionUtil::encode_AES_ECB($cek,$secretKey); + if(empty($encryptedSek)) + throw new Ks3ClientException("can not encode cek useing AES"); + }else if($encrypKeyAlg === "RSA"){ + $encryptedSek = ""; + openssl_public_encrypt($cek,$encryptedSek, $encryptionMaterials[0]); + if(empty($encryptedSek)) + throw new Ks3ClientException("can not encode cek useing RSA"); + } + return $encryptedSek; + } + public static function decodeCek($encryptionMaterials,$cekEncrypted){ + $encrypKeyAlg = EncryptionUtil::getKeyEncryptionAlgm($encryptionMaterials); + if($encrypKeyAlg === "AES"){ + $secretKey = $encryptionMaterials; + $cek = EncryptionUtil::decode_AES_ECB($cekEncrypted,$secretKey); + if(empty($cek)) + throw new Ks3ClientException("can not decode cek useing AES,secret key maybe not correct"); + }else if($encrypKeyAlg === "RSA"){ + $cek = ""; + openssl_private_decrypt($cekEncrypted,$cek, $encryptionMaterials[1]); + if(empty($cek)) + throw new Ks3ClientException("can not decode cek useing RSA,public/private key pair maybe not correct"); + } + return $cek; + } + public static function getPKCS5EncrypedLength($length,$blocksize){ + $pad = $blocksize - $length%$blocksize; + return $length+$pad; + } + //pkcs5填充 + public static function PKCS5Padding($data,$blocksize){ + $pad = $blocksize - strlen($data)%$blocksize; + for($i = 0;$i < $pad;$i++){ + $data.= chr($pad); + } + return $data; + } + public static function updateContentMD5Header($req){ + if(!is_array($req)) + return $req; + if(isset($req["ObjectMeta"])){ + $meta = $req["ObjectMeta"]; + }else{ + return $req; + } + if(is_array($meta) && isset($meta["Content-MD5"])){ + $md5 = $meta["Content-MD5"]; + }else{ + return $req; + } + if(empty($md5)){ + return $req; + }else{ + $req["ObjectMeta"]["Content-MD5"] = NULL; + $req["UserMeta"]["x-kss-meta-x-kss-unencrypted-content-md5"] = $md5; + } + return $req; + } + public static function metaTextLength($req){ + if(!is_array($req)) + return -1; + if(isset($req["ObjectMeta"])){ + $meta = $req["ObjectMeta"]; + }else{ + return -1; + } + if(is_array($meta) && isset($meta["Content-Length"])){ + $length = $meta["Content-Length"]; + return $length; + }else + return -1; + } + public static function plainTextLength($args){ + if(isset($args["Content"])){ + if(is_array($args["Content"])){ + $content = $args["Content"]["content"]; + $seek_position = 0; + $resourceLength = 0; + $length = -1; + $isFile = FALSE; + + if (!is_resource($content)){ + $isFile = TRUE; + //如果之前用户已经转化为GBK则不转换 + if(Utils::chk_chinese($content)&&!Utils::check_char($content)){ + $content = iconv('utf-8','gbk',$content); + } + if(!file_exists($content)) + throw new Ks3ClientException("the specified file does not exist "); + $length = Utils::getFileSize($content); + $content = fopen($content,"r"); + }else{ + $stats = fstat($content); + if ($stats && $stats["size"] >= 0){ + $length = $stats["size"]; + } + } + $resourceLength = $length; + //优先取用户设置seek_position,没有的话取ftell + if(isset($args["Content"]["seek_position"])&&$args["Content"]["seek_position"]>0){ + $seek_position = $args["Content"]["seek_position"]; + }else if(!$isFile){ + $seek_position = ftell($content); + if($seek_position<0) + $seek_position = 0; + fseek($content,0); + } + + $lengthInMeta = -1; + if(isset($args["ObjectMeta"]["Content-Length"])){ + $lengthInMeta = $args["ObjectMeta"]["Content-Length"]; + } + if($lengthInMeta > 0){ + $length = $lengthInMeta; + }else if($resourceLength > 0){ + //根据seek_position计算实际长度 + $length = $resourceLength - $seek_position; + } + if($length <= 0) + throw new Ks3ClientException("calculate content length failed,unexpected contetn length ".$length); + return $length; + }else{ + $content = $args["Content"]; + $lengthInMeta = EncryptionUtil::metaTextLength($args); + $length = strlen($content); + if($length<$lengthInMeta||$lengthInMeta <= 0) + return $length; + else + return $lengthInMeta; + } + } + return -1; + } + public static function initMultipartUploadContext($initResult,$iv,$cek,$encryptedCek,$matdesc="{}"){ + $cacheDir = KS3_API_PATH.DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR; + $encryptionDir = KS3_API_PATH.DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR; + if(!is_dir($cacheDir)) + mkdir($cacheDir); + if(!is_dir($encryptionDir)) + mkdir($encryptionDir); + if(is_array($matdesc)){ + $matdesc = json_encode($matdesc); + } + $initResult["firstIv"] = base64_encode($iv); + $initResult["nextIv"] = base64_encode($iv); + $initResult["cek"] = base64_encode($cek); + $initResult["encryptedCek"] = base64_encode($encryptedCek); + $initResult["lastPart"] = FALSE; + $initResult["matdesc"] = $matdesc; + $json = json_encode($initResult); + $file = EncryptionUtil::openfile($encryptionDir.$initResult["UploadId"], "w"); + fwrite($file, $json); + fclose($file); + } + public static function updateMultipartUploadContext($UploadId,$iv,$lastPart = FALSE){ + $encryptionDir = KS3_API_PATH.DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR; + $content = EncryptionUtil::getMultipartUploadContext($UploadId); + $content["nextIv"] = base64_encode($iv); + $content["lastPart"] = $lastPart; + $json = json_encode($content); + $file = EncryptionUtil::openfile($encryptionDir.$UploadId, "w"); + fwrite($file, $json); + fclose($file); + } + public static function getMultipartUploadContext($UploadId){ + $encryptionDir = KS3_API_PATH.DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR; + if(!EncryptionUtil::multipartUploadContextExists($UploadId)) + throw new Ks3ClientException("can not found multipart upload context in cache dir"); + $jsonString = file_get_contents($encryptionDir.$UploadId); + $arry = json_decode($jsonString,TRUE); + return $arry; + } + public static function deleteMultipartUploadContext($UploadId){ + $encryptionDir = KS3_API_PATH.DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR; + @unlink($encryptionDir.$UploadId); + } + public static function multipartUploadContextExists($UploadId){ + $encryptionDir = KS3_API_PATH.DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR; + return file_exists($encryptionDir.$UploadId); + } + public static function openfile($path,$mode){ + $file = fopen($path, $mode); + if($file) + return $file; + else + throw new Ks3ClientException("open file ".$path." error"); + } + //matdesc为字符串或array数据类型。 + public static function createInstructionFile($bucket,$key,$cek,$iv,$matdesc="{}"){ + if(is_array($matdesc)){ + $matdesc = json_encode($matdesc); + } + $key = $key.EncryptionUtil::$INSTRUCTION_SUFFIX; + + $instruction = json_encode(array( + "x-kss-key"=>$cek, + "x-kss-iv"=>$iv, + "x-kss-matdesc"=>$matdesc + )); + + $req = array( + "Bucket"=>$bucket, + "Key"=>$key, + "Content"=>$instruction, + "UserMeta"=>array( + "x-kss-meta-x-kss-crypto-instr-file"=>base64_encode($key) + ) + ); + return $req; + } + public static function isInstructionFile($s3Object){ + $meta = $s3Object["Meta"]; + if(isset($meta["UserMeta"]["x-kss-meta-x-kss-crypto-instr-file"])) + return TRUE; + return FALSE; + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/exceptions/Exceptions.php b/src/service/ksyun/bin/exceptions/Exceptions.php new file mode 100644 index 0000000..40a84bb --- /dev/null +++ b/src/service/ksyun/bin/exceptions/Exceptions.php @@ -0,0 +1,34 @@ +$property_name=$value; + } + public function __get($property_name){ + if(isset($this->$property_name)) + { + return($this->$property_name); + }else + { + return(NULL); + } + } + public function __toString() + { + $message = get_class($this) . ': ' + ."(errorCode:".$this->errorCode.";" + ."errorMessage:".$this->errorMessage.";" + ."resource:".$this->resource.";" + ."requestId:".$this->requestId.";" + ."statusCode:".$this->statusCode.")"; + return $message; + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/lib/RequestCore.class.php b/src/service/ksyun/bin/lib/RequestCore.class.php new file mode 100644 index 0000000..a98c97c --- /dev/null +++ b/src/service/ksyun/bin/lib/RequestCore.class.php @@ -0,0 +1,1028 @@ +). + */ + public $request_class = 'RequestCore'; + + /** + * The default class to use for HTTP Responses (defaults to ). + */ + public $response_class = 'ResponseCore'; + + /** + * Default useragent string to use. + */ + public $useragent = 'RequestCore/1.4.3'; + + /** + * File to read from while streaming up. + */ + public $read_file = null; + + /** + * The resource to read from while streaming up. + */ + public $read_stream = null; + + /** + * The size of the stream to read from. + */ + public $read_stream_size = null; + + /** + * The length already read from the stream. + */ + public $read_stream_read = 0; + + /** + * File to write to while streaming down. + */ + public $write_file = null; + + /** + * The resource to write to while streaming down. + */ + public $write_stream = null; + + /** + * Stores the intended starting seek position. + */ + public $seek_position = null; + + /** + * The location of the cacert.pem file to use. + */ + public $cacert_location = false; + + /** + * The state of SSL certificate verification. + */ + public $ssl_verification = true; + + /** + * The user-defined callback function to call when a stream is read from. + */ + public $registered_streaming_read_callback = null; + + /** + * The user-defined callback function to call when a stream is written to. + */ + public $registered_streaming_write_callback = null; + + /*%******************************************************************************************%*/ + // CONSTANTS + + /** + * GET HTTP Method + */ + const HTTP_GET = 'GET'; + + /** + * POST HTTP Method + */ + const HTTP_POST = 'POST'; + + /** + * PUT HTTP Method + */ + const HTTP_PUT = 'PUT'; + + /** + * DELETE HTTP Method + */ + const HTTP_DELETE = 'DELETE'; + + /** + * HEAD HTTP Method + */ + const HTTP_HEAD = 'HEAD'; + + + /*%******************************************************************************************%*/ + // CONSTRUCTOR/DESTRUCTOR + + /** + * Constructs a new instance of this class. + * + * @param string $url (Optional) The URL to request or service endpoint to query. + * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. + * @return $this A reference to the current instance. + */ + public function __construct($url = null, $proxy = null, $helpers = null) + { + // Set some default values. + $this->request_url = $url; + $this->method = self::HTTP_GET; + $this->request_headers = array(); + $this->request_body = ''; + + // Set a new Request class if one was set. + if (isset($helpers['request']) && !empty($helpers['request'])) + { + $this->request_class = $helpers['request']; + } + + // Set a new Request class if one was set. + if (isset($helpers['response']) && !empty($helpers['response'])) + { + $this->response_class = $helpers['response']; + } + + if ($proxy) + { + $this->set_proxy($proxy); + } + + return $this; + } + + /** + * Destructs the instance. Closes opened file handles. + * + * @return $this A reference to the current instance. + */ + public function __destruct() + { + if (isset($this->read_file) && isset($this->read_stream)) + { + fclose($this->read_stream); + } + + if (isset($this->write_file) && isset($this->write_stream)) + { + fclose($this->write_stream); + } + + return $this; + } + + + /*%******************************************************************************************%*/ + // REQUEST METHODS + + /** + * Sets the credentials to use for authentication. + * + * @param string $user (Required) The username to authenticate with. + * @param string $pass (Required) The password to authenticate with. + * @return $this A reference to the current instance. + */ + public function set_credentials($user, $pass) + { + $this->username = $user; + $this->password = $pass; + return $this; + } + + /** + * Adds a custom HTTP header to the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @param mixed $value (Required) The value to assign to the custom HTTP header. + * @return $this A reference to the current instance. + */ + public function add_header($key, $value) + { + $this->request_headers[$key] = $value; + return $this; + } + + /** + * Removes an HTTP header from the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @return $this A reference to the current instance. + */ + public function remove_header($key) + { + if (isset($this->request_headers[$key])) + { + unset($this->request_headers[$key]); + } + return $this; + } + + /** + * Set the method type for the request. + * + * @param string $method (Required) One of the following constants: , , , , . + * @return $this A reference to the current instance. + */ + public function set_method($method) + { + $this->method = strtoupper($method); + return $this; + } + + /** + * Sets a custom useragent string for the class. + * + * @param string $ua (Required) The useragent string to use. + * @return $this A reference to the current instance. + */ + public function set_useragent($ua) + { + $this->useragent = $ua; + return $this; + } + + /** + * Set the body to send in the request. + * + * @param string $body (Required) The textual content to send along in the body of the request. + * @return $this A reference to the current instance. + */ + public function set_body($body) + { + $this->request_body = $body; + return $this; + } + + /** + * Set the URL to make the request to. + * + * @param string $url (Required) The URL to make the request to. + * @return $this A reference to the current instance. + */ + public function set_request_url($url) + { + $this->request_url = $url; + return $this; + } + + /** + * Set additional CURLOPT settings. These will merge with the default settings, and override if + * there is a duplicate. + * + * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings. + * @return $this A reference to the current instance. + */ + public function set_curlopts($curlopts) + { + $this->curlopts = $curlopts; + return $this; + } + + /** + * Sets the length in bytes to read from the stream while streaming up. + * + * @param integer $size (Required) The length in bytes to read from the stream. + * @return $this A reference to the current instance. + */ + public function set_read_stream_size($size) + { + $this->read_stream_size = $size; + + return $this; + } + + /** + * Sets the resource to read from while streaming up. Reads the stream from its current position until + * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by and + * . + * + * @param resource $resource (Required) The readable resource to read from. + * @param integer $size (Optional) The size of the stream to read. + * @return $this A reference to the current instance. + */ + public function set_read_stream($resource, $size = null) + { + if (!isset($size) || $size < 0) + { + $stats = fstat($resource); + + if ($stats && $stats['size'] >= 0) + { + $position = ftell($resource); + + if ($position !== false && $position >= 0) + { + $size = $stats['size'] - $position; + } + } + } + + $this->read_stream = $resource; + + return $this->set_read_stream_size($size); + } + + /** + * Sets the file to read from while streaming up. + * + * @param string $location (Required) The readable location to read from. + * @return $this A reference to the current instance. + */ + public function set_read_file($location) + { + $this->read_file = $location; + $read_file_handle = fopen($location, 'r'); + + return $this->set_read_stream($read_file_handle); + } + + /** + * Sets the resource to write to while streaming down. + * + * @param resource $resource (Required) The writeable resource to write to. + * @return $this A reference to the current instance. + */ + public function set_write_stream($resource) + { + $this->write_stream = $resource; + + return $this; + } + + /** + * Sets the file to write to while streaming down. + * + * @param string $location (Required) The writeable location to write to. + * @return $this A reference to the current instance. + */ + public function set_write_file($location) + { + $this->write_file = $location; + $write_file_handle = fopen($location, 'w'); + + return $this->set_write_stream($write_file_handle); + } + + /** + * Set the proxy to use for making requests. + * + * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @return $this A reference to the current instance. + */ + public function set_proxy($proxy) + { + $proxy = parse_url($proxy); + $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null; + $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null; + $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null; + $this->proxy = $proxy; + return $this; + } + + /** + * Set the intended starting seek position. + * + * @param integer $position (Required) The byte-position of the stream to begin reading from. + * @return $this A reference to the current instance. + */ + public function set_seek_position($position) + { + $this->seek_position = isset($position) ? (integer) $position : null; + + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is read from using + * . + * + * The user-defined callback function should accept three arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $file_handle - resource - Required - The file handle resource that represents the file on the local file system.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_read_callback($callback) + { + $this->registered_streaming_read_callback = $callback; + + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is written to using + * . + * + * The user-defined callback function should accept two arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_write_callback($callback) + { + $this->registered_streaming_write_callback = $callback; + + return $this; + } + + + /*%******************************************************************************************%*/ + // PREPARE, SEND, AND PROCESS REQUEST + + /** + * A callback function that is invoked by cURL for streaming up. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param resource $file_handle (Required) The open file handle resource. + * @param integer $length (Required) The maximum number of bytes to read. + * @return binary Binary data from a stream. + */ + public function streaming_read_callback($curl_handle, $file_handle, $length) + { + // Execute callback function + if ($this->registered_streaming_read_callback) + { + return $this->registered_streaming_read_callback->streaming_read_callback($curl_handle, $file_handle, $length,$this->read_stream,$this->seek_position); + } + // Once we've sent as much as we're supposed to send... + if ($this->read_stream_read >= $this->read_stream_size) + { + // Send EOF + return ''; + } + + // If we're at the beginning of an upload and need to seek... + if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) + { + if (fseek($this->read_stream, $this->seek_position) !== 0) + { + throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.'); + } + } + + $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size + $this->read_stream_read += strlen($read); + + $out = $read === false ? '' : $read; + + return $out; + } + + /** + * A callback function that is invoked by cURL for streaming down. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param binary $data (Required) The data to write. + * @return integer The number of bytes written. + */ + public function streaming_write_callback($curl_handle, $data) + { + if ($this->registered_streaming_write_callback){ + return $this->registered_streaming_write_callback->streaming_write_callback($curl_handle,$data,$this->write_stream); + } + $length = strlen($data); + $written_total = 0; + $written_last = 0; + + while ($written_total < $length) + { + $written_last = fwrite($this->write_stream, substr($data, $written_total)); + + if ($written_last === false) + { + return $written_total; + } + + $written_total += $written_last; + } + + return $written_total; + } + + /** + * Prepares and adds the details of the cURL request. This can be passed along to a + * function. + * + * @return resource The handle for the cURL object. + */ + public function prep_request() + { + $curl_handle = curl_init(); + + // Set default options. + curl_setopt($curl_handle, CURLOPT_URL, $this->request_url); + curl_setopt($curl_handle, CURLOPT_FILETIME, true); + curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false); + //为了兼容PHP 5.6,PHP 5.6把 CURLOPT_CLOSEPOLICY 这个变量删除了 + //curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED); + curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5); + curl_setopt($curl_handle, CURLOPT_HEADER, true); + curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl_handle, CURLOPT_TIMEOUT, 5184000); + curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 120); + curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true); + curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url); + curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent); + curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback')); + + // Verification of the SSL cert + if ($this->ssl_verification) + { + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2); + } + else + { + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false); + } + + // chmod the file as 0755 + if ($this->cacert_location === true) + { + curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); + } + elseif (is_string($this->cacert_location)) + { + curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location); + } + + // Debug mode + if ($this->debug_mode) + { + curl_setopt($curl_handle, CURLOPT_VERBOSE, true); + } + + // Handle open_basedir & safe mode + if (!ini_get('safe_mode') && !ini_get('open_basedir')) + { + curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, FALSE); + } + + // Enable a proxy connection if requested. + if ($this->proxy) + { + curl_setopt($curl_handle, CURLOPT_HTTPPROXYTUNNEL, true); + + $host = $this->proxy['host']; + $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : ''; + curl_setopt($curl_handle, CURLOPT_PROXY, $host); + + if (isset($this->proxy['user']) && isset($this->proxy['pass'])) + { + curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']); + } + } + + // Set credentials for HTTP Basic/Digest Authentication. + if ($this->username && $this->password) + { + curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password); + } + + // Handle the encoding if we can. + if (extension_loaded('zlib')) + { + curl_setopt($curl_handle, CURLOPT_ENCODING, ''); + } + + // Process custom headers + if (isset($this->request_headers) && count($this->request_headers)) + { + $temp_headers = array(); + + foreach ($this->request_headers as $k => $v) + { + $temp_headers[] = $k . ': ' . $v; + } + + curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers); + } + + switch ($this->method) + { + case self::HTTP_PUT: + //unset($this->read_stream); + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT'); + if (isset($this->read_stream)) + { + if (!isset($this->read_stream_size) || $this->read_stream_size < 0) + { + throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); + } + + curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); + curl_setopt($curl_handle, CURLOPT_UPLOAD, true); + } + else + { + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + } + break; + + case self::HTTP_POST: + curl_setopt($curl_handle, CURLOPT_POST, true); + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + break; + + case self::HTTP_HEAD: + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD); + curl_setopt($curl_handle, CURLOPT_NOBODY, 1); + break; + + default: // Assumed GET + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method); + if (isset($this->write_stream)) + { + curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback')); + curl_setopt($curl_handle, CURLOPT_HEADER, false); + } + else + { + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + } + break; + } + + // Merge in the CURLOPTs + if (isset($this->curlopts) && sizeof($this->curlopts) > 0) + { + foreach ($this->curlopts as $k => $v) + { + curl_setopt($curl_handle, $k, $v); + } + } + + return $curl_handle; + } + + /** + * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the + * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via + * parameters. + * + * @param resource $curl_handle (Optional) The reference to the already executed cURL request. + * @param string $response (Optional) The actual response content itself that needs to be parsed. + * @return ResponseCore A object containing a parsed HTTP response. + */ + public function process_response($curl_handle = null, $response = null) + { + // Accept a custom one if it's passed. + if ($curl_handle && $response) + { + $this->curl_handle = $curl_handle; + $this->response = $response; + } + + // As long as this came back as a valid resource... + if (is_resource($this->curl_handle)) + { + // Determine what's what. + $header_size = curl_getinfo($this->curl_handle, CURLINFO_HEADER_SIZE); + $this->response_headers = substr($this->response, 0, $header_size); + $this->response_body = substr($this->response, $header_size); + $this->response_code = curl_getinfo($this->curl_handle, CURLINFO_HTTP_CODE); + $this->response_info = curl_getinfo($this->curl_handle); + + // Parse out the headers + $this->response_headers = explode("\r\n\r\n", trim($this->response_headers)); + $this->response_headers = array_pop($this->response_headers); + $this->response_headers = explode("\r\n", $this->response_headers); + array_shift($this->response_headers); + + // Loop through and split up the headers. + $header_assoc = array(); + foreach ($this->response_headers as $header) + { + $kv = explode(': ', $header); + $header_assoc[strtolower($kv[0])] = isset($kv[1])?$kv[1]:''; + } + + // Reset the headers to the appropriate property. + $this->response_headers = $header_assoc; + $this->response_headers['_info'] = $this->response_info; + $this->response_headers['_info']['method'] = $this->method; + + if ($curl_handle && $response) + { + return new $this->response_class($this->response_headers, $this->response_body, $this->response_code, $this->curl_handle); + } + } + + // Return false + return false; + } + + /** + * Sends the request, calling necessary utility functions to update built-in properties. + * + * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not. + * @return string The resulting unparsed data from the request. + */ + public function send_request($parse = false) + { + set_time_limit(0); + + $curl_handle = $this->prep_request(); + $this->response = curl_exec($curl_handle); + + if ($this->response === false) + { + throw new RequestCore_Exception('cURL resource: ' . (string) $curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')'); + } + + $parsed_response = $this->process_response($curl_handle, $this->response); + + curl_close($curl_handle); + + if ($parse) + { + return $parsed_response; + } + + return $this->response; + } + + /** + * Sends the request using , enabling parallel requests. Uses the "rolling" method. + * + * @param array $handles (Required) An indexed array of cURL handles to process simultaneously. + * @param array $opt (Optional) An associative array of parameters that can have the following keys:
    + *
  • callback - string|array - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the [0] index is the class and the [1] index is the method name.
  • + *
  • limit - integer - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.
+ * @return array Post-processed cURL responses. + */ + public function send_multi_request($handles, $opt = null) + { + set_time_limit(0); + + // Skip everything if there are no handles to process. + if (count($handles) === 0) return array(); + + if (!$opt) $opt = array(); + + // Initialize any missing options + $limit = isset($opt['limit']) ? $opt['limit'] : -1; + + // Initialize + $handle_list = $handles; + $http = new $this->request_class(); + $multi_handle = curl_multi_init(); + $handles_post = array(); + $added = count($handles); + $last_handle = null; + $count = 0; + $i = 0; + + // Loop through the cURL handles and add as many as it set by the limit parameter. + while ($i < $added) + { + if ($limit > 0 && $i >= $limit) break; + curl_multi_add_handle($multi_handle, array_shift($handles)); + $i++; + } + + do + { + $active = false; + + // Start executing and wait for a response. + while (($status = curl_multi_exec($multi_handle, $active)) === CURLM_CALL_MULTI_PERFORM) + { + // Start looking for possible responses immediately when we have to add more handles + if (count($handles) > 0) break; + } + + // Figure out which requests finished. + $to_process = array(); + + while ($done = curl_multi_info_read($multi_handle)) + { + // Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html ) + if ($done['result'] > 0) + { + throw new RequestCore_Exception('cURL resource: ' . (string) $done['handle'] . '; cURL error: ' . curl_error($done['handle']) . ' (' . $done['result'] . ')'); + } + + // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests + elseif (!isset($to_process[(int) $done['handle']])) + { + $to_process[(int) $done['handle']] = $done; + } + } + + // Actually deal with the request + foreach ($to_process as $pkey => $done) + { + $response = $http->process_response($done['handle'], curl_multi_getcontent($done['handle'])); + $key = array_search($done['handle'], $handle_list, true); + $handles_post[$key] = $response; + + if (count($handles) > 0) + { + curl_multi_add_handle($multi_handle, array_shift($handles)); + } + + curl_multi_remove_handle($multi_handle, $done['handle']); + curl_close($done['handle']); + } + } + while ($active || count($handles_post) < $added); + + curl_multi_close($multi_handle); + + ksort($handles_post, SORT_NUMERIC); + return $handles_post; + } + + + /*%******************************************************************************************%*/ + // RESPONSE METHODS + + /** + * Get the HTTP response headers from the request. + * + * @param string $header (Optional) A specific header value to return. Defaults to all headers. + * @return string|array All or selected header values. + */ + public function get_response_header($header = null) + { + if ($header) + { + return $this->response_headers[strtolower($header)]; + } + return $this->response_headers; + } + + /** + * Get the HTTP response body from the request. + * + * @return string The response body. + */ + public function get_response_body() + { + return $this->response_body; + } + + /** + * Get the HTTP response code from the request. + * + * @return string The HTTP response code. + */ + public function get_response_code() + { + return $this->response_code; + } +} + + +/** + * Container for all response-related methods. + */ +class ResponseCore +{ + /** + * Stores the HTTP header information. + */ + public $header; + + /** + * Stores the SimpleXML response. + */ + public $body; + + /** + * Stores the HTTP response code. + */ + public $status; + + /** + * Constructs a new instance of this class. + * + * @param array $header (Required) Associative array of HTTP headers (typically returned by ). + * @param string $body (Required) XML-formatted response from AWS. + * @param integer $status (Optional) HTTP response status code from the request. + * @return object Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code. + */ + public function __construct($header, $body, $status = null) + { + $this->header = $header; + $this->body = $body; + $this->status = $status; + + return $this; + } + + /** + * Did we receive the status code we expected? + * + * @param integer|array $codes (Optional) The status code(s) to expect. Pass an for a single acceptable value, or an of integers for multiple acceptable values. + * @return boolean Whether we received the expected status code or not. + */ + public function isOK($codes = array(200, 201, 204, 206)) + { + if (is_array($codes)) + { + return in_array($this->status, $codes); + } + + return $this->status === $codes; + } +} + +/** + * Default RequestCore Exception. + */ +class RequestCore_Exception extends Exception {} diff --git a/src/service/ksyun/bin/readme.md b/src/service/ksyun/bin/readme.md new file mode 100644 index 0000000..8a663e6 --- /dev/null +++ b/src/service/ksyun/bin/readme.md @@ -0,0 +1,1227 @@ +# KS3 SDK For PHP使用指南 +--- + +[TOC] + +## 1 概述 +此SDK适用于PHP 5及以上版本。基于KS3 API 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到金山云存储上。 + + +## 2 环境准备 +配置PHP 5 以上开发环境 +添加curl拓展 +下载KS3 SDK For PHP +在项目中引用该php文件,Ks3Client.class.php + +## 3 初始化 +### 3.1 下载SDK +[https://github.com/ks3sdk/ks3-php-sdk](https://github.com/ks3sdk/ks3-php-sdk)下载SDK +### 3.2 获取秘钥 +1、开通KS3服务,[http://www.ksyun.com/user/register](http://www.ksyun.com/user/register) 注册账号 +2、进入控制台, [http://ks3.ksyun.com/console.html#/setting](http://ks3.ksyun.com/console.html#/setting) 获取AccessKeyID 、AccessKeySecret +### 3.3 配置 +在引用Ks3Client.class.php文件前定义 +//是否使用VHOST +define("KS3_API_VHOST",FALSE); +//是否开启日志(写入日志文件) +define("KS3_API_LOG",TRUE); +//是否显示日志(直接输出日志) +define("KS3_API_DISPLAY_LOG", TRUE); +//定义日志目录(默认是该项目log下) +define("KS3_API_LOG_PATH",""); +//是否使用HTTPS +define("KS3_API_USE_HTTPS",FALSE); +//是否开启curl debug模式 +define("KS3_API_DEBUG_MODE",FALSE); + +### 3.4 初始化客户端 +当以上全部完成之后用户便可初始化客户端进行操作了 + +需要指定ks3节点 +第三个参数endpoint需要对应bucket所在region!! 详见http://ks3.ksyun.com/doc/api/index.html Region(区域)一节 + + $client = new Ks3Client("<您的AccessKeyID>","<您的AccessKeySecret>","endpoint") + +ks3节点列表 +详见http://ks3.ksyun.com/doc/api/index.html Region(区域)一节 +## 4 异常说明 +### 4.1 Ks3ServiceException +当抛出Ks3ServiceException时表示KS3服务端返回异常信息。Ks3ServiceException继承自RuntimeException +用户可根据该异常中的信息获取到出错的原因 +### 4.2 Ks3ClientException +当抛出Ks3ClientException时表示客户端发送了异常。Ks3ClientException继承自RuntimeException +## 5 使用示例 +快速导航: +删除文件:5.3.1 5.3.2 +下载文件:5.3.3 +判断文件是否存在:5.3.5 +上传文件:5.3.7 +分块上传:5.3.12-5.3.17 +### 5.1 Service接口 +#### 5.1.1 GET Service +获取用户的所有bucket列表 +使用示例: + + $client->listBuckets(); + +返回结果格式: + + Array + ( + [0] => Array + ( + [Name] => aaphp + [CreationDate] => 2015-03-21T06:25:45.000Z + ) + + [1] => Array + ( + [Name] => adest + [CreationDate] => 2015-02-10T03:55:40.000Z + ) + + [2] => Array + ( + [Name] => afiles + [CreationDate] => 2015-02-10T07:39:19.000Z + ) + ) + +### 5.2 Bucket接口 +#### 5.2.1 DELETE Bucket +删除Bucket +注意: +1、只能删除空的Bucket +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>") + +使用示例: + + $client->deleteBucket($args); + +#### 5.2.2 DELETE Bucket cors +删除Bucket的跨域配置 +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>") + +使用示例: + + $client->deleteBucketCORS($args); + +#### 5.2.3 GET Bucket +罗列Bucket下的object +参数格式: +Options中为可选参数,用户需参考KS3 API文档根据实际情况调节参数。 + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Options"=>array( + "prefix"=>"", + "max-keys"=>"", + "marker"=>"", + "delimiter"=>"" + ) + ); +使用示例: + + $client->listObjects($args); + +返回结果格式: + + Array + ( + [Name] => ksc-scm //bucket名称 + [Prefix] => + [Marker] => + [Delimiter] => / + [MaxKeys] => 4 + [IsTruncated] => true //true表示返回的结果是全部结果的一部分 + [NextMarker] => dir/ //如果IsTruncated为true,则可以使用NextMarker作为下一次请求的marker.当请求时不提供delimiter的话不会返回NextMarker,可以使用Contents的最后一项作为下一次的Marker + [Contents] => Array + ( + [0] => Array + ( + [Key] => 123.pdf + [LastModified] => 2015-02-06T07:39:32.687Z + [ETag] => 1285ba0d89e9b0883a1a5975051af159 + [Size] => 515602 + [Owner] => Array + ( + [ID] => 73398334 + [DisplayName] => 73398334 + ) + + [StorageClass] => STANDARD + ) + + [1] => Array + ( + [Key] => 20150210154319.jpg + [LastModified] => 2015-02-10T07:44:20.818Z + [ETag] => c61d3bbb47947029b968d02be1cae7d0 + [Size] => 141179 + [Owner] => Array + ( + [ID] => 73398334 + [DisplayName] => 73398334 + ) + + [StorageClass] => STANDARD + ) + + [2] => Array + ( + [Key] => chrome.exe + [LastModified] => 2015-01-07T05:30:26.845Z + [ETag] => ac08a03d7e579e2903925736e7ab48f2 + [Size] => 852808 + [Owner] => Array + ( + [ID] => 73398334 + [DisplayName] => 73398334 + ) + + [StorageClass] => STANDARD + ) + + ) + + [CommonPrefixes] => Array + ( + [0] => dir/ + ) + ) + + +#### 5.2.4 GET Bucket acl +获取bucket的权限 +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>") + +使用示例: + + $client->getBucketAcl($args); + +返回结果: + + private、public-read或者public-read-write + +#### 5.2.5 GET Bucket cors +获取bucket的跨域配置 +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>") + +使用示例 + + $client->getBucketCORS($args); + +返回结果格式: + + Array + ( + [0] => Array + ( + [AllowedOrigin] => Array + ( + [0] => http://www.kingsoft.com + ) + [AllowedMethod] => Array + ( + [0] => GET + [1] => PUT + ) + [AllowedHeader] => Array + ( + [0] => * + ) + [MaxAgeSeconds] => 10 + [ExposeHeader] => Array + ( + [0] => * + ) + ) + [1] => Array + ( + [AllowedOrigin] => Array + ( + [0] => * + ) + [AllowedMethod] => Array + ( + [0] => GET + [1] => PUT + ) + [AllowedHeader] => Array + ( + [0] => * + ) + [MaxAgeSeconds] => 10 + [ExposeHeader] => Array + ( + [0] => * + ) + ) + ) + +#### 5.2.6 GET Bucket location +获取bucket的地址 +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>") + +使用示例: + + $client->getBucketLocation($args); + +返回结果格式: + + HANGZHOU + +#### 5.2.7 GET Bucket logging +获取bucket的日志配置 +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>") + +使用示例: + + $client->getBucketLogging($args); + +返回结果格式: + + Array + ( + [Enable] => 1 + [TargetBucket] => ksc-scm + [TargetPrefix] => + ) + +#### 5.2.8 HEAD Bucket +判断一个bucket是否存在 +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>") + +使用示例: + + $client->bucketExists($args); + +返回结果格式: + + TRUE或者FALSE + +#### 5.2.9 List Mutipart Uploads +列出当前bucket下未完成的分块上传 +参数格式: + + $args=array( + "Bucket"=><目标bucket名称>, + "Options"=>array( + "max-uploads"=>1,//调节参数,支持key-marker、prefix、upload-id-​marker、delimiter,详细作用请参考KS3 API文档 + ) + ) + +使用示例: + + $client->listMutipartUploads($args); + +返回结果格式: + + Array + ( + [Bucket] => phpsdktestlijunwei + [KeyMarker] => + [UploadIdMarker] => + [NextKeyMarker] => + [NextUploadIdMarker] => + [MaxUploads] => 1 + [IsTruncated] => true //true表示返回的结果只是全部结果的部分 + [Uploads] => Array + ( + [0] => Array + ( + [Key] => dir/test/中文目录/@特殊字符!.txt + [Initiated] => 2015-03-23T11:22:45.451+08:00 + [UploadId] => b05e21c69ff14386a66bbe9843976b17 + [Initiator] => Array + ( + [ID] => 73398529 + [DisplayName] => 73398529 + ) + [Owner] => Array + ( + [ID] => 73398529 + [DisplayName] => 73398529 + ) + [StorageClass] => STANDARD + ) + ) + ) + +#### 5.2.10 PUT Bucket +创建一个bucket +注意: +1、bucket名称是全局唯一,如果返回BucketAlreadyExists请尝试换一个名称 +2、bucket名称规则请参考KS3 API文档 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "ACL"=>"private", //配置bucket的访问权限,合法值:private、public-read、public-read-write + "Location"=>"HANGZHOU"//配置bucket存储地址,默认是杭州。支持HANGZHOU,AMERICA + ) + +使用示例: + + $client->createBucket($args); + +#### 5.2.11 PUT Bucket acl +设置bucket的访问权限 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "ACL"=>"private" //配置bucket的访问权限,合法值:private、public-read、public-read-write + ) +使用示例: + + $client->setBucketAcl ($args); + +#### 5.2.12 PUT Bucket cors +设置bucket的跨域规则 +注意: +1、如果返回InvalidArguments,请查看KS3 API文档,查看各参数格式要求。 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "CORS"=>array( + array( + "AllowedMethod"=>array("GET","PUT"), + "AllowedOrigin"=>array("http://www.kingsoft.com"), + "AllowedHeader"=>array("*"), + "ExposeHeader"=>array("*"), + "MaxAgeSeconds"=>10 + ), + array( + "AllowedMethod"=>array("GET","PUT"), + "AllowedOrigin"=>array("*"), + "AllowedHeader"=>array("*"), + "ExposeHeader"=>array("*"), + "MaxAgeSeconds"=>10 + ) + ) + ); + +使用示例 + + $client->setBucketCORS($args); + +#### 5.2.13 PUT Bucket logging +设置bucket的日志配置 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "BucketLogging"=>array( + "Enable"=>TRUE,//是否开启 + "TargetBucket"=>"ksc-scm", + "TargetPrefix"=>"X-KSS" + ) + ); + +使用示例 + + $client->setBucketLogging ($args); + + +### 5.3 Object接口 +#### 5.3.1 DELETE Object +删除一个object +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"123.pdf" + ); + +使用示例: + + $client->deleteObject($args); + +#### 5.3.2 DELETE Multiple Objects +删除多个object +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "DeleteKeys"=>array("","","") + ); + +使用示例: + + $client->deleteObjects($args); + +#### 5.3.3 GET Object +##### 5.3.3.1 下载object +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Range"=>array( //当需要分块下载时可以提供该参数 + "start"=>1, + "end"=>4, + ), + "WriteTo"=>"D://test.zip" //文件保存路径,可以不提供。可以是resource + ); + +使用示例: + + $client->getObject($args); + +返回结果格式(当不提供WriteTo时会有该返回结果): + + Array + ( + [Content] => "1234"//文件内容 + [Meta] => Array + ( + [ObjectMeta] => Array //元数据 + ( + [Content-Type] => binay/ocet-stream + [Content-Length] => 4 + [ETag] => "81dc9bdb52d04dc20036dbd8313ed055" + [Last-Modified] => Sat, 21 Mar 2015 06:31:28 GMT + ) + [UserMeta] => Array //用户自定义元数据 + ( + [x-kss-meta-test] => test + ) + ) + ) + + + +##### 5.3.3.2 下载经过客户提供主密钥的服务端加密数据 +参数格式: +在原有参数的基础上加上如下 + + "SSEC"=>array( + "Algm"=>"AES256", + "Key"=>"",// + "KeyBase64"=>"",//Key和KeyBase64提供一个即可 + "KeyMD5"=>"",//可以不指定,SDK将根据Key计算 + ) + +##### 5.3.3.3 生成object外链 +参数格式: + + $args=array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Options"=>array( + "Expires"=>60*60*24*10,//过期时间,单位秒,即x秒后过期 + "response-content-type"=>"application/xml"//覆盖返回的http header,支持的值"response-expires","response-content-encoding","response-content-disposition","response-content-language","response-content-type","response-cache-control" + ) + ); +使用示例: + + $client->generatePresignedUrl($args); + +返回结果格式: + + http://kss.ksyun.com/aaphp/multi.zip?Expires=1427900010&response-content-type=application%2Fxml&KSSAccessKeyId=2HITWMQXL2VBB3XMAEHQ&Signature=E3YAKqMp0%2BVoBaslu%2B3eE3Ki97w%3D + +#### 5.3.4 GET Object acl +获取object的权限 +参数格式: + + $args = array("Bucket"=>"<您的bucket名称>","Key"=>"") + +使用示例: + + $client->getObjectAcl($args); + +返回结果: + + private、public-read或者public-read-write + +#### 5.3.5 HEAD Object +可用来判断object是否存在或者获取object的元数据 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"" + ); + +##### 5.3.5.1 判断object是否存在 +使用示例: + + $client->objectExists ($args); + +返回结果格式: + + TRUE或者FALSE + +##### 5.3.5.2 获取object元数据 +使用示例: + + $client->getObjectMeta($args); + +返回结果格式: + + Array + ( + [ObjectMeta] => Array //元数据 + ( + [Content-Type] => binay/ocet-stream + [Content-Length] => 4 + [ETag] => "81dc9bdb52d04dc20036dbd8313ed055" + [Last-Modified] => Sat, 21 Mar 2015 06:31:28 GMT + ) + [UserMeta] => Array //用户自定义元数据 + ( + [x-kss-meta-test] => test + ) + ) +##### 5.3.5.3 请求经过客户提供主密钥的服务端加密数据 +参数格式: +在原有参数的基础上加上如下 + + "SSEC"=>array( + "Algm"=>"AES256", + "Key"=>"",// + "KeyBase64"=>"",//Key和KeyBase64提供一个即可 + "KeyMD5"=>"",//可以不指定,SDK将根据Key计算 + ) + +#### 5.3.6 POST Object +表单上传文件,用于获取KSSAccessKeyId、Policy和Signature +使用示例: + + $result = postObject( + $bucket ,//要上传的bucket + $postFormData=array(),//表单中能确定值得表单项, 如 array("key"=>"123.txt"); + $unknowValueFormFiled=array(),//表单中不能确定值得表单项,如 array("random1","random2"); + $filename=NULL,//如果没有使用${filename}占位符的话可以不提供要上传的文件名 + $expire=18000//生成的签名过期时间,单位秒 + ); + +返回结果格式: + + Array + ( + [Policy] => eyJleHBpcmF0aW9uIjoiMjAxNS0wMy0yNFQwMTozMjo0Ny4yODhaIiwiY29uZGl0aW9ucyI6W3sia2V5IjoiZm9ybXVwbG9hZHRlc3RcL0BcdTRlMmRcdTY1ODcudHh0In0seyJzdWNjZXNzX2FjdGlvbl9yZWRpcmVjdCI6Imh0dHA6XC9cL2tzcy5rc3l1bi5jb21cL3BocHNka3Rlc3RsaWp1bndlaSJ9LHsiQ29udGVudC1UeXBlIjoidGV4dFwvaHRtbCJ9LHsiYnVja2V0IjoicGhwc2RrdGVzdGxpanVud2VpIn0sWyJzdGFydHMtd2l0aCIsIiRyYW5kb20iLCIiXV19 + [Signature] => yQcB+sUpyjpwZu2JN9KYf2kXPCI= + [KSSAccessKeyId] => 1GL02rRYQxK8s7FQh8dV + ) + +#### 5.3.7 PUT Object +上传文件 +##### 5.3.7.1 通过内容上传 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Content"=>"1234",//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array(//设置object的元数据,可以设置"Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires"。当设置了Content-Length时,请勿大于实际长度,如果小于实际长度,将只上传部分内容。 + "Content-Type"=>"binay/ocet-stream", + "Content-Length"=>4 + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ) + ) +使用示例: + + $client->putObjectByContent($args); + +返回结果格式: + + Array + ( + [ETag] => "????" + ) + +##### 5.3.7.2 通过文件上传 +参数格式: + + $content = fopen("<文件路径>", "r"); + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Content"=>array(//要上传的内容 + "content"=>$content,//可以是文件路径或者resource,如果文件大于2G,请提供文件路径 + "seek_position"=>0//跳过文件开头?个字节 + ), + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array(//设置object的元数据,可以设置"Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires"。当设置了Content-Length时,最后上传的为从seek_position开始向后Content-Length个字节的内容。当设置了Content-MD5时,系统会在服务端进行md5校验。 + "Content-Type"=>"binay/ocet-stream" + //"Content-Length"=>4 + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ) + ); + +使用示例: + + $client->putObjectByFile ($args); + +返回结果格式: + + Array + ( + [ETag] => "????" + ) + +##### 5.3.7.3 上传文件时添加异步数据处理任务 +参数格式: +在原有参数的基础上加上如下 + + "Adp"=>array( + "NotifyURL"=>"<处理完成后KS3服务通知的地址>", + "Adps"=>array( + array( + "Command"=>"tag=avop&f=mp4&res=1280x720&vbr=1000k&abr=128k",//处理命令。具体参考KS3 API文档数据处理,不需要在命令中写tag=saveas&.. + "Bucket"=>"<处理完成后存在该bucket>",//需要拥有对该bucket写的权限.不提供的话将为数据所在的bucket + "Key"=>"<处理完成后存为该key>",//可以不提供,不提供的话将会是随机值。 + ), + //......可以有多条命令 + ) + ) + +比如: + + + $content = fopen("<文件路径>", "r"); + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Content"=>array(//要上传的内容 + "content"=>$content,//可以是文件路径或者resource + "seek_position"=>0//跳过文件开头?个字节 + ), + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array(//设置object的元数据,可以设置"Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires"。当设置了Content-Length时,最后上传的为从seek_position开始向后Content-Length个字节的内容。当设置了Content-MD5时,系统会在服务端进行md5校验。 + "Content-Type"=>"binay/ocet-stream", + "Content-Length"=>4 + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ) + "Adp"=>array( + "NotifyURL"=>"<处理完成后KS3服务通知的地址>", + "Adps"=>array( + array( + "Command"=>"tag=avop&f=mp4&res=1280x720&vbr=1000k&abr=128k",//处理命令。具体参考KS3 API文档数据处理,不需要在命令中写tag=saveas&.. + "Bucket"=>"<处理完成后存在该bucket>",//需要拥有对该bucket写的权限.不提供的话将为数据所在的bucket + "Key"=>"<处理完成后存为该key>",//可以不提供,不提供的话将会是随机值。 + ), + //......可以有多条命令 + ) + ) + ); + +返回结果格式: + + Array + ( + [ETag] => "????" + [TaskID] => "????" + ) + +##### 5.3.7.4 上传文件时添加回调 +参数格式: +在原有参数的基础上加上如下 + + "CallBack"=>array( + "Url"=>"", + "BodyMagicVariables"=>array("bucket"=>"bucket","key"=>"key"),//魔法变量,key=>value中的value将被最后的实际值替换,比如"bucket"=>"bucket"替换为"bucket"=>"<上传的bucket>"。支持:"bucket","key","etag","objectSize","mimeType","createTime" + "BodyVariables"=>array("name"=>"lijunwei")//自定义KS3回调时需要在body中带的参数 + ) + +##### 5.3.7.5 上传文件时使用服务端加密 +参数格式: +在原有参数的基础上加上如下 + + "SSE"=>array( + "Algm"=>"<服务端加密算法>"//暂时支持AES256 + ) + +##### 5.3.7.6 上传文件时使用客户提供主密钥的服务端加密 +参数格式: +在原有参数的基础上加上如下 + + "SSEC"=>array( + "Algm"=>"AES256", + "Key"=>"<主密钥>",//KS3服务端将使用该主密钥对数据进行加密 + "KeyBase64"=>"<主密钥的Base64>",//Key和KeyBase64提供一个即可 + "KeyMD5"=>"<主密钥经Base64编码的MD5值>",//可以不指定,SDK将根据Key计算 + ) + +#### 5.3.8 PUT Object acl +设置object的访问权限 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "ACL"=>"private" //合法值 private、public-read + ); +使用示例: + + $client->setObjectAcl ($args); + +#### 5.3.9 PUT Object - Copy +##### 5.3.9.1 基本方法 +拷贝object +参数格式: + + $args = array( + "Bucket"=>"<目标bucket>", + "Key"=>"<目标key>", + "CopySource"=>array( + "Bucket"=>"<源bucket>", + "Key"=>"<源key>" + ) + ); + +使用示例: + + $client->copyObject ($args); + +##### 5.3.9.2 被拷贝的Object是经过客户提供主密钥服务端加密的 +在原有参数的基础上添加 + + "SSECSource"=>array( + "Algm"=>"AES256", + "Key"=>"<主密钥>",//KS3服务端将使用该主密钥对数据进行解密 + "KeyBase64"=>"<主密钥的Base64>",//Key和KeyBase64提供一个即可 + "KeyMD5"=>"<主密钥经Base64编码的MD5值>",//可以不指定,SDK将根据Key计算 + ) + +##### 5.3.9.3 Copy后的Object使用服务端加密 +参数格式: +在原有参数的基础上加上如下 + + "SSE"=>array( + "Algm"=>"<服务端加密算法>"//暂时支持AES256 + ) + +##### 5.3.9.4 Copy后的Object使用客户提供主密钥的服务端加密 +参数格式: +在原有参数的基础上加上如下 + + "SSEC"=>array( + "Algm"=>"AES256", + "Key"=>"<主密钥>",//KS3服务端将使用该主密钥对数据进行加密 + "KeyBase64"=>"<主密钥的Base64>",//Key和KeyBase64提供一个即可 + "KeyMD5"=>"<主密钥经Base64编码的MD5值>",//可以不指定,SDK将根据Key计算 + ) + +#### 5.3.10 PUT Adp +添加异步数据处理: +参数格式: + + $args=array( + "Bucket"=>"<数据所在bucket>", + "Key"=>"<要处理的数据key>", + "Adp"=>array( + "NotifyURL"=>"<处理完成后KS3服务通知的地址>", + "Adps"=>array( + array( + "Command"=>"tag=avop&f=mp4&res=1280x720&vbr=1000k&abr=128k",//处理命令。具体参考KS3 API文档数据处理,不需要在命令中写tag=saveas&.. + "Bucket"=>"<处理完成后存在该bucket>",//需要拥有对该bucket写的权限.不提供的话将为数据所在的bucket + "Key"=>"<处理完成后存为该key>",//可以不提供,不提供的话将会是随机值。 + ), + //......可以有多条命令 + ) + ) + ); + +使用示例: + + $client->putAdp($args); + +返回结果格式: + + Array + ( + [TaskID] => 00P7kNjRfJUv + ) + + + +#### 5.3.11 GET Adp +查询数据处理任务 +参数格式: + + $args = array("TaskID"=>""); + +使用示例: + + $client->getAdp($args); + +#### 5.3.12 Initiate Multipart Upload +##### 5.3.12.1 基本方式 +初始化分块上传 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "UserMeta"=>array(//可以设置用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"example" + ), + "ObjectMeta"=>array(//可以设置用户元数据,合法值,"Cache-Control","Content-Disposition","Content-Encoding","Content-Type","Expires" + "Content-Type"=>"text/plain" + ) + ); +使用示例: + + $client->initMultipartUpload ($args); + +返回结果格式: + + Array + ( + [Bucket] => aaphp + [Key] => multi.zip + [UploadId] => bbdb766a65ef43ebad2b2531739092d0 + ) + +##### 5.3.12.2 使用服务端加密 +参数格式: +在原有参数的基础上加上如下 + + "SSE"=>array( + "Algm"=>"<服务端加密算法>"//暂时支持AES256 + ) + +##### 5.3.12.3 使用客户提供主密钥的服务端加密 +参数格式: +在原有参数的基础上加上如下 + + "SSEC"=>array( + "Algm"=>"AES256", + "Key"=>"<主密钥>",//KS3服务端将使用该主密钥对数据进行加密 + "KeyBase64"=>"<主密钥的Base64>",//Key和KeyBase64提供一个即可 + "KeyMD5"=>"<主密钥经Base64编码的MD5值>",//可以不指定,SDK将根据Key计算 + ) + +#### 5.3.13 Upload Part +##### 5.3.13.1 基本方式 +上传块 +参数格式: +主要通过seek_position和Content-Length参数控制上传的内容范围 + + $args=array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "LastPart"=>FALSE,//指定当前块是否为最后一块 + "Options"=>array( + "partNumber"=>,//当前上传块的序号,需要为连续的正整数, + "uploadId"=>//由Initiate Multipart Upload获得 + ), + "ObjectMeta"=>array( + "Content-Length"=>//这一块要上传的大小,必须准确指定,否则会出错。 + "Content-MD5"=>""//可以提供该块的MD5值,将在服务端进行MD5校验 + ), + "Content"=>array( + "content"=>,//要上传的文件路径,可以为resource,如果文件大于2G,请提供文件路径 + "seek_position"=>//跳过文件开头?个字节 + ) + ); +使用示例: + + $client->uploadPart ($args); +返回结果格式: + + Array + ( + [ETag] => "9430d3a88773837eed6ce0f136770ea3" + ) + +##### 5.3.13.2 使用客户提供主密钥的服务端加密 +参数格式: +在原有参数的基础上加上如下 + + "SSEC"=>array( + "Algm"=>"AES256", + "Key"=>"<主密钥>",//KS3服务端将使用该主密钥对数据进行加密 + "KeyBase64"=>"<主密钥的Base64>",//Key和KeyBase64提供一个即可 + "KeyMD5"=>"<主密钥经Base64编码的MD5值>",//可以不指定,SDK将根据Key计算 + ) + +#### 5.3.14 List Parts +列出一个分块上传已经上传的块 +参数格式: + + $args = array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Options"=>array("uploadId"=>)//由Initiate Multipart Upload获得 + ) + +使用示例: + + $client->listParts($args); + +返回结果格式: + + Array + ( + [Bucket] => aaphp + [Key] => multi.zip + [UploadId] => bbdb766a65ef43ebad2b2531739092d0 + [StorageClass] => + [PartNumberMarker] => 1 + [NextPartNumberMarker] => + [MaxParts] => 1000 + [IsTruncated] => false + [Owner] => Array + ( + [ID] => NzMzOTgzMzQ= + [DisplayName] => NzMzOTgzMzQ= + ) + [Initiator] => Array + ( + [ID] => NzMzOTgzMzQ= + [DisplayName] => NzMzOTgzMzQ= + ) + + [Parts] => Array + ( + [0] => Array + ( + [PartNumber] => 1 + [ETag] => 9430d3a88773837eed6ce0f136770ea3 + [LastModified] => 2015-03-22T12:48:32.800Z + [Size] => 5242880 + ) + + [1] => Array + ( + [PartNumber] => 2 + [ETag] => cd18e9d26dba2121baf291693158b84b + [LastModified] => 2015-03-22T12:48:54.716Z + [Size] => 5242880 + ) + + [2] => Array + ( + [PartNumber] => 3 + [ETag] => bfd9044ef806a7408dd6ae803654f1a0 + [LastModified] => 2015-03-22T12:49:17.163Z + [Size] => 5242880 + ) + + [3] => Array + ( + [PartNumber] => 4 + [ETag] => 36a2f4d8582cbd37a20c1541d0aff1cd + [LastModified] => 2015-03-22T12:49:17.390Z + [Size] => 37896 + ) + ) + ) + + +#### 5.3.15 Complete Multipart Upload +##### 5.3.15.1 基本方式 +完成分块上传 +参数格式: + + $args=array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Options"=>array("uploadId"=>)//由Initiate Multipart Upload获得 + "Parts"=>array(//需要提供Upload Part时的PartNumber和ETag。可以直接使用List Parts的返回结果中的Parts + array( + "PartNumber"=>1, + "ETag"=>"7778aef83f66abc1fa1e8477f296d394" + ), + array( + "PartNumber"=>2, + "ETag"=>"7778aef83f66abc1fa1e8477f296d394" + ), + array( + "PartNumber"=>3, + "ETag"=>"7778aef83f66abc1fa1e8477f296d394" + ), + array( + "PartNumber"=>4, + "ETag"=>"7778aef83f66abc1fa1e8477f296d394" + ), + ) + ) + +使用示例: + + $client->completeMultipartUpload($args); + +##### 5.3.15.2 添加异步数据处理任务 +参数格式: +在原有参数的基础上加上如下 + + "Adp"=>array( + "NotifyURL"=>"<处理完成后KS3服务通知的地址>", + "Adps"=>array( + array( + "Command"=>"tag=avop&f=mp4&res=1280x720&vbr=1000k&abr=128k",//处理命令。具体参考KS3 API文档数据处理,不需要在命令中写tag=saveas&.. + "Bucket"=>"<处理完成后存在该bucket>",//需要拥有对该bucket写的权限.不提供的话将为数据所在的bucket + "Key"=>"<处理完成后存为该key>",//可以不提供,不提供的话将会是随机值。 + ), + //......可以有多条命令 + ) + ) + +返回结果格式: + + Array + ( + [TaskID] => "????" + ) + +##### 5.3.15.3 添加回调 +参数格式: +在原有参数的基础上加上如下 + + "CallBack"=>array( + "Url"=>"", + "BodyMagicVariables"=>array("bucket"=>"bucket","key"=>"key"),//魔法变量,key=>value中的value将被最后的实际值替换,比如"bucket"=>"bucket"替换为"bucket"=>"<上传的bucket>"。支持:"bucket","key","etag","objectSize","mimeType","createTime" + "BodyVariables"=>array("name"=>"lijunwei")//自定义KS3回调时需要在body中带的参数 + ) + + + + +#### 5.3.16 Abort Multipart Upload +取消分块上传 +参数格式: + + $args=array( + "Bucket"=>"<您的bucket名称>", + "Key"=>"", + "Options"=>array("uploadId"=>)//由Initiate Multipart Upload获得 + ); +使用示例: + + $client->abortMultipartUpload($args); + +#### 5.3.17 Mutipart Upload(分块上传) Demo +分块上传示例 + + function multipartUpload($client){ + //初始化分开上传,获取uploadid + $args = array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "UserMeta"=>array( + "x-kss-meta-test"=>"example" + ), + "ObjectMeta"=>array( + "Content-Type"=>"text/plain" + ) + ); + $uploadid = $client->initMultipartUpload($args); + print_r($uploadid); + $uploadid = $uploadid["UploadId"];//获取到uploadid + echo $uploadid."\r\n"; + //开始上传 + + $file = "D://iToolsSetup_3.1.6.6.1419818705.exe";//要上传的文件 + $partsize = 1024*1024*5; + $resource = fopen($file,"r"); + $stat = fstat($resource); + $total = $stat["size"];//获取文件的总大小 + fclose($resource); + $count = (int)(($total-1)/$partsize)+1;//计算文件需要分几块上传 + echo $count."\r\n"; + for($i = 0;$i < $count;$i++){ + //依次上传每一块 + echo "upload".$i."\r\n"; + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array( + "partNumber"=>$i+1, + "uploadId"=>$uploadid + ), + "ObjectMeta"=>array( + "Content-Length"=>min($partsize,$total-$partsize*$i)//每次上传$partsize大小 + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>$partsize*$i//跳过之前已经上传的 + ) + ); + $etag = $client->uploadPart($args); + print_r($etag); + $etag = $etag["ETag"]; + } + $parts = $client->listParts(array("Bucket"=>"aaphp","Key"=>"multi.zip","Options"=>array("uploadId"=>$uploadid))); + print_r($parts);//列出以及上传的块 + //结束上传 + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"]//使用之前列出的块完成分开上传 + ); + $result = $client->completeMultipartUpload($args); + print_r($result); + } + +#### 5.3.17 使用外链操作 +使用示例: +参数格式: + + $args=array( + "Method"="GET",//http请求方法 + "Bucket"=>"", + "Key"=>"", + "Options"=>array( + "Expires"=><过期时间,单位秒,即x秒后过期> + //其他参数... + ), + "Headers"=>array( + //"Content-Type"=>"...", + //"Content-MD5"=>"...", + //"x-kss-acl"=>"..." + ) + ); + +使用示例: + + $client->generatePresignedUrl($args); + + +### 5.4 客户端加密 + +#### 5.4.1 环境准备 +添加mcrypt与openssl拓展 +#### 5.4.2 初始化客户端 +1、使用256位AES对称主密钥 + + $client = new Ks3EncryptionClient("","",""); + +2、使用1024位RSA非对称主秘钥(密钥对) + + $client = new Ks3EncryptionClient("","",array("","")); + +#### 5.4.3 注意事项 +1、上传上去的文件是经过加密的。 +2、下载文件只能通过该客户端getObject方法下载,用其他方法下载下来的文件是经过加密的。 +3、分块上传时必须依次上传每一块。当上传最后一块时必须通过$args=array("LastPart"=>TRUE)指定最后一块。上传顺序不能错乱,不能使用多线程分块上传。 +4、请妥善保管自己的主密钥,如果主密钥丢失,将无法解密数据。 + diff --git a/src/service/ksyun/bin/samples/FormUpload.php b/src/service/ksyun/bin/samples/FormUpload.php new file mode 100644 index 0000000..2c74e62 --- /dev/null +++ b/src/service/ksyun/bin/samples/FormUpload.php @@ -0,0 +1,48 @@ +bucketExists(array("Bucket"=>$bucket_name))){ + $client->createBucket(array("Bucket"=>$bucket_name)); +} + + +$key = 'formuploadtest/@中文.txt'; +$host = "kss.ksyun.com"; +$host_uri = "http://".$host."/".$bucket_name; +$redirect = $host_uri; + +//将所有能确定值的表单项都放在该数组中 +$postData = array( + "key"=>$key, + "success_action_redirect"=>$redirect, + "Content-Type"=>"text/html", + ); +//将不能确定值的表单项都放在该数组中 +$unknowData = array( + "random" + ); +$result = $client->postObject($bucket_name,$postData,$unknowData); +print_r($result); + +?> + + + + + +
+Key to upload:
+ + + +" /> +" /> +" /> +File:
+ + +
+ \ No newline at end of file diff --git a/src/service/ksyun/bin/samples/Samples.php b/src/service/ksyun/bin/samples/Samples.php new file mode 100644 index 0000000..d09b8b5 --- /dev/null +++ b/src/service/ksyun/bin/samples/Samples.php @@ -0,0 +1,413 @@ +listBuckets(); +} +function deleteBucket($client){ + return $client->deleteBucket(array("Bucket"=>"ksc-scm")); +} +function deleteBucketCORS($client){ + return $client->deleteBucketCORS(array("Bucket"=>"ksc-scm")); +} +function listObjects($client){ + $args = array( + "Bucket"=>"lijunwei.test", + "Options"=>array( + //"prefix"=>"dir/", + "max-keys"=>4, + //"marker"=>"123.pdf", + "delimiter"=>"/" + ) + ); + return $client->listObjects($args); +} +function getBucketAcl($client){ + return $client->getBucketAcl(array("Bucket"=>"aaphp")); +} +function getBucketCORS($client){ + return $client->getBucketCORS(array("Bucket"=>"ksc-scm")); +} +function getBucketLocation($client){ + return $client->getBucketLocation(array("Bucket"=>"ksc-scm")); +} +function getBucketLogging($client){ + return $client->getBucketLogging(array("Bucket"=>"ksc-scm")); +} +function bucketExists($client){ + $args = array("Bucket"=>"ksc-scm"); + return $client->bucketExists($args); +} +function createBucket($client){ + $args = array( + "Bucket"=>"ksc-scm", + "ACL"=>"private" + ); + return $client->createBucket($args); +} +function setBucketAcl($client){ + $args = array( + "Bucket"=>"ksc-scm", + "ACL"=>"private" + ); + return $client->setBucketAcl($args); +} +function setBucketCORS($client){ + $args = array( + "Bucket"=>"ksc-scm", + "CORS"=>array( + array( + "AllowedMethod"=>array("GET","PUT"), + "AllowedOrigin"=>array("http://www.kingsoft.com"), + "AllowedHeader"=>array("*"), + "ExposeHeader"=>array("*"), + "MaxAgeSeconds"=>10 + ), + array( + "AllowedMethod"=>array("GET","PUT"), + "AllowedOrigin"=>array("*"), + "AllowedHeader"=>array("*"), + "ExposeHeader"=>array("*"), + "MaxAgeSeconds"=>10 + ) + ) + ); + return $client->setBucketCORS($args); +} +function setBucketLogging($client){ + $args = array( + "Bucket"=>"ksc-scm", + "BucketLogging"=>array( + "Enable"=>TRUE, + "TargetBucket"=>"ksc-scm", + "TargetPrefix"=>"X-KSS" + ) + ); + return $client->setBucketLogging($args); +} +function deleteObject($client){ + $args = array( + "Bucket"=>"ksc-scm", + "Key"=>"123.pdf" + ); + return $client->deleteObject($args); +} +function deleteObjects($client){ + $args = array( + "Bucket"=>"ksc-scm", + "DeleteKeys"=>array("copy/test.zip","copy/123.doc") + ); + return $client->deleteObjects($args); +} +function getObject($client){ + $args = array( + "Bucket"=>"aaphp", + "Key"=>"multi.exe", + "Range"=>array( + "start"=>NULL, + "end"=>4, + ), + "WriteTo"=>"D://test.zip" + ); + return $client->getObject($args); +} +function getObjectAcl($client){ + $args = array( + "Bucket"=>"aaphp", + "Key"=>"multi.exe" + ); + return $client->getObjectAcl($args); +} +function objectExists($client){ + $args = array( + "Bucket"=>"ksc-scm", + "Key"=>"123.pdf" + ); + return $client->objectExists($args); +} +function getObjectMeta($client){ + $args = array( + "Bucket"=>"aaphp", + "Key"=>"test.zip" + ); + return $client->getObjectMeta($args); +} +function setObjectAcl($client){ + $args = array( + "Bucket"=>"aaphp", + "Key"=>"test.zip", + "ACL"=>"private" + ); + return $client->setObjectAcl($args); +} +function copyObject($client){ + $args = array( + "Bucket"=>"aaphp", + "Key"=>"copy/test.zip", + "CopySource"=>array( + "Bucket"=>"aaphp", + "Key"=>"test.zip" + ) + ); + return $client->copyObject($args); +} +function putObjectByFile($client){ + $file = "D://phpput"; + if(Utils::chk_chinese($file)){ + $file = iconv('utf-8','gbk',$file); + } + $content = $file; + $args = array( + "Bucket"=>"aaphp", + "Key"=>"stream_upload1.txt", + "ACL"=>"public-read", + "ObjectMeta"=>array( + "Content-Type"=>"image/jpg",//只传0-10字节, + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>0 + ), + ); + return $client->putObjectByFile($args); +} +function multipartUpload($client){ + $args = array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "UserMeta"=>array( + "x-kss-meta-test"=>"example" + ), + "ObjectMeta"=>array( + "Content-Type"=>"text/plain" + ) + ); + $uploadid = $client->initMultipartUpload($args); + print_r($uploadid); + $uploadid = $uploadid["UploadId"]; + echo $uploadid."\r\n"; + //开始上传 + + $file = "D://新建文件夹.rar"; + if(Utils::chk_chinese($file)){ + $file = iconv('utf-8','gbk',$file); + } + $total = Utils::getFileSize($file); + $partsize = 1024*1024*5; + $count = (int)(($total-1)/$partsize)+1; + echo $count."\r\n"; + for($i = 0;$i < $count;$i++){ + echo "upload".$i."\r\n"; + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array( + "partNumber"=>$i+1, + "uploadId"=>$uploadid + ), + "ObjectMeta"=>array( + "Content-Length"=>$partsize + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>$partsize*$i + ) + ); + $etag = $client->uploadPart($args); + print_r($etag); + $etag = $etag["ETag"]; + } + $parts = $client->listParts(array("Bucket"=>"aaphp","Key"=>"multi.zip","Options"=>array("uploadId"=>$uploadid))); + print_r($parts); + //结束上传 + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"] + ); + $result = $client->completeMultipartUpload($args); + print_r($result); +} +function abortMultipartUpload($client){ + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array("uploadId"=>"1234") + ); + return $client->abortMultipartUpload($args); +} +function generatePresignedUrl($client){ + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array( + "Expires"=>60*60*24*10, + "response-content-type"=>"application/xml" + ) + ); + return $client->generatePresignedUrl($args); +} +function putObjectWithAdpAndCallBack($client){ + $content = "D://野生动物.3gp"; + $args = array( + "Bucket"=>"aaphp", + "Key"=>"野生动物.3gp", + "ACL"=>"public-read", + "Content"=>array( + "content"=>$content + ), + "Adp"=>array( + "NotifyURL"=>"http://10.4.2.38:19090/", + "Adps"=>array( + array( + "Command"=>"tag=avop&f=mp4&res=1280x720&vbr=1000k&abr=128k", + "Key"=>"野生动物-转码.3gp" + ) + ) + ), + "CallBack"=>array( + "Url"=>"http://10.4.2.38:19090/", + "BodyMagicVariables"=>array("bucket"=>"bucket","key"=>"key"), + "BodyVariables"=>array("name"=>"lijunwei") + ) + ); + return $client->putObjectByFile($args); +} +function multipartUploadWithAdpAndCallBack($client){ + $args = array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "UserMeta"=>array( + "x-kss-meta-test"=>"example" + ), + "ObjectMeta"=>array( + "Content-Type"=>"text/plain" + ) + ); + $uploadid = $client->initMultipartUpload($args); + print_r($uploadid); + $uploadid = $uploadid["UploadId"]; + echo $uploadid."\r\n"; + //开始上传 + + $file = "D://野生动物.3gp"; + if(Utils::chk_chinese($file)){ + $file = iconv('utf-8','gbk',$file); + } + $partsize = 1024*1024*5; + $total = Utils::getFileSize($file); + $count = (int)(($total-1)/$partsize)+1; + echo $count."\r\n"; + for($i = 0;$i < $count;$i++){ + echo "upload".$i."\r\n"; + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array( + "partNumber"=>$i+1, + "uploadId"=>$uploadid + ), + "ObjectMeta"=>array( + "Content-Length"=>$partsize + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>$partsize*$i + ) + ); + $etag = $client->uploadPart($args); + print_r($etag); + $etag = $etag["ETag"]; + } + $parts = $client->listParts(array("Bucket"=>"aaphp","Key"=>"multi.zip","Options"=>array("uploadId"=>$uploadid))); + print_r($parts); + //结束上传 + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"], + "Adp"=>array( + "NotifyURL"=>"http://10.4.2.38:19090/", + "Adps"=>array( + array( + "Command"=>"tag=avop&f=mp4&res=1280x720&vbr=1000k&abr=128k", + "Key"=>"野生动物-转码.3gp" + ) + ) + ), + "CallBack"=>array( + "Url"=>"http://10.4.2.38:19090/", + "BodyMagicVariables"=>array("bucket"=>"bucket","key"=>"key"), + "BodyVariables"=>array("name"=>"lijunwei") + ) + ); + $result = $client->completeMultipartUpload($args); + print_r($result); + $taskid = $result["TaskID"]; + $task = $client->getAdp(array("TaskID"=>$taskid)); + print_r($task); +} +function putAdp($client){ + $args=array( + "Bucket"=>"aaphp", + "Key"=>"multi.zip", + "Adp"=>array( + "NotifyURL"=>"http://10.4.2.38:19090/", + "Adps"=>array( + array( + "Command"=>"tag=avop&f=mp4&res=1280x720&vbr=1000k&abr=128k", + "Key"=>"野生动物-转码.3gp" + ) + ) + ) + ); + $result = $client->putAdp($args); + print_r($result); + $taskid = $result["TaskID"]; + $task = $client->getAdp(array("TaskID"=>$taskid)); + print_r($task); +} +function postObject($client){ + + $postData = array( + "key"=>"~!@\\#$\%^&*()_+-=qw", + "acl"=>"public-read" + ); + $unKnowData=array("122","334"); + + print_r($client->postObject("ksc-scm",$postData,$unKnowData)); +} +?> diff --git a/src/service/ksyun/bin/samples/TestEncryptionClientFile.php b/src/service/ksyun/bin/samples/TestEncryptionClientFile.php new file mode 100644 index 0000000..29b44b5 --- /dev/null +++ b/src/service/ksyun/bin/samples/TestEncryptionClientFile.php @@ -0,0 +1,170 @@ +$bucket, + "Key"=>$keyprefix."EOFile", + "ACL"=>"public-read", + "Content"=>$content + ); + $client->putObjectByContent($args); + rangeGetAndCheckMd5($client,$bucket,$keyprefix."EOFile", + "D://testdown/down",base64_encode(md5($args["Content"]))); +} +function putObjectByFileAndGetObjectUsingFile($client,$bucket,$keyprefix){ + + $args = array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOFile", + "ACL"=>"public-read", + "Content"=>array( + "content"=>"D://IMG.jpg" + ) + ); + $client->putObjectByFile($args); + rangeGetAndCheckMd5($client,$bucket,$keyprefix."EOFile", + "D://testdown/down",base64_encode(md5_file("D://IMG.jpg"))); +} +function multipartUpload($client,$bucket,$keyprefix){ + //初始化分开上传,获取uploadid + $args = array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOFile", + ); + $uploadid = $client->initMultipartUpload($args); + $uploadid = $uploadid["UploadId"];//获取到uploadid + //开始上传 + + $file = "D://IMG.jpg";//要上传的文件 + $partsize = 1024*100; + $resource = fopen($file,"r"); + $stat = fstat($resource); + $total = $stat["size"];//获取文件的总大小 + fclose($resource); + $count = (int)(($total-1)/$partsize)+1;//计算文件需要分几块上传 + for($i = 0;$i < $count;$i++){ + //依次上传每一块 + echo "upload".$i."\r\n"; + $args=array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOFile", + "LastPart"=>($i===$count-1), + "Options"=>array( + "partNumber"=>$i+1, + "uploadId"=>$uploadid + ), + "ObjectMeta"=>array( + "Content-Length"=>min($partsize,$total-$partsize*$i)//每次上传$partsize大小 + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>$partsize*$i//跳过之前已经上传的 + ) + ); + $etag = $client->uploadPart($args); + $etag = $etag["ETag"]; + } + $parts = $client->listParts(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFile","Options"=>array("uploadId"=>$uploadid))); + //结束上传 + $args=array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOFile", + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"]//使用之前列出的块完成分开上传 + ); + $result = $client->completeMultipartUpload($args); + + rangeGetAndCheckMd5($client,$bucket,$keyprefix."EOFile", + "D://testdown/down",base64_encode(md5_file("D://IMG.jpg"))); +} +function copyAnddeleteObject($client,$bucket,$keyprefix){ + $content = EncryptionUtil::genereateOnceUsedKey(rand(100,1000)); + $args = array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOFile", + "ACL"=>"public-read", + "Content"=>$content + ); + $client->putObjectByContent($args); + + if($client->objectExists(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy"))) + $client->deleteObject(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy")); + if($client->objectExists(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy.instruction"))) + $client->deleteObject(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy.instruction")); + + $copyReq = array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOFileCopy", + "CopySource"=>array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOFile" + ) + ); + $client->copyObject($copyReq); + + if(!$client->objectExists(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy"))) + throw new Exception("not found ".$keyprefix."EOFileCopy"); + if(!$client->objectExists(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy.instruction"))) + throw new Exception("not found ".$keyprefix."EOFileCopy.instruction"); + + $client->deleteObject(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy")); + + if($client->objectExists(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy"))) + throw new Exception("found ".$keyprefix."EOFileCopy"); + if($client->objectExists(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOFileCopy.instruction"))) + throw new Exception("found ".$keyprefix."EOFileCopy.instruction"); +} +function rangeGetAndCheckMd5($client,$bucket,$key,$file,$expectedMd5){ + $args = array("Bucket"=>$bucket,"Key"=>$key); + $meta = $client->getObjectMeta($args); + $contentlength = $meta["ObjectMeta"]["Content-Length"]; + + $filelist = array(); + + for($begin = 0;$begin <$contentlength;){ + $index = rand((int)($contentlength/20),(int)($contentlength/10)); + $range = array("start"=>$begin,"end"=>$begin+$index); + $destFile = $file.$begin."-".($begin+$index); + array_push($filelist,$destFile); + $begin += ($index+1); + $args = array( + "Bucket"=>$bucket, + "Key"=>$key, + "Range"=>$range, + "WriteTo"=>$destFile + ); + $client->getObject($args); + } + + foreach ($filelist as $key => $value) { + $handle = fopen($value,"r"); + $size = filesize($value); + if($size > 0){ + $content = fread($handle,$size); + file_put_contents($file,$content,FILE_APPEND); + } + fclose($handle); + @unlink($value); + } + $md5 = base64_encode(md5_file($file)); + if($md5 != $expectedMd5) + throw new Exception("file md5 check error expected ".$expectedMd5." ,actual ".$md5, 1); + @unlink($file); +} diff --git a/src/service/ksyun/bin/samples/TestEncryptionClientMeta.php b/src/service/ksyun/bin/samples/TestEncryptionClientMeta.php new file mode 100644 index 0000000..d38a4b4 --- /dev/null +++ b/src/service/ksyun/bin/samples/TestEncryptionClientMeta.php @@ -0,0 +1,136 @@ +$bucket, + "Key"=>$keyprefix."EOMeta", + "ACL"=>"public-read", + "Content"=>$content + ); + $client->putObjectByContent($args); + rangeGetAndCheckMd5($client,$bucket,$keyprefix."EOMeta", + "D://testdown/down",base64_encode(md5($args["Content"]))); + } +} +function putObjectByFileAndGetObjectUsingMeta($client,$bucket,$keyprefix){ + + $args = array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOMeta", + "ACL"=>"public-read", + "Content"=>array( + "content"=>"D://IMG.jpg" + ) + ); + $client->putObjectByFile($args); + rangeGetAndCheckMd5($client,$bucket,$keyprefix."EOMeta", + "D://testdown/down",base64_encode(md5_file("D://IMG.jpg"))); +} +function multipartUpload($client,$bucket,$keyprefix){ + //初始化分开上传,获取uploadid + $args = array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOMeta", + ); + $uploadid = $client->initMultipartUpload($args); + $uploadid = $uploadid["UploadId"];//获取到uploadid + //开始上传 + + $file = "D://IMG.jpg";//要上传的文件 + $partsize = 1024*100; + $resource = fopen($file,"r"); + $stat = fstat($resource); + $total = $stat["size"];//获取文件的总大小 + fclose($resource); + $count = (int)(($total-1)/$partsize)+1;//计算文件需要分几块上传 + for($i = 0;$i < $count;$i++){ + //依次上传每一块 + echo "upload".$i."\r\n"; + $args=array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOMeta", + "LastPart"=>($i===$count-1), + "Options"=>array( + "partNumber"=>$i+1, + "uploadId"=>$uploadid + ), + "ObjectMeta"=>array( + "Content-Length"=>min($partsize,$total-$partsize*$i)//每次上传$partsize大小 + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>$partsize*$i//跳过之前已经上传的 + ) + ); + $etag = $client->uploadPart($args); + $etag = $etag["ETag"]; + } + $parts = $client->listParts(array("Bucket"=>$bucket,"Key"=>$keyprefix."EOMeta","Options"=>array("uploadId"=>$uploadid))); + //结束上传 + $args=array( + "Bucket"=>$bucket, + "Key"=>$keyprefix."EOMeta", + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"]//使用之前列出的块完成分开上传 + ); + $result = $client->completeMultipartUpload($args); + + rangeGetAndCheckMd5($client,$bucket,$keyprefix."EOMeta", + "D://testdown/down",base64_encode(md5_file("D://IMG.jpg"))); +} +function rangeGetAndCheckMd5($client,$bucket,$key,$file,$expectedMd5){ + $args = array("Bucket"=>$bucket,"Key"=>$key); + $meta = $client->getObjectMeta($args); + $contentlength = $meta["ObjectMeta"]["Content-Length"]; + + $filelist = array(); + + for($begin = 0;$begin <$contentlength;){ + $index = rand((int)($contentlength/20),(int)($contentlength/10)); + $range = array("start"=>$begin,"end"=>$begin+$index); + $destFile = $file.$begin."-".($begin+$index); + array_push($filelist,$destFile); + $begin += ($index+1); + $args = array( + "Bucket"=>$bucket, + "Key"=>$key, + "Range"=>$range, + "WriteTo"=>$destFile + ); + $client->getObject($args); + } + + foreach ($filelist as $key => $value) { + $handle = fopen($value,"r"); + $size = filesize($value); + if($size > 0){ + $content = fread($handle,$size); + file_put_contents($file,$content,FILE_APPEND); + } + fclose($handle); + @unlink($value); + } + $md5 = base64_encode(md5_file($file)); + if($md5 != $expectedMd5) + throw new Exception("file md5 check error expected ".$expectedMd5." ,actual ".$md5, 1); + @unlink($file); +} diff --git a/src/service/ksyun/bin/samples/secret.key b/src/service/ksyun/bin/samples/secret.key new file mode 100644 index 0000000..812d1e6 --- /dev/null +++ b/src/service/ksyun/bin/samples/secret.key @@ -0,0 +1,2 @@ +U깐L| +we} p/^@H( \ No newline at end of file diff --git a/src/service/ksyun/bin/unit/PUnit.php b/src/service/ksyun/bin/unit/PUnit.php new file mode 100644 index 0000000..6b00e75 --- /dev/null +++ b/src/service/ksyun/bin/unit/PUnit.php @@ -0,0 +1,60 @@ +getMethods() as $key=>$methodObj){ + if($methodObj->isPrivate()) + $methods[$key]['type'] = 'private'; + elseif($methodObj->isProtected()) + $methods[$key]['type'] = 'protected'; + else + $methods[$key]['type'] = 'public'; + $methods[$key]['name'] = $methodObj->name; + $methods[$key]['class'] = $methodObj->class; + } + $before = NULL; + $after = NULL; + foreach ($methods as $method) { + if($method["class"] != "PUnit"&&$method["name"] == "before"){ + $before = $method; + } + if($method["class"] != "PUnit"&&$method["name"] == "after"){ + $after = $method; + } + } + $error = array(); + $success = array(); + foreach ($methods as $method) { + if($method["class"] != "PUnit"&&substr($method["name"],0,4) == "test"){ + if($torun !== NULL){ + if(!in_array($method["name"],$torun)) + continue; + } + try{ + if($method["type"] == "public"){ + $log = new Logger(); + $log->info("Run unit --->".$method["name"]); + if($before!=NULL) + $this->$before["name"](); + $this->$method["name"](); + array_push($success,$method["name"]); + } + }catch(Exception $e){ + $error[$method["name"]]="".$e; + } + } + } + echo "\r\nPHP Unit-----------error"."\r\n"; + print_r($error); + echo "PHP Unit-----------result"."\r\n"; + echo "total:".(count($success)+count($error)).",success:".count($success).",error:".count($error)."\r\n"; + + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/unit/Test.php b/src/service/ksyun/bin/unit/Test.php new file mode 100644 index 0000000..737d51e --- /dev/null +++ b/src/service/ksyun/bin/unit/Test.php @@ -0,0 +1,922 @@ +client=new Ks3Client($this->accesskey,$this->secrectkey); + $this->cachedir=KS3_API_PATH.DIRECTORY_SEPARATOR."unit".DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR; + $filename = "secret.key"; + $handle = fopen($filename, "r"); + $sseckey = fread($handle, filesize ($filename)); + fclose($handle); + $this->sseckey = $sseckey; + $this->encryptionClient = new Ks3EncryptionClient($this->accesskey,$this->secrectkey,$sseckey); + } + public function before(){ + if($this->client->bucketExists(array("Bucket"=>$this->bucket))){ + $keys = array(); + $objects = $this->client->listObjects(array("Bucket"=>$this->bucket)); + foreach ($objects["Contents"] as $object) { + array_push($keys, $object["Key"]); + } + $this->client->deleteObjects(array("Bucket"=>$this->bucket,"DeleteKeys"=>$keys)); + }else{ + $this->client->createBucket(array("Bucket"=>$this->bucket)); + } + } + public function testListBuckets(){ + $buckets = $this->client->listBuckets(); + $found = FALSE; + foreach ($buckets as $bucket) { + if($bucket["Name"] == $this->bucket) + $found = TRUE; + } + if(!$found) + throw new Exception("list buckets expected found ".$this->bucket.",but not found"); + + } + public function testDeleteBucket(){ + $this->client->putObjectByContent(array("Bucket"=>$this->bucket,"Key"=>"test","Content"=>"")); + $ex = NULL; + try{ + $this->client->deleteBucket(array("Bucket"=>$this->bucket)); + }catch(Exception $e){ + $ex = $e; + } + if($ex == NULL||!($ex->errorCode === "BucketNotEmpty")){ + throw new Exception("delete bucket expected BucketNotEmpty but ".$ex); + } + } + public function testBucketCORS(){ + $this->client->setBucketCORS($args = array( + "Bucket"=>$this->bucket, + "CORS"=>array( + array( + "AllowedMethod"=>array("GET","PUT"), + "AllowedOrigin"=>array("http://www.kingsoft.com"), + "AllowedHeader"=>array("*"), + "ExposeHeader"=>array("*"), + "MaxAgeSeconds"=>10 + ), + array( + "AllowedMethod"=>array("GET","PUT"), + "AllowedOrigin"=>array("*"), + "AllowedHeader"=>array("*"), + "ExposeHeader"=>array("*"), + "MaxAgeSeconds"=>10 + ) + ))); + $cors = $this->client->getBucketCORS(array("Bucket"=>$this->bucket)); + $this->assertEquals(count($cors),2,"bucket cors count "); + $this->client->deleteBucketCORS(array("Bucket"=>$this->bucket)); + $cors = $this->client->getBucketCORS(array("Bucket"=>$this->bucket)); + $this->assertEquals(count($cors),0,"bucket cors count "); + } + public function testCreateBucket(){ + $ex = NULL; + try{ + $this->client->createBucket(array("Bucket"=>$this->bucket)); + }catch(Exception $e){ + $ex = $e; + } + if($ex == NULL||!($ex->errorCode === "BucketAlreadyExists")){ + throw new Exception("create bucket expected BucketAlreadyExists but ".$ex); + } + } + public function testACL(){ + $this->client->setBucketAcl(array("Bucket"=>$this->bucket,"ACL"=>"public-read")); + $acl = $this->client->getBucketAcl(array("Bucket"=>$this->bucket)); + $this->assertEquals($acl,"public-read","bucket acl"); + } + public function testBucketLogging(){ + $this->client->setBucketLogging(array( + "Bucket"=>$this->bucket, + "BucketLogging"=>array( + "Enable"=>TRUE, + "TargetBucket"=>$this->bucket, + "TargetPrefix"=>"X-KSS" + ) + )); + $logging = $this->client->getBucketLogging(array("Bucket"=>$this->bucket)); + $this->assertEquals($logging["Enable"],TRUE,"bucket logging enable"); + + $this->client->setBucketLogging(array( + "Bucket"=>$this->bucket, + "BucketLogging"=>array( + "Enable"=>FALSE,//是否开启 + ) + )); + $logging = $this->client->getBucketLogging(array("Bucket"=>$this->bucket)); + $this->assertEquals($logging["Enable"],FALSE,"bucket logging enable"); + } + public function testBucketLocation(){ + $location = $this->client->getBucketLocation(array("Bucket"=>$this->bucket)); + $this->assertEquals($location,"HANGZHOU","bucket location "); + } + public function testPutObjectByContentAndGetObjectContent(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>"1234",//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array( + "Content-Type"=>"application/xml", + "Content-Length"=>3 + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ) + ); + $this->client->putObjectByContent($args); + $this->assertEquals($this->client->objectExists(array("Bucket"=>$this->bucket,"Key"=>$this->key)),TRUE,"object exists "); + $meta = $this->client->getObjectMeta(array("Bucket"=>$this->bucket,"Key"=>$this->key)); + $this->assertEquals($meta["UserMeta"]["x-kss-meta-test"],"test","x-kss-meta-test"); + $this->assertEquals($meta["ObjectMeta"]["Content-Type"],"application/xml","Content-Type"); + $this->assertEquals($meta["ObjectMeta"]["Content-Length"],3,"Content-Length"); + $this->assertEquals($this->client->getObjectAcl(array("Bucket"=>$this->bucket,"Key"=>$this->key)),"public-read","object acl "); + + $s3Object = $this->client->getObject(array("Bucket"=>$this->bucket,"Key"=>$this->key)); + $this->assertEquals($s3Object["Content"],"123","s3 object content"); + $meta = $s3Object["Meta"]; + $this->assertEquals($meta["UserMeta"]["x-kss-meta-test"],"test","x-kss-meta-test"); + $this->assertEquals($meta["ObjectMeta"]["Content-Type"],"application/xml","Content-Type"); + $this->assertEquals($meta["ObjectMeta"]["Content-Length"],3,"Content-Length"); + + } + public function testPutObjectByFile(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>array( + "content"=>$this->cachedir."test_file" + ),//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array( + "Content-Type"=>"application/xml", + "Content-Length"=>100 + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ) + ); + $this->client->putObjectByFile($args); + $this->assertEquals($this->client->objectExists(array("Bucket"=>$this->bucket,"Key"=>$this->key)),TRUE,"object exists "); + $meta = $this->client->getObjectMeta(array("Bucket"=>$this->bucket,"Key"=>$this->key)); + $this->assertEquals($meta["UserMeta"]["x-kss-meta-test"],"test","x-kss-meta-test"); + $this->assertEquals($meta["ObjectMeta"]["Content-Type"],"application/xml","Content-Type"); + $this->assertEquals($meta["ObjectMeta"]["Content-Length"],100,"Content-Length"); + $this->assertEquals($this->client->getObjectAcl(array("Bucket"=>$this->bucket,"Key"=>$this->key)),"public-read","object acl "); + } + public function testObjectAcl(){ + $this->client->putObjectByContent(array("Bucket"=>$this->bucket,"Key"=>$this->key, +"Content"=>"1234","ACL"=>"private")); + $this->assertEquals($this->client->getObjectAcl(array("Bucket"=>$this->bucket,"Key"=>$this->key)),"private","object acl"); + $this->client->setObjectAcl(array("Bucket"=>$this->bucket,"Key"=>$this->key,"ACL"=>"public-read")); + $this->assertEquals($this->client->getObjectAcl(array("Bucket"=>$this->bucket,"Key"=>$this->key)),"public-read","object acl"); + } + public function testDeleteObject(){ + $this->client->putObjectByContent(array("Bucket"=>$this->bucket,"Key"=>$this->key, +"Content"=>"1234")); + $this->client->deleteObject(array("Bucket"=>$this->bucket,"Key"=>$this->key)); + $this->assertEquals($this->client->objectExists(array("Bucket"=>$this->bucket,"Key"=>$this->key)),FALSE,"object exits"); + } + public function testDeleteObjects(){ + $this->client->putObjectByContent(array("Bucket"=>$this->bucket,"Key"=>$this->key, +"Content"=>"1234")); + $this->client->deleteObjects(array("Bucket"=>$this->bucket,"DeleteKeys"=>array($this->key))); + $this->assertEquals($this->client->objectExists(array("Bucket"=>$this->bucket,"Key"=>$this->key)),FALSE,"object exits"); + } + public function testCopyObject(){ + $this->client->putObjectByContent(array("Bucket"=>$this->bucket,"Key"=>$this->key, +"Content"=>"1234")); + $this->client->copyObject(array("Bucket"=>$this->bucket,"Key"=>$this->key_copy,"CopySource"=>array("Bucket"=>$this->bucket,"Key"=>$this->key))); + $this->assertEquals($this->client->objectExists(array("Bucket"=>$this->bucket,"Key"=>$this->key)),TRUE,"object exits"); + $this->assertEquals($this->client->objectExists(array("Bucket"=>$this->bucket,"Key"=>$this->key_copy)),TRUE + ,"object exits"); + } + public function testPutAndGetObject(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>array( + "content"=>$this->cachedir."test_file" + ),//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array( + "Content-Type"=>"application/xml", + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ) + ); + $this->client->putObjectByFile($args); + $this->client->getObject(array("Bucket"=>$this->bucket,"Key"=>$this->key,"WriteTo"=>$this->cachedir."down")); + $md5 = md5_file($this->cachedir."down"); + $md5pre = md5_file($this->cachedir."test_file"); + @unlink($this->cachedir."down"); + $this->assertEquals($md5,$md5pre,"contentmd5"); + } + public function testPutAndGetObjectRanges(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>array( + "content"=>$this->cachedir."test_file" + ),//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array( + "Content-Type"=>"application/xml", + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ) + ); + $this->client->putObjectByFile($args); + rangeGetAndCheckMd5($this->client,$this->bucket,$this->key,$this->cachedir."down",md5_file($this->cachedir."test_file")); + } + public function testInitAndAbortMultipart(){ + $initResult = $this->client->initMultipartUpload(array("Bucket"=>$this->bucket,"Key"=>$this->key)); + $uid = $initResult["UploadId"]; + $listParts = $this->client->listParts(array("Bucket"=>$this->bucket,"Key"=>$this->key,"Options"=>array("uploadId"=>$uid))); + $this->client->abortMultipartUpload(array("Bucket"=>$this->bucket,"Key"=>$this->key,"Options"=>array("uploadId"=>$uid))); + $ex = NULL; + try{ + $this->client->listParts(array("Bucket"=>$this->bucket,"Key"=>$this->key,"Options"=>array("uploadId"=>$uid))); + }catch(Exception $e){ + $ex = $e; + } + if($ex == NULL||!($ex->errorCode === "NoSuchUpload")){ + throw new Exception("create bucket expected NoSuchUpload but ".$ex); + } + } + public function testMultipartUpload(){ + generateFile(1024*1024,$this->cachedir."multi"); + //初始化分开上传,获取uploadid + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "ACL"=>"public-read", + "UserMeta"=>array( + "x-kss-meta-test"=>"example" + ), + "ObjectMeta"=>array( + "Content-Type"=>"application/xml" + ) + ); + $uploadid = $this->client->initMultipartUpload($args); + $uploadid = $uploadid["UploadId"];//获取到uploadid + //开始上传 + $file = $this->cachedir."multi";//要上传的文件 + $partsize = 1024*100; + $resource = fopen($file,"r"); + $stat = fstat($resource); + $total = $stat["size"];//获取文件的总大小 + fclose($resource); + $count = (int)(($total-1)/$partsize)+1;;//计算文件需要分几块上传 + for($i = 0;$i < $count;$i++){ + //依次上传每一块 + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array( + "partNumber"=>$i+1, + "uploadId"=>$uploadid + ), + "ObjectMeta"=>array( + "Content-Length"=>min($partsize,$total-$partsize*$i)//每次上传$partsize大小 + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>$partsize*$i//跳过之前已经上传的 + ) + ); + $etag = $this->client->uploadPart($args); + $etag = $etag["ETag"]; + } + $parts = $this->client->listParts(array("Bucket"=>$this->bucket,"Key"=>$this->key,"Options"=>array("uploadId"=>$uploadid))); + //结束上传 + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"]//使用之前列出的块完成分开上传 + ); + $result = $this->client->completeMultipartUpload($args); + $this->assertEquals($this->client->getObjectAcl(array("Bucket"=>$this->bucket,"Key"=>$this->key)),"public-read","object acl"); + $meta = $this->client->getObjectMeta(array("Bucket"=>$this->bucket,"Key"=>$this->key)); + $this->assertEquals($meta["ObjectMeta"]["Content-Type"],"application/xml","Content-Type"); + $this->assertEquals($meta["ObjectMeta"]["Content-Length"],filesize($this->cachedir."multi"),"Content-Length"); + $this->assertEquals($meta["UserMeta"]["x-kss-meta-test"],"example","x-kss-meta-test"); + rangeGetAndCheckMd5($this->client,$this->bucket,$this->key,$this->cachedir."down",md5_file($this->cachedir."multi")); + @unlink($this->cachedir."multi"); + } + public function testListBucketsPresignedUrl(){ + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"GET", + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"text/plain") + )); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("GET"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"list buckets status code"); + } + public function testHeadBucketPresignedUrl(){ + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"HEAD", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("HEAD"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"head bucket status code"); + } + public function testDeleteBucketPresignedUrl(){ + $this->client->putObjectByContent(array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>"123" + ) + ); + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"DELETE", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("DELETE"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,409,"delete bucket status code"); + } + public function testGetBucketAclPresignedUrl(){ + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"GET", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10,"acl"=>NULL), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("GET"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"get bucket acl status code"); + } + public function testPutBucketPresignedUrl(){ + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"PUT", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("PUT"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,409,"delete bucket status code"); + } + public function testPutBucketAclPresignedUrl(){ + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"PUT", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10,"acl"=>NULL), + "Headers"=>array("Content-Type"=>"text/plain","x-kss-acl"=>"public-read") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("PUT"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->add_header("x-kss-acl","public-read"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"put bucket acl status code"); + $this->assertEquals($this->client->getBucketAcl(array("Bucket"=>$this->bucket)),"public-read","bucket acl"); + } + public function testListObjectsPresignedUrl(){ + $url = $this->client->generatePresignedUrl(array( + "Method"=>"GET", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10,"delimiter"=>"/"), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("GET"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"list objects status code"); + } + public function testGetBucketLoggingPresignedUrl(){ + $url = $this->client->generatePresignedUrl(array( + "Method"=>"GET", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10,"logging"=>""), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("GET"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"get bucket logging status code"); + } + public function testPutBucketLoggingPresignedUrl(){ + $xml = new SimpleXmlElement(''); + $xml = $xml->asXml(); + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"PUT", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10,"logging"=>NULL), + "Headers"=>array("Content-Type"=>"application/xml") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("PUT"); + $httpRequest->add_header("Content-Type","application/xml"); + $httpRequest->add_header("Content-Length",strlen($xml)); + $httpRequest->request_body=$xml; + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"put bucket logging status code"); + } + public function testGetBucketLocationPresignedUrl(){ + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"GET", + "Bucket"=>$this->bucket, + "Options"=>array("Expires"=>60*10,"location"=>NULL), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("GET"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"get bucket location status code"); + } + public function testDeleteObjectPresignedUrl(){ + $this->client->putObjectByContent(array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>"123" + ) + ); + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"DELETE", + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("DELETE"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,204,"delete object status code"); + } + public function testGetObjectPresignedUrl(){ + $this->client->putObjectByContent(array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>"123" + ) + ); + $url = $this->client->generatePresignedUrl( + array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("GET"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"get object status code"); + $this->assertEquals($body,"123","get object body"); + } + public function testPutObjectPresignedUrl(){ + $body = "123"; + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"PUT", + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"application/ocet-stream") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("PUT"); + $httpRequest->add_header("Content-Type","application/ocet-stream"); + $httpRequest->add_header("Content-Length",strlen($body)); + $httpRequest->request_body=$body; + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"put object status code"); + } + public function testHeadObjectPresignedUrl(){ + $this->testPutObjectPresignedUrl(); + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"HEAD", + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("Expires"=>60*10), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("HEAD"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"head object status code"); + } + public function testGetObjectAclPresignedUrl(){ + $this->testPutObjectPresignedUrl(); + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"GET", + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("Expires"=>60*10,"acl"=>NULL), + "Headers"=>array("Content-Type"=>"text/plain") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("GET"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"get object acl status code"); + } + public function testPutObjectAclPresignedUrl(){ + $this->testPutObjectPresignedUrl(); + $url = $this->client->generatePresignedUrl( + array( + "Method"=>"PUT", + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("Expires"=>60*10,"acl"=>NULL), + "Headers"=>array("Content-Type"=>"text/plain","x-kss-acl"=>"public-read") + ) + ); + $httpRequest = new RequestCore($url); + $httpRequest->set_method("PUT"); + $httpRequest->add_header("Content-Type","text/plain"); + $httpRequest->add_header("x-kss-acl","public-read"); + $httpRequest->send_request(); + $body = $httpRequest->get_response_body (); + $this->assertEquals($httpRequest->get_response_code()." body:".$body,200,"put object acl status code"); + } + public function testPutObjectSSEAndGetHeadObject(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>"12345",//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array(//设置object的元数据,可以设置"Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires"。当设置了Content-Length时,请勿大于实际长度,如果小于实际长度,将只上传部分内容。 + "Content-Type"=>"binay/ocet-stream" + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ), + "SSE"=>array( + "Algm"=>"AES256"//暂时支持AES256 + ) + ); + $result = $this->client->putObjectByContent($args); + $this->assertEquals($result["SSEAlgm"],"AES256"); + + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key + ); + $result = $this->client->getObjectMeta($args); + $this->assertEquals($result["ObjectMeta"]["SSEAlgm"],"AES256"); + rangeGetAndCheckMd5($this->client,$this->bucket,$this->key,$this->cachedir."down",md5("12345")); + } + public function testPutObjectSSECAndGetHeadObject(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>"12345",//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array(//设置object的元数据,可以设置"Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires"。当设置了Content-Length时,请勿大于实际长度,如果小于实际长度,将只上传部分内容。 + "Content-Type"=>"binay/ocet-stream" + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ), + "SSEC"=>array( + "Key"=>$this->sseckey + ) + ); + $result = $this->client->putObjectByContent($args); + $this->assertEquals($result["SSECAlgm"],"AES256"); + $this->assertEquals($result["SSECKeyMD5"],Utils::hex_to_base64(md5($this->sseckey))); + + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "SSEC"=>array( + "Key"=>$this->sseckey + ) + ); + $result = $this->client->getObjectMeta($args); + $this->assertEquals($result["ObjectMeta"]["SSECAlgm"],"AES256"); + $this->assertEquals($result["ObjectMeta"]["SSECKeyMD5"],Utils::hex_to_base64(md5($this->sseckey))); + + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "WriteTo"=>$this->cachedir."down", //文件保存路径,必须提供。可以是resource + "SSEC"=>array( + "Key"=>$this->sseckey + ) + ); + $this->client->getObject($args); + $this->assertEquals("12345",file_get_contents($this->cachedir."down")); + @unlink($this->cachedir."down"); + } + public function testMultipartUploadSSE(){ + $file = $this->cachedir."test_file"; + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "SSE"=>array( + "Algm"=>"AES256" + ) + ); + $uploadid = $this->client->initMultipartUpload($args); + + $this->assertEquals($uploadid["SSEAlgm"],"AES256"); + + $uploadid = $uploadid["UploadId"]; + //开始上传 + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array( + "partNumber"=>1, + "uploadId"=>$uploadid + ), + "Content"=>array( + "content"=>$file + ) + ); + $etag = $this->client->uploadPart($args); + + $this->assertEquals($etag["SSEAlgm"],"AES256"); + $etag = $etag["ETag"]; + + $parts = $this->client->listParts(array("Bucket"=>$this->bucket,"Key"=>$this->key,"Options"=>array("uploadId"=>$uploadid))); + //结束上传 + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"], + ); + $result = $this->client->completeMultipartUpload($args); + $this->assertEquals($result["SSEAlgm"],"AES256"); + } + public function testMultipartUploadSSEC(){ + $file = $this->cachedir."test_file"; + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "SSEC"=>array( + "Key"=>$this->sseckey + ) + ); + $uploadid = $this->client->initMultipartUpload($args); + + $this->assertEquals($uploadid["SSECAlgm"],"AES256"); + $this->assertEquals($uploadid["SSECKeyMD5"],Utils::hex_to_base64(md5($this->sseckey))); + + $uploadid = $uploadid["UploadId"]; + //开始上传 + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array( + "partNumber"=>1, + "uploadId"=>$uploadid + ), + "Content"=>array( + "content"=>$file + ), + "SSEC"=>array( + "Key"=>$this->sseckey + ) + ); + $etag = $this->client->uploadPart($args); + + $this->assertEquals($etag["SSECAlgm"],"AES256"); + $this->assertEquals($etag["SSECKeyMD5"],Utils::hex_to_base64(md5($this->sseckey))); + + $etag = $etag["ETag"]; + + $parts = $this->client->listParts(array("Bucket"=>$this->bucket,"Key"=>$this->key,"Options"=>array("uploadId"=>$uploadid))); + //结束上传 + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"], + ); + $result = $this->client->completeMultipartUpload($args); + $this->assertEquals($result["SSECAlgm"],"AES256"); + $this->assertEquals($result["SSECKeyMD5"],Utils::hex_to_base64(md5($this->sseckey))); + } + public function testCopySSECObject(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Content"=>"12345",//要上传的内容 + "ACL"=>"public-read",//可以设置访问权限,合法值,private、public-read + "ObjectMeta"=>array(//设置object的元数据,可以设置"Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires"。当设置了Content-Length时,请勿大于实际长度,如果小于实际长度,将只上传部分内容。 + "Content-Type"=>"binay/ocet-stream" + ), + "UserMeta"=>array(//可以设置object的用户元数据,需要以x-kss-meta-开头 + "x-kss-meta-test"=>"test" + ), + "SSEC"=>array( + "Key"=>$this->sseckey + ) + ); + $result = $this->client->putObjectByContent($args); + + $args = array( + "Bucket"=>$this->bucket, + "Key"=>"copy".$this->key_copy, + "CopySource"=>array( + "Bucket"=>$this->bucket, + "Key"=>$this->key + ), + "SSECSource"=>array( + "Key"=>$this->sseckey + ), + "SSEC"=>array( + "Key"=>$this->sseckey + ) + ); + $result = $this->client->copyObject($args); + } + public function testPutObjectByContentAndGetObjectUsingEncyptionMeta(){ + for($i = 45 ;$i < 60;$i++){ + + $content = EncryptionUtil::genereateOnceUsedKey($i); + + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "ACL"=>"public-read", + "Content"=>$content + ); + $this->encryptionClient->putObjectByContent($args); + rangeGetAndCheckMd5($this->encryptionClient,$this->bucket,$this->key, + $this->cachedir."down",md5($args["Content"])); + } + } + public function testPutObjectByFileAndGetObjectUsingEncyptionMeta(){ + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "ACL"=>"public-read", + "Content"=>array( + "content"=>$this->cachedir."test_file" + ) + ); + $this->encryptionClient->putObjectByFile($args); + rangeGetAndCheckMd5($this->encryptionClient,$this->bucket,$this->key, + $this->cachedir."down",md5_file($this->cachedir."test_file")); + } + public function testMultipartUploadUsingEncyptionMeta(){ + generateFile(1024*1024,$this->cachedir."multi"); + //初始化分开上传,获取uploadid + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + ); + $uploadid = $this->encryptionClient->initMultipartUpload($args); + $uploadid = $uploadid["UploadId"];//获取到uploadid + //开始上传 + + $file = $this->cachedir."multi";//要上传的文件 + $partsize = 1024*100; + $resource = fopen($file,"r"); + $stat = fstat($resource); + $total = $stat["size"];//获取文件的总大小 + fclose($resource); + $count = (int)(($total-1)/$partsize)+1;//计算文件需要分几块上传 + for($i = 0;$i < $count;$i++){ + //依次上传每一块 + echo "upload".$i."\r\n"; + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "LastPart"=>($i===$count-1), + "Options"=>array( + "partNumber"=>$i+1, + "uploadId"=>$uploadid + ), + "ObjectMeta"=>array( + "Content-Length"=>min($partsize,$total-$partsize*$i)//每次上传$partsize大小 + ), + "Content"=>array( + "content"=>$file, + "seek_position"=>$partsize*$i//跳过之前已经上传的 + ) + ); + $etag = $this->encryptionClient->uploadPart($args); + $etag = $etag["ETag"]; + } + $parts = $this->encryptionClient->listParts(array("Bucket"=>$this->bucket,"Key"=>$this->key,"Options"=>array("uploadId"=>$uploadid))); + //结束上传 + $args=array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "Options"=>array("uploadId"=>$uploadid), + "Parts"=>$parts["Parts"]//使用之前列出的块完成分开上传 + ); + $result = $this->encryptionClient->completeMultipartUpload($args); + + rangeGetAndCheckMd5($this->encryptionClient,$this->bucket,$this->key, + $this->cachedir."down",md5_file($file)); + @unlink($this->cachedir."multi"); + } + public function testPutObjectByContentAndGetObject(){ + @unlink($this->cachedir."down"); + $content = EncryptionUtil::genereateOnceUsedKey(500); + $args = array( + "Bucket"=>$this->bucket, + "Key"=>$this->key, + "ACL"=>"public-read", + "Content"=>$content + ); + $this->encryptionClient->putObjectByContent($args); + $start = (int)rand(0,520); + $end = (int)rand($start,520); + $s3Object = $this->encryptionClient->getObject( + array("Bucket"=>$this->bucket,"Key"=>$this->key, + "Range"=>"bytes=".$start."-".$end) + ); + $this->assertEquals(substr($content,$start,$end-$start+1),$s3Object["Content"]); + } + public function test01(){ + $this->client->listObjects(array("Bucket"=>$this->bucket)); + } +} +$test = new SDKTest(); +$methods = array( + //"testRangeGetFile", + "testObjectAcl" + ); +$test->run(); +?> diff --git a/src/service/ksyun/bin/unit/TestUtil.php b/src/service/ksyun/bin/unit/TestUtil.php new file mode 100644 index 0000000..9d5cba5 --- /dev/null +++ b/src/service/ksyun/bin/unit/TestUtil.php @@ -0,0 +1,53 @@ +$bucket,"Key"=>$key); + $meta = $client->getObjectMeta($args); + $contentlength = $meta["ObjectMeta"]["Content-Length"]; + + $filelist = array(); + + for($begin = 0;$begin <$contentlength;){ + $index = rand((int)($contentlength/20),(int)($contentlength/4)); + $range = array("start"=>$begin,"end"=>$begin+$index); + $destFile = $file.$begin."-".($begin+$index); + array_push($filelist,$destFile); + $begin += ($index+1); + $args = array( + "Bucket"=>$bucket, + "Key"=>$key, + "Range"=>$range, + "WriteTo"=>$destFile + ); + $client->getObject($args); + } + + foreach ($filelist as $key => $value) { + $handle = fopen($value,"r"); + $size = filesize($value); + if($size > 0){ + $content = fread($handle,$size); + file_put_contents($file,$content,FILE_APPEND); + } + fclose($handle); + //@unlink($value); + } + $md5 = md5_file($file); + //@unlink($file); + if($md5 != $expectedMd5) + throw new Exception("file md5 check error expected ".$expectedMd5." ,actual ".$md5, 1); + foreach ($filelist as $key => $value) { + @unlink($value); + } + @unlink($file); +} +function generateFile($sizeInBytes,$destFile){ + for($i = 0;$i < $sizeInBytes/10;$i++){ + $randpwd = ""; + for ($j = 0; $j < 10; $j++) + { + $randpwd .= chr(mt_rand(33, 126)); + } + file_put_contents($destFile,$randpwd,FILE_APPEND); + } +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/unit/cache/test_file b/src/service/ksyun/bin/unit/cache/test_file new file mode 100644 index 0000000..ef14a4e --- /dev/null +++ b/src/service/ksyun/bin/unit/cache/test_file @@ -0,0 +1,2176 @@ +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> +array( + "redirect"=>"listBuckets" + ), + "listBuckets"=> array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListBucketsHandler" + ), + "deleteBucket"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteBucketCORS"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "createBucket"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "body"=>Array("builder"=>"LocationBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketCORS"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->HeaderAuthSigner", + "subResource"=>"cors", + "body"=>Array("builder"=>"CORSBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "setBucketLogging"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"logging", + "body"=>Array("builder"=>"BucketLoggingBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listObjects" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "queryParams"=>array("Options->prefix","Options->delimiter","Options->marker","Options->max-keys"), + "handler"=>"ErrorResponseHandler->ListObjectsHandler" + ), + "getBucketAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "getBucketCORS"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"cors", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketCORSHandler" + ), + "getBucketLocation"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"location", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLocationHandler" + ), + "getBucketLogging"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"logging", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetBucketLoggingHandler" + ), + "listMutipartUploads"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"uploads", + "queryParams"=>array("Options->max-uploads","Options->key-marker","Options->prefix","Options->upload-id-​marker","Options->delimiter"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListMutipartUploadsHandler" + ), + "bucketExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "putObjectByContent"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + //将ContentMD5Signer放在最后的原因是,ContentMD5需要根据Content-Length计算 + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ContentLengthSigner->ObjectMetaSigner->ContentMD5Signer->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("position"=>"Content") + ), + "putObjectByFile"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->ObjectMetaSigner->UserMetaSigner->AdpSigner->CallBackSigner->SSESigner->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "setObjectAcl"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->ACLSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "subResource"=>"acl", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "copyObject"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->CopySourceSigner->DefaultContentTypeSigner->SSESigner->SSECSigner->SSECSourceSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->CopyHandler" + ), + "getObjectMeta"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ObjectMetaHandler" + ), + "objectExists"=>array( + "method"=>"HEAD", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ExistsHandler" + ), + "deleteObject"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "deleteObjects"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>FALSE, + "subResource"=>"delete", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentMD5Signer->ContentLengthSigner->HeaderAuthSigner", + "body"=>array("builder"=>"DeleteObjectsBuilder"), + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObject"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->RangeSigner->SSECSigner->GetObjectSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "getObjectAcl" => array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"acl", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->GetAclHandler" + ), + "initMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"uploads", + "signer"=>"DefaultUserAgentSigner->ACLSigner->SuffixContentTypeSigner->MultipartObjectMetaSigner->UserMetaSigner->SSESigner->SSECSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->InitMultipartUploadHandler" + ), + "uploadPart"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","!Options->partNumber"), + //这个请求没有body,所以使用了ContentLengthSigner->ContentMD5Signer而没用ObjectMetaSigner + "signer"=>"DefaultUserAgentSigner->ACLSigner->StreamContentTypeSigner->ContentLengthSigner->ContentMD5Signer->SSECSigner->StreamUploadSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "abortMultipartUpload"=>array( + "method"=>"DELETE", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->BooleanHandler" + ), + "listParts"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId","Options->max-parts","Options->part-number​-marker"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->ListPartsHandler" + ), + "completeMultipartUpload"=>array( + "method"=>"POST", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->uploadId"), + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->ContentLengthSigner->AdpSigner->CallBackSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler", + "body"=>array("builder"=>"CompleteMultipartUploadBuilder") + ), + "generatePresignedUrl"=>array( + "method"=>"GET", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "queryParams"=>array("!Options->Expires","Options->response-content-type","Options->response-content-encoding","Options->response-content-disposition", + "Options->response-content-language","Options->response-expires","Options->response-cache-control"), + "signer"=>"QueryAuthSigner", + ), + "putAdp"=>array( + "method"=>"PUT", + "needBucket"=>TRUE, + "needObject"=>TRUE, + "subResource"=>"adp", + "signer"=>"DefaultUserAgentSigner->DefaultContentTypeSigner->AdpSigner->HeaderAuthSigner", + "handler"=>"ErrorResponseHandler->UploadHandler" + ), + "getAdp"=>array( + "method"=>"GET", + "needBucket"=>FALSE, + "needObject"=>TRUE, + "objectPostion"=>"TaskID",//专门为这个接口定义的属性 + "subResource"=>"queryadp", + "signer"=>"DefaultUserAgentSigner", + "handler"=>"ErrorResponseHandler->AdpHandler" + ) + ); +} +?> \ No newline at end of file diff --git a/src/service/ksyun/bin/unit/secret.key b/src/service/ksyun/bin/unit/secret.key new file mode 100644 index 0000000..812d1e6 --- /dev/null +++ b/src/service/ksyun/bin/unit/secret.key @@ -0,0 +1,2 @@ +U깐L| +we} p/^@H( \ No newline at end of file diff --git a/src/service/ksyun/bin/更新日志.txt b/src/service/ksyun/bin/更新日志.txt new file mode 100644 index 0000000..7e0772c --- /dev/null +++ b/src/service/ksyun/bin/更新日志.txt @@ -0,0 +1,24 @@ +V1.2.3 +1、copyObject接口支持回调 + +V1.2.2 +1、修复某些接口操作成功但返回布尔值不正确的问题,如deleteObject等 +2、更新sample中Ks3Client初始化时用户需要提供endpoint值 + +V1.2.1 +1、Ks3Client 初始化时用户需要提供endpoint值,详见http://ks3.ksyun.com/doc/api/index.html Region part +2、修复某些时候会出现Notice警告的bug + +V1.2 +1、常量配置项添加 KS3_API_前缀 +2、getObject的WriteTo不再是必要参数,当不提供该参数时,会直接返回文件内容。 +3、修复Ks3EncryptionClient分块下载可能出现的bug +4、优化获取文件大小的逻辑,windows下上传小文件,将不再需要COM组件 +5、修复不支持某些特殊字符的bug + +V1.1 +1、添加Ks3EncryptionClient,可以将数据加密之后再上传到服务器上。 +2、修复putObjectByFile可能出现的bug +3、SDK添加服务端加密的支持 + +V1.0 初始化版本 diff --git a/src/service/netease/NosService.php b/src/service/netease/NosService.php new file mode 100644 index 0000000..c76b24c --- /dev/null +++ b/src/service/netease/NosService.php @@ -0,0 +1,90 @@ +accessKeyId = $accessKeyId; + return $this; + } + + public function accessKeySecret(string $accessKeySecret) + { + $this->accessKeySecret = $accessKeySecret; + return $this; + } + + public function endpoint(string $endpoint) + { + $this->endpoint = $endpoint; + return $this; + } + + public function bucket(string $bucket) + { + $this->bucket = $bucket; + return $this; + } + + /** + * 获取配置信息 + * @return $this + */ + private function getConfig() + { + $this->accessKeyId = $this->app->config->get('dtapp.netease.nos.access_key_id'); + $this->accessKeySecret = $this->app->config->get('dtapp.netease.nos.access_key_secret'); + $this->endpoint = $this->app->config->get('dtapp.netease.nos.endpoint'); + $this->bucket = $this->app->config->get('dtapp.netease.nos.bucket'); + return $this; + } + + /** + * 上传文件 + * @param string $object + * @param string $filePath + * @return bool|string + */ + public function upload(string $object, string $filePath) + { + if (empty($this->accessKeyId)) $this->getConfig(); + if (empty($this->accessKeySecret)) $this->getConfig(); + if (empty($this->endpoint)) $this->getConfig(); + try { + $nosClient = new NosClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint); + if (empty($this->bucket)) $this->getConfig(); + $nosClient->uploadFile($this->bucket, $object, $filePath); + return $this->app->config->get('dtapp.netease.nos.url') . $object; + } catch (NosException $e) { + return false; + } + } +} diff --git a/src/service/ucloud/UfileService.php b/src/service/ucloud/UfileService.php new file mode 100644 index 0000000..6ea31a3 --- /dev/null +++ b/src/service/ucloud/UfileService.php @@ -0,0 +1,49 @@ +bucket = $bucket; + return $this; + } + + /** + * 上传文件 + * @param $object + * @param $filePath + * @return bool + */ + public function upload(string $object, string $filePath) + { + list($data, $err) = UCloud_PutFile($this->bucket, $object, $filePath); + if (($err)) return false; + return $this->app->config->get('dtapp.ucloud.ufile.url') . $object; + } +} diff --git a/src/service/ucloud/bin/CHANGELOG.md b/src/service/ucloud/bin/CHANGELOG.md new file mode 100644 index 0000000..e518d1f --- /dev/null +++ b/src/service/ucloud/bin/CHANGELOG.md @@ -0,0 +1,18 @@ +=========================== +===Version 1.0.0=== + * 支持普通上传 + * 支持表单上传 + * 支持分片上传 + * 支持删除文件 + * 支持秒传文件 + +===Version 1.0.1=== + * 强化 MimeType 检测功能 + * bugfix + +===Version 1.0.5=== +2015.10.19 + * fix digest bug +=== Version 1.0.6 === + * 新增append 接口 + * 上传key 去掉转义,保留原有格式 diff --git a/src/service/ucloud/bin/README.md b/src/service/ucloud/bin/README.md new file mode 100644 index 0000000..c967210 --- /dev/null +++ b/src/service/ucloud/bin/README.md @@ -0,0 +1,16 @@ +ucloud/conf.php 为配置文件,按需填写: + +- $UCLOUD_PROXY_SUFFIX = '.cn-bj.ufileos.com'; +- $UCLOUD_PUBLIC_KEY = 'paste your public key here'; +- $UCLOUD_PRIVATE_KEY = 'paste your private key here'; + + +Demo 目录中,包含各个接口的使用例子: +- append.php +- delete.php +- get.php +- multipart.php +- mupload.php +- put.php +- listobjects.php +- uploadhit.php diff --git a/src/service/ucloud/bin/v1/demo/append.php b/src/service/ucloud/bin/v1/demo/append.php new file mode 100644 index 0000000..4424fe4 --- /dev/null +++ b/src/service/ucloud/bin/v1/demo/append.php @@ -0,0 +1,21 @@ +ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} +echo "ETag: " . $data['ETag'] . "\n"; diff --git a/src/service/ucloud/bin/v1/demo/delete.php b/src/service/ucloud/bin/v1/demo/delete.php new file mode 100644 index 0000000..9a3359f --- /dev/null +++ b/src/service/ucloud/bin/v1/demo/delete.php @@ -0,0 +1,17 @@ +ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} + +echo "delete $bucket/$key success\n"; diff --git a/src/service/ucloud/bin/v1/demo/get.php b/src/service/ucloud/bin/v1/demo/get.php new file mode 100644 index 0000000..c44a64b --- /dev/null +++ b/src/service/ucloud/bin/v1/demo/get.php @@ -0,0 +1,39 @@ +ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} + +echo json_encode($data, 128); diff --git a/src/service/ucloud/bin/v1/demo/multipart.php b/src/service/ucloud/bin/v1/demo/multipart.php new file mode 100644 index 0000000..0a65026 --- /dev/null +++ b/src/service/ucloud/bin/v1/demo/multipart.php @@ -0,0 +1,22 @@ +ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} +echo "ETag: " . $data['ETag'] . "\n"; diff --git a/src/service/ucloud/bin/v1/demo/mupload.php b/src/service/ucloud/bin/v1/demo/mupload.php new file mode 100644 index 0000000..c050ae3 --- /dev/null +++ b/src/service/ucloud/bin/v1/demo/mupload.php @@ -0,0 +1,42 @@ +ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} + +$uploadId = $data['UploadId']; +$blkSize = $data['BlkSize']; +echo "UploadId: " . $uploadId . "\n"; +echo "BlkSize: " . $blkSize . "\n"; + +//数据上传 +list($etagList, $err) = UCloud_MUpload($bucket, $key, $file, $uploadId, $blkSize); +if ($err) { + echo "error: " . $err->ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} + +//完成上传 +list($data, $err) = UCloud_MFinish($bucket, $key, $uploadId, $etagList); +if ($err) { + echo "error: " . $err->ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} +echo "Etag: " . $data['ETag'] . "\n"; +echo "FileSize: " . $data['FileSize'] . "\n"; diff --git a/src/service/ucloud/bin/v1/demo/put.php b/src/service/ucloud/bin/v1/demo/put.php new file mode 100644 index 0000000..5df5480 --- /dev/null +++ b/src/service/ucloud/bin/v1/demo/put.php @@ -0,0 +1,19 @@ +ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} +echo "ETag: " . $data['ETag'] . "\n"; diff --git a/src/service/ucloud/bin/v1/demo/uploadhit.php b/src/service/ucloud/bin/v1/demo/uploadhit.php new file mode 100644 index 0000000..ea8730e --- /dev/null +++ b/src/service/ucloud/bin/v1/demo/uploadhit.php @@ -0,0 +1,21 @@ +ErrMsg . "\n"; + echo "code: " . $err->Code . "\n"; + exit; +} + +echo "upload hit success\n"; diff --git a/src/service/ucloud/bin/v1/ucloud/conf.php b/src/service/ucloud/bin/v1/ucloud/conf.php new file mode 100644 index 0000000..3404b8f --- /dev/null +++ b/src/service/ucloud/bin/v1/ucloud/conf.php @@ -0,0 +1,15 @@ +PublicKey = $publicKey; + $this->PrivateKey = $privateKey; + } + + public function Sign($data) + { + $sign = base64_encode(hash_hmac('sha1', $data, $this->PrivateKey, true)); + return "UCloud " . $this->PublicKey . ":" . $sign; + } + + //@results: $token + public function SignRequest($req, $mimetype = null, $type = HEAD_FIELD_CHECK) + { + $url = $req->URL; + $url = parse_url($url['path']); + $data = ''; + $data .= strtoupper($req->METHOD) . "\n"; + $data .= UCloud_Header_Get($req->Header, 'Content-MD5') . "\n"; + if ($mimetype) + $data .= $mimetype . "\n"; + else + $data .= UCloud_Header_Get($req->Header, 'Content-Type') . "\n"; + if ($type === HEAD_FIELD_CHECK) + $data .= UCloud_Header_Get($req->Header, 'Date') . "\n"; + else + $data .= UCloud_Header_Get($req->Header, 'Expires') . "\n"; + $data .= CanonicalizedUCloudHeaders($req->Header); + $data .= CanonicalizedResource($req->Bucket, $req->Key); + return $this->Sign($data); + } +} + +function UCloud_MakeAuth($auth) +{ + if (isset($auth)) { + return $auth; + } + + global $UCLOUD_PUBLIC_KEY; + global $UCLOUD_PRIVATE_KEY; + + return new UCloud_Auth($UCLOUD_PUBLIC_KEY, $UCLOUD_PRIVATE_KEY); +} + +//@results: token +function UCloud_SignRequest($auth, $req, $type = HEAD_FIELD_CHECK) +{ + return UCloud_MakeAuth($auth)->SignRequest($req, $type); +} + +// ---------------------------------------------------------- + + diff --git a/src/service/ucloud/bin/v1/ucloud/http.php b/src/service/ucloud/bin/v1/ucloud/http.php new file mode 100644 index 0000000..2763c93 --- /dev/null +++ b/src/service/ucloud/bin/v1/ucloud/http.php @@ -0,0 +1,373 @@ +URL = $url; + if (isset($url["query"])) { + $this->RawQuerys = $url["query"]; + } + $this->Header = array(); + $this->Body = $body; + $this->UA = UCloud_UserAgent(); + $this->METHOD = $method; + $this->Bucket = $bucket; + $this->Key = $key; + + global $CURL_TIMEOUT; + global $UFILE_ACTION_TYPE; + if ($CURL_TIMEOUT == null && $action_type !== ActionType::PUTFILE + && $action_type !== ActionType::POSTFILE) { + $CURL_TIMEOUT = 10; + } + $this->Timeout = $CURL_TIMEOUT; + } + + public function EncodedQuery() { + if ($this->RawQuerys != null) { + $q = ""; + foreach ($this->RawQuerys as $k => $v) { + $q = $q . "&" . rawurlencode($k) . "=" . rawurlencode($v); + } + return $q; + } + return ""; + } +} + +class HTTP_Response +{ + public $StatusCode; + public $Header; + public $ContentLength; + public $Body; + public $Timeout; + + public function __construct($code, $body) + { + $this->StatusCode = $code; + $this->Header = array(); + $this->Body = $body; + $this->ContentLength = strlen($body); + + global $CURL_TIMEOUT; + if ($CURL_TIMEOUT == null) { + $CURL_TIMEOUT = 10; + } + $this->Timeout = $CURL_TIMEOUT; + } +} + +//@results: $val +function UCloud_Header_Get($header, $key) +{ + $val = @$header[$key]; + if (isset($val)) { + if (is_array($val)) { + return $val[0]; + } + return $val; + } else { + return ''; + } +} + +//@results: $error +function UCloud_ResponseError($resp) +{ + $header = $resp->Header; + $err = new UCloud_Error($resp->StatusCode, null); + + if ($err->Code > 299) { + if ($resp->ContentLength !== 0) { + if (UCloud_Header_Get($header, 'Content-Type') === 'application/json') { + $ret = json_decode($resp->Body, true); + $err->ErrRet = $ret['ErrRet']; + $err->ErrMsg = $ret['ErrMsg']; + } + } + } + $err->Reqid = UCloud_Header_Get($header, 'X-SessionId'); + return $err; +} + +// -------------------------------------------------------------------------------- + +//@results: ($resp, $error) +function UCloud_Client_Do($req) +{ + $ch = curl_init(); + $url = $req->URL; + + $options = array( + CURLOPT_USERAGENT => $req->UA, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYHOST => false, + CURLOPT_HEADER => true, + CURLOPT_NOBODY => false, + CURLOPT_CUSTOMREQUEST => $req->METHOD, + //CURLOPT_URL => $url['host'] . "/" . rawurlencode($url['path']) . "?" . $req->EncodedQuery(), + CURLOPT_TIMEOUT => $req->Timeout, + CURLOPT_CONNECTTIMEOUT => $req->Timeout + ); + + if($req->EncodedQuery() !== ""){ + $options[CURLOPT_URL] = $url['host'] . "/" . $url['path'] . "?" . $req->EncodedQuery(); + }else{ + $options[CURLOPT_URL] = $url['host'] . "/" . $url['path']; + } + + $httpHeader = $req->Header; + if (!empty($httpHeader)) + { + $header = array(); + foreach($httpHeader as $key => $parsedUrlValue) { + $header[] = "$key: $parsedUrlValue"; + } + $options[CURLOPT_HTTPHEADER] = $header; + } + $body = $req->Body; + if (!empty($body)) { + $options[CURLOPT_POSTFIELDS] = $body; + } else { + $options[CURLOPT_POSTFIELDS] = ""; + } + curl_setopt_array($ch, $options); + $result = curl_exec($ch); + $ret = curl_errno($ch); + if ($ret !== 0) { + $err = new UCloud_Error(0, $ret, curl_error($ch)); + curl_close($ch); + return array(null, $err); + } + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); + curl_close($ch); + + $responseArray = explode("\r\n\r\n", $result); + $responseArraySize = sizeof($responseArray); + $headerString = $responseArray[$responseArraySize-2]; + $respBody = $responseArray[$responseArraySize-1]; + + $headers = parseHeaders($headerString); + $resp = new HTTP_Response($code, $respBody); + $resp->Header = $headers; + $err = null; + if (floor($resp->StatusCode/100) != 2) { + list($r, $m) = parseError($respBody); + $err = new UCloud_Error($resp->StatusCode, $r, $m); + } + return array($resp, $err); +} + +function parseError($bodyString) { + + $r = 0; + $m = ''; + $mp = json_decode($bodyString); + if (isset($mp->{'ErrRet'})) $r = $mp->{'ErrRet'}; + if (isset($mp->{'ErrMsg'})) $m = $mp->{'ErrMsg'}; + return array($r, $m); +} + +function parseHeaders($headerString) { + + $headers = explode("\r\n", $headerString); + foreach($headers as $header) { + if (strstr($header, ":")) { + $header = trim($header); + list($k, $v) = explode(":", $header); + $headers[$k] = trim($v); + } + } + return $headers; +} + +class UCloud_HttpClient +{ + //@results: ($resp, $error) + public function RoundTrip($req) + { + return UCloud_Client_Do($req); + } +} + +class UCloud_AuthHttpClient +{ + public $Auth; + public $Type; + public $MimeType; + + public function __construct($auth, $mimetype = null, $type = HEAD_FIELD_CHECK) + { + $this->Type = $type; + $this->MimeType = $mimetype; + $this->Auth = UCloud_MakeAuth($auth, $type); + } + + //@results: ($resp, $error) + public function RoundTrip($req) + { + if ($this->Type === HEAD_FIELD_CHECK) { + $token = $this->Auth->SignRequest($req, $this->MimeType, $this->Type); + $req->Header['Authorization'] = $token; + } + return UCloud_Client_Do($req); + } +} + +// -------------------------------------------------------------------------------- + +//@results: ($data, $error) +function UCloud_Client_Ret($resp) +{ + $code = $resp->StatusCode; + $data = null; + if ($code >= 200 && $code <= 299) { + if ($resp->ContentLength !== 0 && UCloud_Header_Get($resp->Header, 'Content-Type') == 'application/json') { + $data = json_decode($resp->Body, true); + if ($data === null) { + $err = new UCloud_Error($code, 0, ""); + return array(null, $err); + } + } + } + + $etag = UCloud_Header_Get($resp->Header, 'ETag'); + if ($etag != ''){ + $data['ETag'] = $etag; + }else{ + $data['ETag'] = UCloud_Header_Get($resp->Header, 'Etag'); + } + if (floor($code/100) == 2) { + return array($data, null); + } + return array($data, UCloud_ResponseError($resp)); +} + +//@results: ($data, $error) +function UCloud_Client_Call($self, $req, $type = HEAD_FIELD_CHECK) +{ + list($resp, $err) = $self->RoundTrip($req, $type); + if ($err !== null) { + return array(null, $err); + } + return UCloud_Client_Ret($resp); +} + +//@results: $error +function UCloud_Client_CallNoRet($self, $req, $type = HEAD_FIELD_CHECK) +{ + list($resp, $err) = $self->RoundTrip($req, $type); + if ($err !== null) { + return array(null, $err); + } + if (floor($resp->StatusCode/100) == 2) { + return null; + } + return UCloud_ResponseError($resp); +} + +//@results: ($data, $error) +function UCloud_Client_CallWithForm( + $self, $req, $body, $contentType = 'application/x-www-form-urlencoded') +{ + if ($contentType === 'application/x-www-form-urlencoded') { + if (is_array($req->Params)) { + $body = http_build_query($req->Params); + } + } + if ($contentType !== 'multipart/form-data') { + $req->Header['Content-Type'] = $contentType; + } + $req->Body = $body; + list($resp, $err) = $self->RoundTrip($req, HEAD_FIELD_CHECK); + if ($err !== null) { + return array(null, $err); + } + return UCloud_Client_Ret($resp); +} + +// -------------------------------------------------------------------------------- + +function UCloud_Client_CallWithMultipartForm($self, $req, $fields, $files) +{ + list($contentType, $body) = UCloud_Build_MultipartForm($fields, $files); + return UCloud_Client_CallWithForm($self, $req, $body, $contentType); +} + +//@results: ($contentType, $body) +function UCloud_Build_MultipartForm($fields, $files) +{ + $data = array(); + $boundary = md5(microtime()); + + foreach ($fields as $name => $val) { + array_push($data, '--' . $boundary); + array_push($data, "Content-Disposition: form-data; name=\"$name\""); + array_push($data, ''); + array_push($data, $val); + } + + foreach ($files as $file) { + array_push($data, '--' . $boundary); + list($name, $fileName, $fileBody, $mimeType) = $file; + $mimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType; + $fileName = UCloud_EscapeQuotes($fileName); + array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$fileName\""); + array_push($data, "Content-Type: $mimeType"); + array_push($data, ''); + array_push($data, $fileBody); + } + + array_push($data, '--' . $boundary . '--'); + array_push($data, ''); + + $body = implode("\r\n", $data); + $contentType = 'multipart/form-data; boundary=' . $boundary; + return array($contentType, $body); +} + +function UCloud_UserAgent() { + global $SDK_VER; + $sdkInfo = "UCloudPHP/$SDK_VER"; + + $systemInfo = php_uname("s"); + $machineInfo = php_uname("m"); + + $envInfo = "($systemInfo/$machineInfo)"; + + $phpVer = phpversion(); + + $ua = "$sdkInfo $envInfo PHP/$phpVer"; + return $ua; +} + +function UCloud_EscapeQuotes($str) +{ + $find = array("\\", "\""); + $replace = array("\\\\", "\\\""); + return str_replace($find, $replace, $str); +} + +// -------------------------------------------------------------------------------- + diff --git a/src/service/ucloud/bin/v1/ucloud/mimetypes.php b/src/service/ucloud/bin/v1/ucloud/mimetypes.php new file mode 100644 index 0000000..3df7c3c --- /dev/null +++ b/src/service/ucloud/bin/v1/ucloud/mimetypes.php @@ -0,0 +1,449 @@ + "x-world/x-3dmf", + ".3dmf" => "x-world/x-3dmf", + ".a" => "application/octet-stream", + ".aab" => "application/x-authorware-bin", + ".aam" => "application/x-authorware-map", + ".aas" => "application/x-authorware-seg", + ".abc" => "text/vnd.abc", + ".acgi" => "text/html", + ".afl" => "video/animaflex", + ".ai" => "application/postscript", + ".aif" => "audio/aiff", + ".aifc" => "audio/aiff", + ".aiff" => "audio/aiff", + ".aim" => "application/x-aim", + ".aip" => "text/x-audiosoft-intra", + ".ani" => "application/x-navi-animation", + ".aos" => "application/x-nokia-9000-communicator-add-on-software", + ".aps" => "application/mime", + ".arc" => "application/octet-stream", + ".arj" => "application/arj", + ".art" => "image/x-jg", + ".asf" => "video/x-ms-asf", + ".asm" => "text/x-asm", + ".asp" => "text/asp", + ".asx" => "application/x-mplayer2", + ".au" => "audio/basic", + ".avi" => "video/avi", + ".avs" => "video/avs-video", + ".bcpio" => "application/x-bcpio", + ".bin" => "application/octet-stream", + ".bm" => "image/bmp", + ".bmp" => "image/bmp", + ".boo" => "application/book", + ".book" => "application/book", + ".boz" => "application/x-bzip2", + ".bsh" => "application/x-bsh", + ".bz" => "application/x-bzip", + ".bz2" => "application/x-bzip2", + ".c" => "text/x-c", + ".c++" => "text/plain", + ".cat" => "application/vnd.ms-pki.seccat", + ".cc" => "text/x-c", + ".ccad" => "application/clariscad", + ".cco" => "application/x-cocoa", + ".cdf" => "application/cdf", + ".cer" => "application/pkix-cert", + ".cha" => "application/x-chat", + ".chat" => "application/x-chat", + ".conf" => "text/plain", + ".cpio" => "application/x-cpio", + ".cpp" => "text/x-c", + ".cpt" => "application/x-cpt", + ".crl" => "application/pkcs-crl", + ".crt" => "application/pkix-cert", + ".csh" => "application/x-csh", + ".css" => "text/css", + ".cxx" => "text/plain", + ".dcr" => "application/x-director", + ".deepv" => "application/x-deepv", + ".def" => "text/plain", + ".der" => "application/x-x509-ca-cert", + ".dif" => "video/x-dv", + ".dir" => "application/x-director", + ".dl" => "video/dl", + ".doc" => "application/msword", + ".dot" => "application/msword", + ".dp" => "application/commonground", + ".drw" => "application/drafting", + ".dump" => "application/octet-stream", + ".dv" => "video/x-dv", + ".dvi" => "application/x-dvi", + ".dwf" => "drawing/x-dwf", + ".dwg" => "application/acad", + ".dxf" => "application/dxf", + ".dxr" => "application/x-director", + ".el" => "text/x-script.elisp", + ".elc" => "application/x-elc", + ".env" => "application/x-envoy", + ".eps" => "application/postscript", + ".es" => "application/x-esrehber", + ".etx" => "text/x-setext", + ".evy" => "application/envoy", + ".exe" => "application/octet-stream", + ".f" => "text/plain", + ".f77" => "text/x-fortran", + ".f90" => "text/x-fortran", + ".fdf" => "application/vnd.fdf", + ".fif" => "image/fif", + ".fli" => "video/fli", + ".flo" => "image/florian", + ".flx" => "text/vnd.fmi.flexstor", + ".fmf" => "video/x-atomic3d-feature", + ".for" => "text/x-fortran", + ".fpx" => "image/vnd.fpx", + ".frl" => "application/freeloader", + ".funk" => "audio/make", + ".g" => "text/plain", + ".g3" => "image/g3fax", + ".gif" => "image/gif", + ".gl" => "video/gl", + ".gsd" => "audio/x-gsm", + ".gsm" => "audio/x-gsm", + ".gsp" => "application/x-gsp", + ".gss" => "application/x-gss", + ".gtar" => "application/x-gtar", + ".gz" => "application/x-gzip", + ".gzip" => "application/x-gzip", + ".h" => "text/plain", + ".hdf" => "application/x-hdf", + ".help" => "application/x-helpfile", + ".hgl" => "application/vnd.hp-hpgl", + ".hh" => "text/plain", + ".hlb" => "text/x-script", + ".hlp" => "application/hlp", + ".hpg" => "application/vnd.hp-hpgl", + ".hpgl" => "application/vnd.hp-hpgl", + ".hta" => "application/hta", + ".htc" => "text/x-component", + ".htm" => "text/html", + ".html" => "text/html", + ".htmls" => "text/html", + ".htt" => "text/webviewhtml", + ".htx" => "text/html", + ".ice" => "x-conference/x-cooltalk", + ".ico" => "image/x-icon", + ".idc" => "text/plain", + ".ief" => "image/ief", + ".iefs" => "image/ief", + ".iges" => "application/iges", + ".igs" => "application/iges", + ".ima" => "application/x-ima", + ".imap" => "application/x-httpd-imap", + ".inf" => "application/inf", + ".ins" => "application/x-internett-signup", + ".ip" => "application/x-ip2", + ".isu" => "video/x-isvideo", + ".it" => "audio/it", + ".iv" => "application/x-inventor", + ".ivr" => "i-world/i-vrml", + ".ivy" => "application/x-livescreen", + ".jam" => "audio/x-jam", + ".java" => "text/plain", + ".jcm" => "application/x-java-commerce", + ".jfif" => "image/jpeg", + ".jfif-tbnl" => "image/jpeg", + ".jpe" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".jpg" => "image/jpeg", + ".jps" => "image/x-jps", + ".js" => "application/javascript", + ".jut" => "image/jutvision", + ".kar" => "audio/midi", + ".ksh" => "application/x-ksh", + ".la" => "audio/nspaudio", + ".lam" => "audio/x-liveaudio", + ".latex" => "application/x-latex", + ".lha" => "application/lha", + ".lhx" => "application/octet-stream", + ".list" => "text/plain", + ".lma" => "audio/nspaudio", + ".log" => "text/plain", + ".lsp" => "application/x-lisp", + ".lst" => "text/plain", + ".ltx" => "application/x-latex", + ".lzh" => "application/x-lzh", + ".lzx" => "application/lzx", + ".m" => "text/x-m", + ".m1v" => "video/mpeg", + ".m2a" => "audio/mpeg", + ".m2v" => "video/mpeg", + ".m3u" => "audio/x-mpequrl", + ".man" => "application/x-troff-man", + ".map" => "application/x-navimap", + ".mar" => "text/plain", + ".mbd" => "application/mbedlet", + ".mc$" => "application/x-magic-cap-package-1.0", + ".mcd" => "application/mcad", + ".mcf" => "image/vasa", + ".mcp" => "application/netmc", + ".me" => "application/x-troff-me", + ".mht" => "message/rfc822", + ".mhtml" => "message/rfc822", + ".mid" => "audio/midi", + ".midi" => "audio/midi", + ".mif" => "application/x-mif", + ".mime" => "www/mime", + ".mjf" => "audio/x-vnd.audioexplosion.mjuicemediafile", + ".mjpg" => "video/x-motion-jpeg", + ".mm" => "application/base64", + ".mod" => "audio/mod", + ".moov" => "video/quicktime", + ".mov" => "video/quicktime", + ".movie" => "video/x-sgi-movie", + ".mp2" => "audio/mpeg", + ".mp3" => "audio/mpeg3", + ".mpa" => "video/mpeg", + ".mpc" => "application/x-project", + ".mpe" => "video/mpeg", + ".mpeg" => "video/mpeg", + ".mpg" => "video/mpeg", + ".mpga" => "audio/mpeg", + ".mpp" => "application/vnd.ms-project", + ".mpt" => "application/x-project", + ".mpv" => "application/x-project", + ".mpx" => "application/x-project", + ".mrc" => "application/marc", + ".ms" => "application/x-troff-ms", + ".mv" => "video/x-sgi-movie", + ".my" => "audio/make", + ".mzz" => "application/x-vnd.audioexplosion.mzz", + ".nap" => "image/naplps", + ".naplps" => "image/naplps", + ".nc" => "application/x-netcdf", + ".ncm" => "application/vnd.nokia.configuration-message", + ".nif" => "image/x-niff", + ".niff" => "image/x-niff", + ".nix" => "application/x-mix-transfer", + ".nsc" => "application/x-conference", + ".nvd" => "application/x-navidoc", + ".o" => "application/octet-stream", + ".oda" => "application/oda", + ".omc" => "application/x-omc", + ".omcd" => "application/x-omcdatamaker", + ".omcr" => "application/x-omcregerator", + ".p" => "text/x-pascal", + ".p10" => "application/pkcs10", + ".p12" => "application/pkcs-12", + ".p7a" => "application/x-pkcs7-signature", + ".p7c" => "application/pkcs7-mime", + ".p7m" => "application/pkcs7-mime", + ".p7r" => "application/x-pkcs7-certreqresp", + ".p7s" => "application/pkcs7-signature", + ".part" => "application/pro_eng", + ".pas" => "text/pascal", + ".pbm" => "image/x-portable-bitmap", + ".pcl" => "application/x-pcl", + ".pct" => "image/x-pict", + ".pcx" => "image/x-pcx", + ".pdb" => "chemical/x-pdb", + ".pdf" => "application/pdf", + ".pfunk" => "audio/make", + ".pgm" => "image/x-portable-graymap", + ".pic" => "image/pict", + ".pict" => "image/pict", + ".pko" => "application/vnd.ms-pki.pko", + ".pl" => "text/plain", + ".plx" => "application/x-pixclscript", + ".pm" => "image/x-xpixmap", + ".pm4" => "application/x-pagemaker", + ".pm5" => "application/x-pagemaker", + ".png" => "image/png", + ".pnm" => "application/x-portable-anymap", + ".pot" => "application/mspowerpoint", + ".pov" => "model/x-pov", + ".ppa" => "application/vnd.ms-powerpoint", + ".ppm" => "image/x-portable-pixmap", + ".pps" => "application/mspowerpoint", + ".ppt" => "application/mspowerpoint", + ".ppz" => "application/mspowerpoint", + ".pre" => "application/x-freelance", + ".prt" => "application/pro_eng", + ".ps" => "application/postscript", + ".psd" => "application/octet-stream", + ".pvu" => "paleovu/x-pv", + ".pwz" => "application/vnd.ms-powerpoint", + ".py" => "text/x-script.phyton", + ".pyc" => "application/x-bytecode.python", + ".qcp" => "audio/vnd.qcelp", + ".qd3" => "x-world/x-3dmf", + ".qd3d" => "x-world/x-3dmf", + ".qif" => "image/x-quicktime", + ".qt" => "video/quicktime", + ".qtc" => "video/x-qtc", + ".qti" => "image/x-quicktime", + ".qtif" => "image/x-quicktime", + ".ra" => "audio/x-pn-realaudio", + ".ram" => "audio/x-pn-realaudio", + ".ras" => "application/x-cmu-raster", + ".rast" => "image/cmu-raster", + ".rexx" => "text/x-script.rexx", + ".rf" => "image/vnd.rn-realflash", + ".rgb" => "image/x-rgb", + ".rm" => "audio/x-pn-realaudio", + ".rmi" => "audio/mid", + ".rmm" => "audio/x-pn-realaudio", + ".rmp" => "audio/x-pn-realaudio", + ".rng" => "application/ringing-tones", + ".rnx" => "application/vnd.rn-realplayer", + ".roff" => "application/x-troff", + ".rp" => "image/vnd.rn-realpix", + ".rpm" => "audio/x-pn-realaudio-plugin", + ".rt" => "text/richtext", + ".rtf" => "application/rtf", + ".rtx" => "application/rtf", + ".rv" => "video/vnd.rn-realvideo", + ".s" => "text/x-asm", + ".s3m" => "audio/s3m", + ".saveme" => "application/octet-stream", + ".sbk" => "application/x-tbook", + ".sdml" => "text/plain", + ".sdp" => "application/sdp", + ".sdr" => "application/sounder", + ".sea" => "application/sea", + ".set" => "application/set", + ".sgm" => "text/sgml", + ".sgml" => "text/sgml", + ".sh" => "application/x-sh", + ".shar" => "application/x-shar", + ".shtml" => "text/html", + ".sid" => "audio/x-psid", + ".sit" => "application/x-sit", + ".skd" => "application/x-koan", + ".skm" => "application/x-koan", + ".skp" => "application/x-koan", + ".skt" => "application/x-koan", + ".sl" => "application/x-seelogo", + ".smi" => "application/smil", + ".smil" => "application/smil", + ".snd" => "audio/basic", + ".sol" => "application/solids", + ".spl" => "application/futuresplash", + ".spr" => "application/x-sprite", + ".sprite" => "application/x-sprite", + ".src" => "application/x-wais-source", + ".ssi" => "text/x-server-parsed-html", + ".ssm" => "application/streamingmedia", + ".sst" => "application/vnd.ms-pki.certstore", + ".step" => "application/step", + ".stl" => "application/sla", + ".stp" => "application/step", + ".sv4cpio" => "application/x-sv4cpio", + ".sv4crc" => "application/x-sv4crc", + ".svf" => "image/vnd.dwg", + ".svr" => "application/x-world", + ".swf" => "application/x-shockwave-flash", + ".svg" => "image/svg+xml", + ".t" => "application/x-troff", + ".talk" => "text/x-speech", + ".tar" => "application/x-tar", + ".tbk" => "application/toolbook", + ".tcl" => "application/x-tcl", + ".tcsh" => "text/x-script.tcsh", + ".tex" => "application/x-tex", + ".texi" => "application/x-texinfo", + ".texinfo" => "application/x-texinfo", + ".text" => "text/plain", + ".tgz" => "application/x-compressed", + ".tif" => "image/tiff", + ".tiff" => "image/tiff", + ".tr" => "application/x-troff", + ".tsi" => "audio/tsp-audio", + ".tsp" => "application/dsptype", + ".tsv" => "text/tab-separated-values", + ".turbot" => "image/florian", + ".txt" => "text/plain", + ".uil" => "text/x-uil", + ".uni" => "text/uri-list", + ".unis" => "text/uri-list", + ".unv" => "application/i-deas", + ".uri" => "text/uri-list", + ".uris" => "text/uri-list", + ".ustar" => "application/x-ustar", + ".uu" => "application/octet-stream", + ".uue" => "text/x-uuencode", + ".vcd" => "application/x-cdlink", + ".vcs" => "text/x-vcalendar", + ".vda" => "application/vda", + ".vdo" => "video/vdo", + ".vew" => "application/groupwise", + ".viv" => "video/vivo", + ".vivo" => "video/vivo", + ".vmd" => "application/vocaltec-media-desc", + ".vmf" => "application/vocaltec-media-file", + ".voc" => "audio/voc", + ".vos" => "video/vosaic", + ".vox" => "audio/voxware", + ".vqe" => "audio/x-twinvq-plugin", + ".vqf" => "audio/x-twinvq", + ".vql" => "audio/x-twinvq-plugin", + ".vrml" => "application/x-vrml", + ".vrt" => "x-world/x-vrt", + ".vsd" => "application/x-visio", + ".vst" => "application/x-visio", + ".vsw" => "application/x-visio", + ".w60" => "application/wordperfect6.0", + ".w61" => "application/wordperfect6.1", + ".w6w" => "application/msword", + ".wav" => "audio/wav", + ".wb1" => "application/x-qpro", + ".wbmp" => "image/vnd.wap.wbmp", + ".web" => "application/vnd.xara", + ".wiz" => "application/msword", + ".wk1" => "application/x-123", + ".wmf" => "windows/metafile", + ".wmlc" => "application/vnd.wap.wmlc", + ".wmls" => "text/vnd.wap.wmlscript", + ".wmlsc" => "application/vnd.wap.wmlscriptc", + ".word" => "application/msword", + ".wp" => "application/wordperfect", + ".wp5" => "application/wordperfect", + ".wp6" => "application/wordperfect", + ".wpd" => "application/wordperfect", + ".wq1" => "application/x-lotus", + ".wri" => "application/mswrite", + ".wrl" => "application/x-world", + ".wrz" => "model/vrml", + ".wsc" => "text/scriplet", + ".wsrc" => "application/x-wais-source", + ".wtk" => "application/x-wintalk", + ".xbm" => "image/x-xbitmap", + ".xdr" => "video/x-amt-demorun", + ".xgz" => "xgl/drawing", + ".xif" => "image/vnd.xiff", + ".xl" => "application/excel", + ".xla" => "application/excel", + ".xlb" => "application/excel", + ".xlc" => "application/excel", + ".xld" => "application/excel", + ".xlk" => "application/excel", + ".xll" => "application/excel", + ".xlm" => "application/excel", + ".xls" => "application/excel", + ".xlt" => "application/excel", + ".xlv" => "application/excel", + ".xlw" => "application/excel", + ".xm" => "audio/xm", + ".xml" => "application/xml", + ".xmz" => "xgl/movie", + ".xpix" => "application/x-vnd.ls-xpix", + ".x-png" => "image/png", + ".xsr" => "video/x-amt-showrun", + ".xwd" => "image/x-xwd", + ".xyz" => "chemical/x-pdb", + ".zip" => "application/zip", + ".zoo" => "application/octet-stream", + ".zsh" => "text/x-script.zsh", + ".apk" => "application/vnd.android.package-archive", + ".ipa" => "application/octet-stream.ipa", + ".flv" => "video/x-flv", + ".mp4" => "video/mp4", + ".m3u8" => "application/x-mpegURL", + ".ts" => "video/MP2T", + ".3gp" => "video/3gpp", + ".wmv" => "video/x-ms-wmv", +); diff --git a/src/service/ucloud/bin/v1/ucloud/proxy.php b/src/service/ucloud/bin/v1/ucloud/proxy.php new file mode 100644 index 0000000..b0b4e2f --- /dev/null +++ b/src/service/ucloud/bin/v1/ucloud/proxy.php @@ -0,0 +1,361 @@ +$host, 'path'=>$path), $content, $bucket, $key, $action_type); + $req->Header['Expect'] = ''; + $req->Header['Content-Type'] = $mimetype; + + $client = new UCloud_AuthHttpClient(null, $mimetype); + list($data, $err) = UCloud_Client_Call($client, $req); + fclose($f); + return array($data, $err); +} + +//------------------------------表单上传------------------------------ +function UCloud_MultipartForm($bucket, $key, $file) +{ + $action_type = ActionType::POSTFILE; + $err = CheckConfig(ActionType::POSTFILE); + if ($err != null) { + return array(null, $err); + } + + $f = @fopen($file, "r"); + if (!$f) return array(null, new UCloud_Error(-1, -1, "open $file error")); + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = ""; + $fsize = filesize($file); + $content = ""; + if ($fsize != 0) { + $content = @fread($f, filesize($file)); + if ($content == FALSE) { + fclose($f); + return array(null, new UCloud_Error(0, -1, "read file error")); + } + } + list($mimetype, $err) = GetFileMimeType($file); + if ($err) { + fclose($f); + return array("", $err); + } + + $req = new HTTP_Request('POST', array('host'=>$host, 'path'=>$path), $content, $bucket, $key, $action_type); + $req->Header['Expect'] = ''; + $token = UCloud_SignRequest(null, $req, $mimetype); + + $fields = array('Authorization'=>$token, 'FileName' => $key); + $files = array('files'=>array('file', $file, $content, $mimetype)); + + $client = new UCloud_AuthHttpClient(null, NO_AUTH_CHECK); + list($data, $err) = UCloud_Client_CallWithMultipartForm($client, $req, $fields, $files); + fclose($f); + return array($data, $err); +} + +//------------------------------分片上传------------------------------ +function UCloud_MInit($bucket, $key) +{ + + $err = CheckConfig(ActionType::MINIT); + if ($err != null) { + return array(null, $err); + } + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = $key; + $querys = array( + "uploads" => "" + ); + $req = new HTTP_Request('POST', array('host'=>$host, 'path'=>$path, 'query'=>$querys), null, $bucket, $key); + $req->Header['Content-Type'] = 'application/x-www-form-urlencoded'; + + $client = new UCloud_AuthHttpClient(null); + return UCloud_Client_Call($client, $req); +} + +//@results: (tagList, err) +function UCloud_MUpload($bucket, $key, $file, $uploadId, $blkSize, $partNumber=0) +{ + + $err = CheckConfig(ActionType::MUPLOAD); + if ($err != null) { + return array(null, $err); + } + + $f = @fopen($file, "r"); + if (!$f) return array(null, new UCloud_Error(-1, -1, "open $file error")); + + global $UCLOUD_PROXY_SUFFIX; + + $etagList = array(); + list($mimetype, $err) = GetFileMimeType($file); + if ($err) { + fclose($f); + return array("", $err); + } + $client = new UCloud_AuthHttpClient(null); + for(;;) { + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = $key; + if (@fseek($f, $blkSize*$partNumber, SEEK_SET) < 0) { + fclose($f); + return array(null, new UCloud_Error(0, -1, "fseek error")); + } + $content = @fread($f, $blkSize); + if ($content == FALSE) { + if (feof($f)) break; + fclose($f); + return array(null, new UCloud_Error(0, -1, "read file error")); + } + + $querys = array( + "uploadId" => $uploadId, + "partNumber" => $partNumber + ); + $req = new HTTP_Request('PUT', array('host'=>$host, 'path'=>$path, 'query'=>$querys), $content, $bucket, $key); + $req->Header['Content-Type'] = $mimetype; + $req->Header['Expect'] = ''; + list($data, $err) = UCloud_Client_Call($client, $req); + if ($err) { + fclose($f); + return array(null, $err); + } + $etag = @$data['ETag']; + $part = @$data['PartNumber']; + if ($part != $partNumber) { + fclose($f); + return array(null, new UCloud_Error(0, -1, "unmatch partnumber")); + } + $etagList[] = $etag; + $partNumber += 1; + } + fclose($f); + return array($etagList, null); +} + +function UCloud_MFinish($bucket, $key, $uploadId, $etagList, $newKey = '') +{ + + $err = CheckConfig(ActionType::MFINISH); + if ($err != null) { + return array(null, $err); + } + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = $key; + $querys = array( + 'uploadId' => $uploadId, + 'newKey' => $newKey, + ); + + $body = @implode(',', $etagList); + $req = new HTTP_Request('POST', array('host'=>$host, 'path'=>$path, 'query'=>$querys), $body, $bucket, $key); + $req->Header['Content-Type'] = 'text/plain'; + + $client = new UCloud_AuthHttpClient(null); + return UCloud_Client_Call($client, $req); +} + +function UCloud_MCancel($bucket, $key, $uploadId) +{ + + $err = CheckConfig(ActionType::MCANCEL); + if ($err != null) { + return array(null, $err); + } + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = $key; + $querys = array( + 'uploadId' => $uploadId + ); + + $req = new HTTP_Request('DELETE', array('host'=>$host, 'path'=>$path, 'query'=>$querys), null, $bucket, $key); + $req->Header['Content-Type'] = 'application/x-www-form-urlencoded'; + + $client = new UCloud_AuthHttpClient(null); + return UCloud_Client_Call($client, $req); +} + +//------------------------------秒传------------------------------ +function UCloud_UploadHit($bucket, $key, $file) +{ + + $err = CheckConfig(ActionType::UPLOADHIT); + if ($err != null) { + return array(null, $err); + } + + $f = @fopen($file, "r"); + if (!$f) return array(null, new UCloud_Error(-1, -1, "open $file error")); + + $content = ""; + $fileSize = filesize($file); + if ($fileSize != 0) { + $content = @fread($f, $fileSize); + if ($content == FALSE) { + fclose($f); + return array(null, new UCloud_Error(0, -1, "read file error")); + } + } + list($fileHash, $err) = UCloud_FileHash($file); + if ($err) { + fclose($f); + return array(null, $err); + } + fclose($f); + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = "uploadhit"; + $querys = array( + 'Hash' => $fileHash, + 'FileName' => $key, + 'FileSize' => $fileSize + ); + + $req = new HTTP_Request('POST', array('host'=>$host, 'path'=>$path, 'query'=>$querys), null, $bucket, $key); + $req->Header['Content-Type'] = 'application/x-www-form-urlencoded'; + + $client = new UCloud_AuthHttpClient(null); + return UCloud_Client_Call($client, $req); +} + +//------------------------------删除文件------------------------------ +function UCloud_Delete($bucket, $key) +{ + + $err = CheckConfig(ActionType::DELETE); + if ($err != null) { + return array(null, $err); + } + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = "$key"; + + $req = new HTTP_Request('DELETE', array('host'=>$host, 'path'=>$path), null, $bucket, $key); + $req->Header['Content-Type'] = 'application/x-www-form-urlencoded'; + + $client = new UCloud_AuthHttpClient(null); + return UCloud_Client_Call($client, $req); +} + +//------------------------------追加上传------------------------------ +function UCloud_AppendFile($bucket, $key, $file, $position) +{ + $action_type = ActionType::APPENDFILE; + $err = CheckConfig(ActionType::APPENDFILE); + if ($err != null) { + return array(null, $err); + } + + $f = @fopen($file, "r"); + if (!$f) return array(null, new UCloud_Error(-1, -1, "open $file error")); + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $key = $key . "?append&position=" . $position; + $path = $key; + $content = @fread($f, filesize($file)); + list($mimetype, $err) = GetFileMimeType($file); + if ($err) { + fclose($f); + return array("", $err); + } + $req = new HTTP_Request('PUT', array('host'=>$host, 'path'=>$path), $content, $bucket, $key, $action_type); + $req->Header['Expect'] = ''; + $req->Header['Content-Type'] = $mimetype; + + $client = new UCloud_AuthHttpClient(null, $mimetype); + list($data, $err) = UCloud_Client_Call($client, $req); + fclose($f); + return array($data, $err); +} + +//------------------------------列表目录------------------------------ +function UCloud_ListObjects($bucket, $path_prefix, $marker, $count, $delimiter) +{ + $action_type = ActionType::LISTOBJECTS; + $err = CheckConfig(ActionType::LISTOBJECTS); + if ($err != null) { + return array(null, $err); + } + + global $UCLOUD_PROXY_SUFFIX; + $host = $bucket . $UCLOUD_PROXY_SUFFIX; + $path = "?listobjects&prefix=" . $path_prefix ."&marker=". $marker . "&max-keys=" . $count ."&delimiter=" .$delimiter; + + $req = new HTTP_Request('GET', array('host'=>$host, 'path'=>$path), null, $bucket, null, $action_type); + $req->Header['Content-Type'] = 'application/x-www-form-urlencoded'; + + $client = new UCloud_AuthHttpClient(null); + list($data, $err) = UCloud_Client_Call($client, $req); + return array($data, $err); +} + +//------------------------------生成公有文件Url------------------------------ +// @results: $url +function UCloud_MakePublicUrl($bucket, $key) +{ + global $UCLOUD_PROXY_SUFFIX; + return $bucket . $UCLOUD_PROXY_SUFFIX . "/" . rawurlencode($key); +} +//------------------------------生成私有文件Url------------------------------ +// @results: $url +function UCloud_MakePrivateUrl($bucket, $key, $expires = 0) +{ + + $err = CheckConfig(ActionType::GETFILE); + if ($err != null) { + return array(null, $err); + } + + global $UCLOUD_PUBLIC_KEY; + + $public_url = UCloud_MakePublicUrl($bucket, $key); + $req = new HTTP_Request('GET', array('path'=>$public_url), null, $bucket, $key); + if ($expires > 0) { + $req->Header['Expires'] = $expires; + } + + $client = new UCloud_AuthHttpClient(null); + $temp = $client->Auth->SignRequest($req, null, QUERY_STRING_CHECK); + $signature = substr($temp, -28, 28); + $url = $public_url . "?UCloudPublicKey=" . rawurlencode($UCLOUD_PUBLIC_KEY) . "&Signature=" . rawurlencode($signature); + if ('' != $expires) { + $url .= "&Expires=" . rawurlencode($expires); + } + return $url; +} diff --git a/src/service/ucloud/bin/v1/ucloud/utils.php b/src/service/ucloud/bin/v1/ucloud/utils.php new file mode 100644 index 0000000..a785ecf --- /dev/null +++ b/src/service/ucloud/bin/v1/ucloud/utils.php @@ -0,0 +1,147 @@ +Code = $code; + $this->ErrRet = $errRet; + $this->ErrMsg = $errMsg; + } +} + +function UCloud_UrlSafe_Encode($data) +{ + $find = array('+', '/'); + $replace = array('-', '_'); + return str_replace($find, $replace, $data); +} + +function UCloud_UrlSafe_Decode($data) +{ + $find = array('-', '_'); + $replace = array('+', '/'); + return str_replace($find, $replace, $data); +} + +//@results: (hash, err) +function UCloud_FileHash($file) +{ + $f = fopen($file, "r"); + if (!$f) return array(null, new UCloud_Error(0, -1, "open $file error")); + + $fileSize = filesize($file); + $buffer = ''; + $sha = ''; + $blkcnt = $fileSize/BLKSIZE; + if ($fileSize % BLKSIZE) $blkcnt += 1; + $buffer .= pack("L", $blkcnt); + if ($fileSize <= BLKSIZE) { + $content = fread($f, BLKSIZE); + if (!$content) { + fclose($f); + return array("", new UCloud_Error(0, -1, "read file error")); + } + $sha .= sha1($content, TRUE); + } else { + for($i=0; $i<$blkcnt; $i+=1) { + $content = fread($f, BLKSIZE); + if (!$content) { + if (feof($f)) break; + fclose($f); + return array("", new UCloud_Error(0, -1, "read file error")); + } + $sha .= sha1($content, TRUE); + } + $sha = sha1($sha, TRUE); + } + $buffer .= $sha; + $hash = UCloud_UrlSafe_Encode(base64_encode($buffer)); + fclose($f); + return array($hash, null); +} + +//@results: (mime, err) +function GetFileMimeType($filename) +{ + $mimetype = ""; + $ext = ""; + $filename_component = explode(".", $filename); + if (count($filename_component) >= 2) { + $ext = "." . $filename_component[count($filename_component)-1]; + } + + global $mimetype_complete_map; + if (array_key_exists($ext, $mimetype_complete_map)) { + $mimetype = $mimetype_complete_map[$ext]; + } else if (function_exists('mime_content_type')) { + $mimetype = mime_content_type($filename); + } else if (function_exists('finfo_file')) { + $finfo = finfo_open(FILEINFO_MIME_TYPE); // 返回 mime 类型 + $mimetype = finfo_file($finfo, $filename); + finfo_close($finfo); + } else { + return array("application/octet-stream", null); + } + return array($mimetype, null); +} + +function CheckConfig($action) { + + global $UCLOUD_PUBLIC_KEY; + global $UCLOUD_PRIVATE_KEY; + global $UCLOUD_PROXY_SUFFIX; + + switch ($action) { + case ActionType::PUTFILE: + case ActionType::POSTFILE: + case ActionType::MINIT: + case ActionType::MUPLOAD: + case ActionType::MCANCEL: + case ActionType::MFINISH: + case ActionType::DELETE: + case ActionType::UPLOADHIT: + case ActionType::LISTOBJECTS: + if ($UCLOUD_PROXY_SUFFIX == "") { + return new UCloud_Error(400, -1, "no proxy suffix found in config"); + } else if ($UCLOUD_PUBLIC_KEY == "" || strstr($UCLOUD_PUBLIC_KEY, " ") != FALSE) { + return new UCloud_Error(400, -1, "invalid public key found in config"); + } else if ($UCLOUD_PRIVATE_KEY == "" || strstr($UCLOUD_PRIVATE_KEY, " ") != FALSE) { + return new UCloud_Error(400, -1, "invalid private key found in config"); + } + break; + case ActionType::GETFILE: + if ($UCLOUD_PROXY_SUFFIX == "") { + return new UCloud_Error(400, -1, "no proxy suffix found in config"); + } + break; + default: + break; + } + return null; +}