- 支持更多的云存储(金山云、移动云、网易云、优刻得)

v6
Chaim 4 years ago
parent b60b05c100
commit 3a094e2bcb

@ -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"

@ -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' => '',
]
],
];

@ -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;
}

@ -0,0 +1,103 @@
<?php
// +----------------------------------------------------------------------
// | ThinkLibrary 6.0 for ThinkPhP 6.0
// +----------------------------------------------------------------------
// | 版权所有 2017~2020 [ https://www.dtapp.net ]
// +----------------------------------------------------------------------
// | 官方网站: https://gitee.com/liguangchun/ThinkLibrary
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/liguangchun/ThinkLibrary
// | github 仓库地址 https://github.com/GC0202/ThinkLibrary
// | Packagist 地址 https://packagist.org/packages/liguangchun/think-library
// +----------------------------------------------------------------------
namespace DtApp\ThinkLibrary\service\ecloud;
use Aws\S3\S3Client;
use DtApp\ThinkLibrary\Service;
/**
* 移动云
* https://ecloud.10086.cn/product-introduction/onest
* Class OnestService
* @package DtApp\ThinkLibrary\service\ecloud
*/
class OnestService extends Service
{
private $accessKey, $secretKey, $bucket, $baseUrl, $port;
public function accessKey(string $accessKey)
{
$this->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;
}
}

@ -0,0 +1,122 @@
<?php
// +----------------------------------------------------------------------
// | ThinkLibrary 6.0 for ThinkPhP 6.0
// +----------------------------------------------------------------------
// | 版权所有 2017~2020 [ https://www.dtapp.net ]
// +----------------------------------------------------------------------
// | 官方网站: https://gitee.com/liguangchun/ThinkLibrary
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/liguangchun/ThinkLibrary
// | github 仓库地址 https://github.com/GC0202/ThinkLibrary
// | Packagist 地址 https://packagist.org/packages/liguangchun/think-library
// +----------------------------------------------------------------------
namespace DtApp\ThinkLibrary\service\ksyun;
use DtApp\ThinkLibrary\Service;
use Ks3Client;
use Ks3ServiceException;
/**
* 金山云对象存储
* https://www.ksyun.com/nv/product/KS3.html
* Class Ks3Service
* @package DtApp\ThinkLibrary\service\ksyun
*/
class Ks3Service extends Service
{
private $accessKeyID, $accessKeySecret, $endpoint, $bucket;
public function accessKeyID(string $accessKeyID)
{
$this->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;
}
}
}

@ -0,0 +1,370 @@
<?php
//使用时请在项目中引用该php文件
//设置默认时区
date_default_timezone_set('Asia/Shanghai');
//检测API路径
if(!defined("KS3_API_PATH"))
define("KS3_API_PATH", dirname(__FILE__));
//是否使用VHOST
if(!defined("KS3_API_VHOST"))
define("KS3_API_VHOST",TRUE);
//是否开启日志(写入日志文件)
if(!defined("KS3_API_LOG"))
define("KS3_API_LOG",TRUE);
//是否显示日志(直接输出日志)
if(!defined("KS3_API_DISPLAY_LOG"))
define("KS3_API_DISPLAY_LOG", TRUE);
//定义日志目录(默认是该项目log下)
if(!defined("KS3_API_LOG_PATH"))
define("KS3_API_LOG_PATH","");
//是否使用HTTPS
if(!defined("KS3_API_USE_HTTPS"))
define("KS3_API_USE_HTTPS",FALSE);
//是否开启curl debug模式
if(!defined("KS3_API_DEBUG_MODE"))
define("KS3_API_DEBUG_MODE",FALSE);
define("KS3_API_Author","lijunwei@kingsoft.com");
define("KS3_API_Version","1.2");
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."config".DIRECTORY_SEPARATOR."Consts.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."API.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Signers.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Ks3Request.class.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Handlers.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Builders.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Logger.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."MessageHolder.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."lib".DIRECTORY_SEPARATOR."RequestCore.class.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."exceptions".DIRECTORY_SEPARATOR."Exceptions.php";
if(function_exists('get_loaded_extensions')){
//检测curl扩展
$extensions = get_loaded_extensions();
if($extensions){
if(!in_array('curl', $extensions)){
throw new Ks3ClientException("please install curl extension");
}
if(!in_array('mbstring', $extensions)){
throw new Ks3ClientException("please install mbstring extension");
}
}else{
throw new Ks3ClientException("please install extensions");
}
}else{
throw new Ks3ClientException();
}
class Ks3Client{
private $accessKey;
private $secretKey;
private $endpoint;
private $log;
public function __construct($accessKey = NULL, $secretKey = NULL, $endpoint = NULL ){
$this->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;
}
}
?>

@ -0,0 +1,129 @@
<?php
//使用客户端加密的方式上传下载文件
//检测API路径
if(!defined('KS3_API_PATH'))
define('KS3_API_PATH', dirname(__FILE__));
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."Ks3Client.class.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR."EncryptionUtil.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR."EncryptionHandlers.php";
//加密模式
//暂时仅支持EO,使用AES/CBC/PKCS5Padding算法对数据进行加密
if(!defined("ENCRYPTPTION_MODE"))
define("ENCRYPTPTION_MODE","EO");
//加密信息存储模式,暂时支持 ObjectMetadata和InstructionFile
//ObjectMetadata:存在用户元数据中
//InstructionFile存在一个.instruction文件中
if(!defined("ENCRYPTPTION_STORAGE_MODE"))
define("ENCRYPTPTION_STORAGE_MODE","ObjectMetadata");
if(function_exists('get_loaded_extensions')){
//检测mcrypt,openssl扩展
$extensions = get_loaded_extensions();
if($extensions){
if(!in_array('mcrypt', $extensions)){
throw new Ks3ClientException("please install mcrypt extension");
}
if(!in_array('openssl', $extensions)){
throw new Ks3ClientException("please install openssl extension");
}
}else{
throw new Ks3ClientException("please install extensions");
}
}else{
throw new Ks3ClientException();
}
class Ks3EncryptionClient extends Ks3Client{
private $encryptionHandler = NULL;
//用户提供的主密钥,可以是对称秘钥或非对称秘钥(array,分别是公钥和私钥)
private $encryptionMaterials = NULL;
public function __construct($accessKey, $secretKey,$encryptionMaterials, $endpoint = NULL ){
parent::__construct($accessKey,$secretKey,$endpoint);
if(is_array($encryptionMaterials)){
if(count($encryptionMaterials)==2){
$pk = openssl_pkey_get_public($encryptionMaterials[0]);
$sk = openssl_pkey_get_private($encryptionMaterials[1]);
if(!$pk)
throw new Ks3ClientException("invalid RSA public key,you can generate key use openssl");
if(!$sk)
throw new Ks3ClientException("invalid RSA private key,you can generate key use openssl");
$encryptionMaterials = array($pk,$sk);
}else{
throw new Ks3ClientException("encryptionMaterials should be string or an array of size 2");
}
}
$ks3client = new Ks3Client($accessKey,$secretKey,$endpoint);
$this->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);
}
}
?>

@ -0,0 +1,54 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Headers.php";
class Consts {
// static $Ks3EndPoint = "kss.ksyun.com";
static $SubResource = array("acl", "lifecycle", "location", "logging", "notification", "policy", "requestPayment", "torrent", "uploadId", "uploads", "versionId","versioning", "versions", "website", "delete", "thumbnail","cors","pfop","querypfop","adp","queryadp");
static $QueryParam = array("partNumber","response-content-type","response-content-language","response-expires", "response-cache-control","response-content-disposition", "response-content-encoding", );
static $Acl = array("private","public-read","public-read-write");
static $KS3HeaderPrefix = "x-kss-";
static $CORSElements = array("AllowedMethod","AllowedOrigin","AllowedHeader","MaxAgeSeconds","ExposeHeader");
static $BucketLoggingElements = array("TargetBucket","TargetPrefix");
static $ObjectMeta = array("Cache-Control","Content-Disposition","Content-Encoding","Content-Length","Content-MD5","Content-Type","Expires");
static $MultipartObjectMeta = array("Cache-Control","Content-Disposition","Content-Encoding","Content-Type","Expires");
static $UserMetaPrefix = "x-kss-meta";
static $ResponseObjectMeta = array(
"cache-control"=>"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";
}
?>

@ -0,0 +1,271 @@
<?php
/*
redirect:跳转至对应的API即别名
methodHTTP Method
needBucket:是否需要bucket
needObject是否需要object
signer请求构造链
handler结果处理链
*/
class API{
public static $API = array(
"getService"=>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"
)
);
}
?>

@ -0,0 +1,102 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."exceptions".DIRECTORY_SEPARATOR."Exceptions.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."config".DIRECTORY_SEPARATOR."Consts.php";
class LocationBuilder{
function build($args){
if(isset($args["Location"])){
$location = $args["Location"];
$xml = new SimpleXmlElement('<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"></CreateBucketConfiguration>');
$xml->addChild("LocationConstraint",$args["Location"]);
return $xml->asXml();
}
}
}
class CORSBuilder{
function build($args){
if(isset($args["CORS"])){
$cors = $args["CORS"];
$xml = new SimpleXmlElement('<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"></CORSConfiguration>');
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('<BucketLoggingStatus xmlns="http://s3.amazonaws.com/doc/2006-03-01/" />');
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('<Delete></Delete>');
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('<CompleteMultipartUpload></CompleteMultipartUpload>');
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();
}
}
}
?>

@ -0,0 +1,343 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."exceptions".DIRECTORY_SEPARATOR."Exceptions.php";
interface Handler{
public function handle(ResponseCore $response);
}
class ErrorResponseHandler implements Handler{
public function handle(ResponseCore $response){
$code = $response->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;
}
}
}
?>

@ -0,0 +1,29 @@
<?php
class Headers{
static $Date = "Date";
static $Authorization = "Authorization";
static $ContentMd5 = "Content-MD5";
static $ContentType = "Content-Type";
static $ContentLength="Content-Length";
static $Acl = "x-kss-acl";
static $CopySource = "x-kss-copy-source";
static $ETag = "ETag";
static $TaskID = "TaskID";
static $Range = "Range";
static $AsynchronousProcessingList = "kss-async-process";
static $NotifyURL = "kss-notifyurl";
static $XKssCallbackUrl = "x-kss-callbackurl";
static $XKssCallbackBody = "x-kss-callbackbody";
static $UserAgent = "User-Agent";
static $SSEAlgm = "x-kss-server-side-encryption";
static $SSEKMSId = "x-kss-server-side-encryption-kss-kms-key-id";
static $SSECAlgm = "x-kss-server-side-encryption-customer-algorithm";
static $SSECKey = "x-kss-server-side-encryption-customer-key";
static $SSECMD5 = "x-kss-server-side-encryption-customer-key-MD5";
static $SSECSourceAlgm = "x-kss-copy-source-server-side-encryption-customer-algorithm";
static $SSECSourceKey = "x-kss-copy-source-server-side-encryption-customer-key";
static $SSECSourceMD5 = "x-kss-copy-source-server-side-encryption-customer-key-MD5";
}
?>

@ -0,0 +1,84 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Utils.class.php";
class Ks3Request{
private $bucket;
private $key;
private $queryParams=array();
private $headers=array();
private $subResource;
private $method;
private $endpoint;
private $scheme;
private $body;
private $read_stream;
private $seek_position;
private $write_stream;
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 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;
}
}
?>

@ -0,0 +1,46 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."exceptions".DIRECTORY_SEPARATOR."Exceptions.php";
class Logger{
function info($msg){
$this->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");
}
}
}
}
?>

@ -0,0 +1,5 @@
<?php
class MessageHolder{
public $msg;
}
?>

@ -0,0 +1,541 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Headers.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."core".DIRECTORY_SEPARATOR."Utils.class.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."config".DIRECTORY_SEPARATOR."Consts.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."exceptions".DIRECTORY_SEPARATOR."Exceptions.php";
interface Signer{
public function sign( Ks3Request $request,$args=array());
}
class DefaultUserAgentSigner implements Signer{
public function sign(Ks3Request $request,$args=array()){
$request->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;
}
}
?>

@ -0,0 +1,235 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."exceptions".DIRECTORY_SEPARATOR."Exceptions.php";
class Utils{
public static function encodeUrl($url,$path=TRUE){
$url = rawurlencode($url);
$url = str_replace("+", "%20", $url);
$url = str_replace("*", "%2A", $url);
$url = str_replace("%7A", "~", $url);
if($path){
$url = str_replace("%2F", "/", $url);
}
return $url;
}
public static function hex_to_base64($str){
$result = '';
for ($i = 0; $i < strlen($str); $i += 2){
$result .= chr(hexdec(substr($str, $i, 2)));
}
return base64_encode($result);
}
public static function replaceNS2($str){
$str = str_replace("<ns2:", "<", $str);
$str = str_replace("</ns2:", "</", $str);
return $str;
}
public static $mime_types = array (
'apk' => '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<strlen($str); $i++) {
$v = ord( $str[$i] );
if( $v > 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<strlen($str); $i++) {
$v = ord( $str[$i] );
if( $v > 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;
}
}
?>

@ -0,0 +1,227 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR."EncryptionUtil.php";
//下载
class AESCBCStreamWriteCallBack{
private $iv;
private $cek;
private $contentLength;
//数组,分别为上限和下限
private $expectedRange;
//经过调整后的range
private $adjustedRange;
//当前指针位置
private $currentIndex;
private $buffer;//上一次调用streaming_write_callback后未解码的数据
private $firstWrite = TRUE;
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);
}
}
//最后的数据大小肯定是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,长度是2end=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;
}
}
?>

@ -0,0 +1,358 @@
<?php
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR."EncryptionUtil.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR."EncryptionCallBack.php";
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."exceptions".DIRECTORY_SEPARATOR."Exceptions.php";
interface EncryptionHandler{
public function putObjectByContentSecurely($args=array());
public function putObjectByFileSecurely($args=array());
public function getObjectSecurely($args=array());
public function initMultipartUploadSecurely($args=array());
public function uploadPartSecurely($args=array());
public function abortMultipartUploadSecurely($args=array());
public function completeMultipartUploadSecurely($args=array());
}
class EncryptionEO implements EncryptionHandler{
private $encryptionMaterials = NULL;
private $ks3client = NULL;
public function __construct($ks3client,$encryptionMaterials){
$this->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;
}
}
?>

@ -0,0 +1,279 @@
<?php
class EncryptionUtil{
public static $INSTRUCTION_SUFFIX = ".instruction";
public static function genereateOnceUsedKey($length=32){
$randpwd = "";
for ($i = 0; $i < $length; $i++)
{
$randpwd .= chr(mt_rand(33, 126));
}
return $randpwd;
}
public static function encode_AES_ECB($data,$secret_key){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_ECB,'');
$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_ECB);
$pad = $blocksize - (strlen($data) % $blocksize);
$data = $data . str_repeat(chr($pad), $pad);
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td,$secret_key,$iv);
$encrypted = mcrypt_generic($td,$data);
mcrypt_generic_deinit($td);
return $encrypted;
}
public static function decode_AES_ECB($data,$secret_key){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_ECB,'');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td,$secret_key,$iv);
$data = mdecrypt_generic($td,$data);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$dec_s = strlen($data);
$padding = ord($data[$dec_s-1]);
$data = substr($data, 0, -$padding);
return trim($data);
}
public static function getKeyEncryptionAlgm($encryptionMaterials){
if(is_array($encryptionMaterials)){
return "RSA";
}else{
return "AES";
}
}
public static function getAdjustedRange($range,$blocksize){
$a = $range["start"];
$b = $range["end"];
$a = $a - ($a%$blocksize)-$blocksize;
if($a < 0)
$a = 0;
$b = $b+$blocksize-$b%$blocksize+$blocksize;
return array("start"=>$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;
}
}
?>

@ -0,0 +1,34 @@
<?php
class Ks3ClientException extends RuntimeException{
}
class Ks3ServiceException extends Ks3ClientException{
private $requestId;
private $errorCode;
private $errorMessage;
private $resource;
private $statusCode;
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 __toString()
{
$message = get_class($this) . ': '
."(errorCode:".$this->errorCode.";"
."errorMessage:".$this->errorMessage.";"
."resource:".$this->resource.";"
."requestId:".$this->requestId.";"
."statusCode:".$this->statusCode.")";
return $message;
}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,48 @@
<?php
//更加详细的表单上传请参考js sdk
require_once "../Ks3Client.class.php";
$client = new Ks3Client("","");
$bucket_name = "phpsdktestlijunwei";
if(!$client->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);
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<form action="<?php echo $host_uri;?>" method="post" enctype="multipart/form-data">
Key to upload: <input type="input" name="key" value="<?php echo $key;?>" /><br />
<input type="hidden" name="success_action_redirect" value="<?php echo $redirect;?>" />
<input type="hidden" name="Content-Type" value="text/html" />
<input type="hidden" name="random" value="vfegf34egf3" />
<input type="hidden" name="KSSAccessKeyId" value="<?php echo $result["KSSAccessKeyId"];?>" />
<input type="hidden" name="Policy" value="<?php echo $result["Policy"];?>" />
<input type="hidden" name="Signature" value="<?php echo $result["Signature"];?>" />
File: <input type="file" name="file" /> <br />
<!-- The elements after this will be ignored -->
<input type="submit" name="submit" value="Upload to KSS S3" />
</form>
</html>

@ -0,0 +1,413 @@
<?php
require_once "../Ks3Client.class.php";
require_once "../core/Utils.class.php";
$client = new Ks3Client("","","kss.ksyun.com");//!!第三个参数endpoint需要对应bucket所在region!! 详见http://ks3.ksyun.com/doc/api/index.html Region区域一节
//print_r(listBuckets($client));
//print_r(deleteBucket($client));
//print_r(deleteBucketCORS($client));
//print_r(listObjects($client));
//print_r(getBucketAcl($client));
//print_r(getBucketCORS($client));
//print_r(getBucketLocation($client));
//print_r(getBucketLogging($client));
//print_r(bucketExists($client));
//print_r(createBucket($client));
//print_r(setBucketAcl($client));
//print_r(setBucketCORS($client));
//print_r(setBucketLogging($client));
//print_r(deleteObject($client));
//print_r(deleteObjects($client));
//print_r(getObject($client));
//print_r(getObjectAcl($client));
//print_r(objectExists($client));
//print_r(getObjectMeta($client));
//print_r(setObjectAcl($client));
//print_r(copyObject($client));
print_r(putObjectByFile($client));
//print_r(multipartUpload($client));
//print_r(abortMultipartUpload($client));
//print_r(generatePresignedUrl($client));
//print_r(putObjectWithAdpAndCallBack($client));
//print_r(multipartUploadWithAdpAndCallBack($client));
//print_r(putAdp($client));
//print_r(postObject($client));
function listBuckets($client){
return $client->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));
}
?>

@ -0,0 +1,170 @@
<?php
define("ENCRYPTPTION_STORAGE_MODE","InstructionFile");
require_once "../Ks3EncryptionClient.class.php";
require_once "../Ks3Client.class.php";
$bucket = "test-encryption";
$keyprefix = "php/";
$filename = "secret.key";
$handle = fopen($filename, "r");
$contents = fread($handle, filesize ($filename));
fclose($handle);
$client = new Ks3EncryptionClient("lMQTr0hNlMpB0iOk/i+x","D4CsYLs75JcWEjbiI22zR3P7kJ/+5B1qdEje7A7I",$contents);
putObjectByContentAndGetObjectUsingInstruction($client,$bucket,$keyprefix);
putObjectByFileAndGetObjectUsingFile($client,$bucket,$keyprefix);
multipartUpload($client,$bucket,$keyprefix);
copyAnddeleteObject($client,$bucket,$keyprefix);
function putObjectByContentAndGetObjectUsingInstruction($client,$bucket,$keyprefix){
$content = EncryptionUtil::genereateOnceUsedKey(rand(100,1000));
$args = array(
"Bucket"=>$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);
}

@ -0,0 +1,136 @@
<?php
define("ENCRYPTPTION_STORAGE_MODE","ObjectMetadata");
require_once "../Ks3EncryptionClient.class.php";
require_once "../Ks3Client.class.php";
$bucket = "test-encryption";
$keyprefix = "php/";
$filename = "secret.key";
$handle = fopen($filename, "r");
$contents = fread($handle, filesize ($filename));
fclose($handle);
$client = new Ks3EncryptionClient("lMQTr0hNlMpB0iOk/i+x","D4CsYLs75JcWEjbiI22zR3P7kJ/+5B1qdEje7A7I",$contents);
putObjectByContentAndGetObjectUsingMeta($client,$bucket,$keyprefix);
putObjectByFileAndGetObjectUsingMeta($client,$bucket,$keyprefix);
multipartUpload($client,$bucket,$keyprefix);
function putObjectByContentAndGetObjectUsingMeta($client,$bucket,$keyprefix){
for($i = 45 ;$i < 60;$i++){
$content = EncryptionUtil::genereateOnceUsedKey($i);
$args = array(
"Bucket"=>$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);
}

@ -0,0 +1,2 @@
ÓUê¹<EFBFBD>L|
we‰} øp/Õ^@«°áHá(µÁ†

@ -0,0 +1,60 @@
<?php
require_once "../core/Logger.php";
class PUnit{
function assertEquals($value,$expected,$info = NULL){
if($value != $expected){
throw new Exception($info." expected ".$expected." but ".$value);
}
}
function run($torun = NULL){
$r = new ReflectionClass($this);
foreach($r->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";
}
}
?>

@ -0,0 +1,922 @@
<?php
define("ENCRYPTPTION_STORAGE_MODE","InstructionFile");
require_once "../encryption/EncryptionUtil.php";
require_once "../Ks3Client.class.php";
require_once "../Ks3EncryptionClient.class.php";
require_once "TestUtil.php";
require_once "PUnit.php";
require_once "../lib/RequestCore.class.php";
class SDKTest extends PUnit{
protected $bucket = "php-sdk-test";
protected $key = "test==中/文?";
protected $key_copy = "test中/文_copy";
protected $accesskey = "";
protected $secrectkey = "";
protected $client;
protected $encryptionClient;
protected $cachedir;
protected $sseckey;
public function __construct(){
$this->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('<BucketLoggingStatus xmlns="http://s3.amazonaws.com/doc/2006-03-01/" />');
$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();
?>

@ -0,0 +1,53 @@
<?php
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/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);
}
}
?>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,2 @@
ÓUê¹<EFBFBD>L|
we‰} øp/Õ^@«°áHá(µÁ†

@ -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 初始化版本

@ -0,0 +1,90 @@
<?php
// +----------------------------------------------------------------------
// | ThinkLibrary 6.0 for ThinkPhP 6.0
// +----------------------------------------------------------------------
// | 版权所有 2017~2020 [ https://www.dtapp.net ]
// +----------------------------------------------------------------------
// | 官方网站: https://gitee.com/liguangchun/ThinkLibrary
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/liguangchun/ThinkLibrary
// | github 仓库地址 https://github.com/GC0202/ThinkLibrary
// | Packagist 地址 https://packagist.org/packages/liguangchun/think-library
// +----------------------------------------------------------------------
namespace DtApp\ThinkLibrary\service\netease;
use DtApp\ThinkLibrary\Service;
use NOS\Core\NosException;
use NOS\NosClient;
/**
* 网易云
* https://www.163yun.com/product/nos
* Class NosService
* @package DtApp\ThinkLibrary\service\netease
*/
class NosService extends Service
{
private $accessKeyId, $accessKeySecret, $endpoint, $bucket;
public function accessKeyID(string $accessKeyId)
{
$this->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;
}
}
}

@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | ThinkLibrary 6.0 for ThinkPhP 6.0
// +----------------------------------------------------------------------
// | 版权所有 2017~2020 [ https://www.dtapp.net ]
// +----------------------------------------------------------------------
// | 官方网站: https://gitee.com/liguangchun/ThinkLibrary
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/liguangchun/ThinkLibrary
// | github 仓库地址 https://github.com/GC0202/ThinkLibrary
// | Packagist 地址 https://packagist.org/packages/liguangchun/think-library
// +----------------------------------------------------------------------
namespace DtApp\ThinkLibrary\service\ucloud;
use DtApp\ThinkLibrary\Service;
/**
* UCloud优刻得
* https://www.ucloud.cn/site/product/ufile.html
* Class UfileService
* @package DtApp\ThinkLibrary\service\ucloud
*/
class UfileService extends Service
{
private $bucket;
public function bucket(string $bucket)
{
$this->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;
}
}

@ -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 去掉转义,保留原有格式

@ -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

@ -0,0 +1,21 @@
<?php
require_once("../ucloud/proxy.php");
//存储空间名
$bucket = "your bucket";
//上传至存储空间后的文件名称(请不要和API公私钥混淆)
$key = "your key";
//待上传文件的本地路径
$file = "local file path";
//当前append 的文件已有的大小, 新建填0
$position = 0;
//该接口适用于0-10MB小文件,更大的文件建议使用分片上传接口
list($data, $err) = UCloud_AppendFile($bucket, $key, $file, $position);
if ($err) {
echo "error: " . $err->ErrMsg . "\n";
echo "code: " . $err->Code . "\n";
exit;
}
echo "ETag: " . $data['ETag'] . "\n";

@ -0,0 +1,17 @@
<?php
require_once("../ucloud/proxy.php");
//存储空间名
$bucket = "your bucket";
//上传至存储空间后的文件名称(请不要和API公私钥混淆)
$key = "your key";
list($data, $err) = UCloud_Delete($bucket, $key);
if ($err) {
echo "error: " . $err->ErrMsg . "\n";
echo "code: " . $err->Code . "\n";
exit;
}
echo "delete $bucket/$key success\n";

@ -0,0 +1,39 @@
<?php
require_once("../ucloud/proxy.php");
//存储空间名
$bucket = "your bucket";
//上传至存储空间后的文件名称(请不要和API公私钥混淆)
$key = "your key";
function curl_file_get_contents($durl){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $durl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true) ; // 获取数据返回
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true) ; // 在启用 CURLOPT_RETURNTRANSFER 时候将获取数据返回
$r = curl_exec($ch);
curl_close($ch);
return $r;
}
/*
* 访问公有Bucket的例子
*/
$url = UCloud_MakePublicUrl($bucket, $key);
echo "download url(public): ", $url . "\n";
/*
* 访问私有Bucket的例子
*/
$url = UCloud_MakePrivateUrl($bucket, $key);
echo "download url(private): ", $url . "\n";
/*
* 访问包含过期时间的私有Bucket例子
*/
$curtime = time();
$curtime += 60; // 有效期60秒
$url = UCloud_MakePrivateUrl($bucket, $key, $curtime);
$content = curl_file_get_contents($url);
echo "download file with expires: ", $url . "\n";

@ -0,0 +1,26 @@
<?php
require_once("../ucloud/proxy.php");
//存储空间名
$bucket = "your bucket";
//需要拉列表的目录前缀
$prefix = "path prefix";
//拉列表一般分页拉取每次拉取会返回一个marker用来作为下一次拉取的marker实现翻页拉取初始为""
//如果拉取到结尾:"IsTruncated":false,"NextMarker":""
$marker = "";
#默认分隔符,目前支持/ 和空字符;如果是空表示不区分目录递归返回列表;
$delimiter ="/";
//该接口拉取一个目录前缀下的目录、文件列表
list($data, $err) = UCloud_ListObjects($bucket, $prefix, $marker, 100, $delimiter);
if ($err) {
echo "error: " . $err->ErrMsg . "\n";
echo "code: " . $err->Code . "\n";
exit;
}
echo json_encode($data, 128);

@ -0,0 +1,22 @@
<?php
require_once("../ucloud/conf.php");
require_once("../ucloud/http.php");
require_once("../ucloud/proxy.php");
//存储空间名
$bucket = "your bucket";
//上传至存储空间后的文件名称(请不要和API公私钥混淆)
$key = "your key";
//待上传文件的本地路径
$file = "local file path";
//该接口适用于web的POST表单上传,本SDK为了完整性故带上该接口demo.
//服务端上传建议使用分片上传接口,而非POST表单
list($data, $err) = UCloud_MultipartForm($bucket, $key, $file);
if ($err) {
echo "error: " . $err->ErrMsg . "\n";
echo "code: " . $err->Code . "\n";
exit;
}
echo "ETag: " . $data['ETag'] . "\n";

@ -0,0 +1,42 @@
<?php
require_once('../ucloud/proxy.php');
//存储空间名
$bucket = 'your bucket';
//上传至存储空间后的文件名称(请不要和API公私钥混淆)
$key = 'your key';
//待上传文件的本地路径
$file = 'local file path';
//初始化分片上传,获取本地上传的uploadId和分片大小
list($data, $err) = UCloud_MInit($bucket, $key);
if ($err)
{
echo "error: " . $err->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";

@ -0,0 +1,19 @@
<?php
require_once("../ucloud/proxy.php");
//存储空间名
$bucket = "your bucket";
//上传至存储空间后的文件名称(请不要和API公私钥混淆)
$key = "your key";
//待上传文件的本地路径
$file = "local file path";
//该接口适用于0-10MB小文件,更大的文件建议使用分片上传接口
list($data, $err) = UCloud_PutFile($bucket, $key, $file);
if ($err) {
echo "error: " . $err->ErrMsg . "\n";
echo "code: " . $err->Code . "\n";
exit;
}
echo "ETag: " . $data['ETag'] . "\n";

@ -0,0 +1,21 @@
<?php
require_once('../ucloud/proxy.php');
//存储空间
$bucket = 'your bucket';
//上传至存储空间后的文件名称(请不要和API公私钥混淆)
$key = 'your key';
//待秒传的本地文件路径
$file = 'local file path';
//该接口不是上传接口.如果秒传返回非200错误码,意味着该文件在服务器不存在
//需要继续调用其他上传接口完成上传操作
list($data, $err) = UCloud_UploadHit($bucket, $key, $file);
if ($err) {
echo "error: " . $err->ErrMsg . "\n";
echo "code: " . $err->Code . "\n";
exit;
}
echo "upload hit success\n";

@ -0,0 +1,15 @@
<?php
global $SDK_VER;
global $UCLOUD_PROXY_SUFFIX;
global $UCLOUD_PUBLIC_KEY;
global $UCLOUD_PRIVATE_KEY;
$SDK_VER = "1.0.9";
//空间域名后缀,请查看控制台上空间域名再配置此处
//https://docs.ucloud.cn/storage_cdn/ufile/tools/introduction
$UCLOUD_PROXY_SUFFIX = config('dtapp.ucloud.ufile.proxy_suffix'); //如果是其他地域的,请参考上面的说明
$UCLOUD_PUBLIC_KEY = config('dtapp.ucloud.ufile.public_key');
$UCLOUD_PRIVATE_KEY = config('dtapp.ucloud.ufile.private_key');

@ -0,0 +1,98 @@
<?php
require_once("utils.php");
require_once("conf.php");
define("NO_AUTH_CHECK", 0);
define("HEAD_FIELD_CHECK", 1);
define("QUERY_STRING_CHECK", 2);
// ----------------------------------------------------------
function CanonicalizedResource($bucket, $key)
{
return "/" . $bucket . "/" . $key;
}
function CanonicalizedUCloudHeaders($headers)
{
$keys = array();
foreach($headers as $header) {
$header = trim($header);
$arr = explode(':', $header);
if (count($arr) < 2) continue;
list($k, $v) = $arr;
$k = strtolower($k);
if (strncasecmp($k, "x-ucloud") === 0) {
$keys[] = $k;
}
}
$c = '';
sort($keys, SORT_STRING);
foreach($keys as $k) {
$c .= $k . ":" . trim($headers[$v], " ") . "\n";
}
return $c;
}
class UCloud_Auth {
public $PublicKey;
public $PrivateKey;
public function __construct($publicKey, $privateKey)
{
$this->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);
}
// ----------------------------------------------------------

@ -0,0 +1,373 @@
<?php
require_once("conf.php");
require_once("utils.php");
require_once("digest.php");
// --------------------------------------------------------------------------------
class HTTP_Request
{
public $URL;
public $RawQuerys;
public $Header;
public $Body;
public $UA;
public $METHOD;
public $Params; //map
public $Bucket;
public $Key;
public $Timeout;
public function __construct($method, $url, $body, $bucket, $key, $action_type = ActionType::NONE)
{
$this->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);
}
// --------------------------------------------------------------------------------

@ -0,0 +1,449 @@
<?php
global $mimetype_complete_map;
$mimetype_complete_map = array(
".3dm" => "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",
);

@ -0,0 +1,361 @@
<?php
require_once("conf.php");
require_once("http.php");
require_once("utils.php");
require_once("digest.php");
//------------------------------普通上传------------------------------
function UCloud_PutFile($bucket, $key, $file)
{
$action_type = ActionType::PUTFILE;
$err = CheckConfig(ActionType::PUTFILE);
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 = $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_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;
}

@ -0,0 +1,147 @@
<?php
require_once("mimetypes.php");
define('BLKSIZE', 4*1024*1024);
abstract class ActionType
{
const NONE = -1;
const PUTFILE = 0;
const POSTFILE = 1;
const MINIT = 2;
const MUPLOAD = 3;
const MFINISH = 4;
const MCANCEL = 5;
const DELETE = 6;
const UPLOADHIT = 7;
const GETFILE = 8;
const APPENDFILE = 9;
const LISTOBJECTS = 10;
}
class UCloud_Error
{
public $Code; // int
public $ErrRet; // int
public $ErrMsg; // string
public $SessionId; // string
public function __construct($code, $errRet, $errMsg)
{
$this->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;
}
Loading…
Cancel
Save