├── Plugin.php ├── README.md └── sdk ├── auth_digest.php ├── conf.php ├── fop.php ├── http.php ├── io.php ├── resumable_io.php ├── rs.php ├── rs_utils.php ├── rsf.php └── utils.php /Plugin.php: -------------------------------------------------------------------------------- 1 | 源代码参考 & 注册七牛 4 | * 5 | * @package Qiniu File 6 | * @author abelyao 7 | * @version 1.2.0 8 | * @link http://www.abelyao.com/ 9 | * @date 2014-02-22 10 | */ 11 | 12 | class QiniuFile_Plugin implements Typecho_Plugin_Interface 13 | { 14 | // 激活插件 15 | public static function activate() 16 | { 17 | Typecho_Plugin::factory('Widget_Upload')->uploadHandle = array('QiniuFile_Plugin', 'uploadHandle'); 18 | Typecho_Plugin::factory('Widget_Upload')->modifyHandle = array('QiniuFile_Plugin', 'modifyHandle'); 19 | Typecho_Plugin::factory('Widget_Upload')->deleteHandle = array('QiniuFile_Plugin', 'deleteHandle'); 20 | Typecho_Plugin::factory('Widget_Upload')->attachmentHandle = array('QiniuFile_Plugin', 'attachmentHandle'); 21 | return _t('插件已经激活,需先配置七牛的信息!'); 22 | } 23 | 24 | 25 | // 禁用插件 26 | public static function deactivate() 27 | { 28 | return _t('插件已被禁用'); 29 | } 30 | 31 | 32 | // 插件配置面板 33 | public static function config(Typecho_Widget_Helper_Form $form) 34 | { 35 | $bucket = new Typecho_Widget_Helper_Form_Element_Text('bucket', null, null, _t('空间名称:')); 36 | $form->addInput($bucket->addRule('required', _t('“空间名称”不能为空!'))); 37 | 38 | $accesskey = new Typecho_Widget_Helper_Form_Element_Text('accesskey', null, null, _t('AccessKey:')); 39 | $form->addInput($accesskey->addRule('required', _t('AccessKey 不能为空!'))); 40 | 41 | $sercetkey = new Typecho_Widget_Helper_Form_Element_Text('sercetkey', null, null, _t('SecretKey:')); 42 | $form->addInput($sercetkey->addRule('required', _t('SecretKey 不能为空!'))); 43 | 44 | $domain = new Typecho_Widget_Helper_Form_Element_Text('domain', null, 'http://', _t('绑定域名:'), _t('以 http:// 开头,结尾不要加 / !')); 45 | $form->addInput($domain->addRule('required', _t('请填写空间绑定的域名!'))->addRule('url', _t('您输入的域名格式错误!'))); 46 | 47 | $savepath = new Typecho_Widget_Helper_Form_Element_Text('savepath', null, '{year}/{month}/', _t('保存路径格式:'), _t('附件保存路径的格式,默认为 Typecho 的 {year}/{month}/ 格式,注意前面不要加 /
可选参数:{year} 年份、{month} 月份、{day} 日期')); 48 | $form->addInput($savepath->addRule('required', _t('请填写保存路径格式!'))); 49 | } 50 | 51 | 52 | // 个人用户配置面板 53 | public static function personalConfig(Typecho_Widget_Helper_Form $form) 54 | { 55 | } 56 | 57 | 58 | // 获得插件配置信息 59 | public static function getConfig() 60 | { 61 | return Typecho_Widget::widget('Widget_Options')->plugin('QiniuFile'); 62 | } 63 | 64 | 65 | // 初始化七牛SDK 66 | public static function initSDK($accesskey, $sercetkey) 67 | { 68 | // 调用 SDK 设置密钥 69 | require_once 'sdk/io.php'; 70 | require_once 'sdk/rs.php'; 71 | Qiniu_SetKeys($accesskey, $sercetkey); 72 | } 73 | 74 | 75 | // 删除文件 76 | public static function deleteFile($filepath) 77 | { 78 | // 获取插件配置 79 | $option = self::getConfig(); 80 | 81 | // 初始化 SDK 82 | self::initSDK($option->accesskey, $option->sercetkey); 83 | 84 | // 删除 85 | $client = new Qiniu_MacHttpClient(null); 86 | return Qiniu_RS_Delete($client, $option->bucket, $filepath); 87 | } 88 | 89 | 90 | // 上传文件 91 | public static function uploadFile($file, $content = null) 92 | { 93 | // 获取上传文件 94 | if (empty($file['name'])) return false; 95 | 96 | // 校验扩展名 97 | $part = explode('.', $file['name']); 98 | $ext = (($length = count($part)) > 1) ? strtolower($part[$length-1]) : ''; 99 | if (!Widget_Upload::checkFileType($ext)) return false; 100 | 101 | // 获取插件配置 102 | $option = self::getConfig(); 103 | $date = new Typecho_Date(Typecho_Widget::widget('Widget_Options')->gmtTime); 104 | 105 | // 保存位置 106 | $savepath = preg_replace(array('/\{year\}/', '/\{month\}/', '/\{day\}/'), array($date->year, $date->month, $date->day), $option->savepath); 107 | $savename = $savepath . sprintf('%u', crc32(uniqid())) . '.' . $ext; 108 | if (isset($content)) 109 | { 110 | $savename = $content['attachment']->path; 111 | self::deleteFile($savename); 112 | } 113 | 114 | // 上传文件 115 | $filename = $file['tmp_name']; 116 | if (!isset($filename)) return false; 117 | 118 | // 初始化 SDK 119 | self::initSDK($option->accesskey, $option->sercetkey); 120 | 121 | // 上传凭证 122 | $policy = new Qiniu_RS_PutPolicy($option->bucket); 123 | $token = $policy->Token(null); 124 | $extra = new Qiniu_PutExtra(); 125 | $extra->Crc32 = 1; 126 | 127 | // 上传 128 | list($result, $error) = Qiniu_PutFile($token, $savename, $filename, $extra); 129 | if ($error == null) 130 | { 131 | return array 132 | ( 133 | 'name' => $file['name'], 134 | 'path' => $savename, 135 | 'size' => $file['size'], 136 | 'type' => $ext, 137 | 'mime' => Typecho_Common::mimeContentType($savename) 138 | ); 139 | } 140 | else return false; 141 | } 142 | 143 | 144 | // 上传文件处理函数 145 | public static function uploadHandle($file) 146 | { 147 | return self::uploadFile($file); 148 | } 149 | 150 | 151 | // 修改文件处理函数 152 | public static function modifyHandle($content, $file) 153 | { 154 | return self::uploadFile($file, $content); 155 | } 156 | 157 | 158 | // 删除文件 159 | public static function deleteHandle(array $content) 160 | { 161 | self::deleteFile($content['attachment']->path); 162 | } 163 | 164 | 165 | // 获取实际文件绝对访问路径 166 | public static function attachmentHandle(array $content) 167 | { 168 | $option = self::getConfig(); 169 | return Typecho_Common::url($content['attachment']->path, $option->domain); 170 | } 171 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Typecho-QiniuFile 2 | --- 3 | 4 | Qiniu File 是一款 Typecho 的七牛云存储插件,可将 Typecho 的文件功能接入到七牛云存储中,包括上传附件、修改附件、删除附件,以及获取文件在七牛的绝对网址。文件目录结构默认与 Typecho 的 `/year/month/` 保持一致,也可自定义配置,方便迁移。 5 | 6 | #### 使用方法: 7 | 第一步:下载本插件,放在 `usr/plugins/` 目录中; 8 | 第二步:激活插件; 9 | 第三步:填写空间名称、Access Key、Secret Key、域名 等配置; 10 | 第四步:完成。 11 | 12 | #### 特别说明: 13 | 这个插件是为满足个人需求而编写,兼容性方面多多少少会有不完善的地方,如有需求,可根据源代码自行修改,或者与我联系。 14 | 15 | #### 与我联系: 16 | 作者:abelyao 17 | 主页:[www.abelyao.com](http://www.abelyao.com/) 18 | 或者通过 Typecho 官方QQ群 `8110782` 找到我 19 | -------------------------------------------------------------------------------- /sdk/auth_digest.php: -------------------------------------------------------------------------------- 1 | AccessKey = $accessKey; 16 | $this->SecretKey = $secretKey; 17 | } 18 | 19 | public function Sign($data) // => $token 20 | { 21 | $sign = hash_hmac('sha1', $data, $this->SecretKey, true); 22 | return $this->AccessKey . ':' . Qiniu_Encode($sign); 23 | } 24 | 25 | public function SignWithData($data) // => $token 26 | { 27 | $data = Qiniu_Encode($data); 28 | return $this->Sign($data) . ':' . $data; 29 | } 30 | 31 | public function SignRequest($req, $incbody) // => ($token, $error) 32 | { 33 | $url = $req->URL; 34 | $url = parse_url($url['path']); 35 | $data = ''; 36 | if (isset($url['path'])) { 37 | $data = $url['path']; 38 | } 39 | if (isset($url['query'])) { 40 | $data .= '?' . $url['query']; 41 | } 42 | $data .= "\n"; 43 | 44 | if ($incbody) { 45 | $data .= $req->Body; 46 | } 47 | return $this->Sign($data); 48 | } 49 | } 50 | 51 | function Qiniu_SetKeys($accessKey, $secretKey) 52 | { 53 | global $QINIU_ACCESS_KEY; 54 | global $QINIU_SECRET_KEY; 55 | 56 | $QINIU_ACCESS_KEY = $accessKey; 57 | $QINIU_SECRET_KEY = $secretKey; 58 | } 59 | 60 | function Qiniu_RequireMac($mac) // => $mac 61 | { 62 | if (isset($mac)) { 63 | return $mac; 64 | } 65 | 66 | global $QINIU_ACCESS_KEY; 67 | global $QINIU_SECRET_KEY; 68 | 69 | return new Qiniu_Mac($QINIU_ACCESS_KEY, $QINIU_SECRET_KEY); 70 | } 71 | 72 | function Qiniu_Sign($mac, $data) // => $token 73 | { 74 | return Qiniu_RequireMac($mac)->Sign($data); 75 | } 76 | 77 | function Qiniu_SignWithData($mac, $data) // => $token 78 | { 79 | return Qiniu_RequireMac($mac)->SignWithData($data); 80 | } 81 | 82 | // ---------------------------------------------------------- 83 | 84 | -------------------------------------------------------------------------------- /sdk/conf.php: -------------------------------------------------------------------------------- 1 | '; 15 | $QINIU_SECRET_KEY = ''; 16 | 17 | -------------------------------------------------------------------------------- /sdk/fop.php: -------------------------------------------------------------------------------- 1 | Mode); 18 | 19 | if (!empty($this->Width)) { 20 | $ops[] = 'w/' . $this->Width; 21 | } 22 | if (!empty($this->Height)) { 23 | $ops[] = 'h/' . $this->Height; 24 | } 25 | if (!empty($this->Quality)) { 26 | $ops[] = 'q/' . $this->Quality; 27 | } 28 | if (!empty($this->Format)) { 29 | $ops[] = 'format/' . $this->Format; 30 | } 31 | 32 | return $url . "?imageView/" . implode('/', $ops); 33 | } 34 | } 35 | 36 | // -------------------------------------------------------------------------------- 37 | // class Qiniu_Exif 38 | 39 | class Qiniu_Exif { 40 | 41 | public function MakeRequest($url) 42 | { 43 | return $url . "?exif"; 44 | } 45 | 46 | } 47 | 48 | // -------------------------------------------------------------------------------- 49 | // class Qiniu_ImageInfo 50 | 51 | class Qiniu_ImageInfo { 52 | 53 | public function MakeRequest($url) 54 | { 55 | return $url . "?imageInfo"; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /sdk/http.php: -------------------------------------------------------------------------------- 1 | Code = $code; 18 | $this->Err = $err; 19 | } 20 | } 21 | 22 | // -------------------------------------------------------------------------------- 23 | // class Qiniu_Request 24 | 25 | class Qiniu_Request 26 | { 27 | public $URL; 28 | public $Header; 29 | public $Body; 30 | 31 | public function __construct($url, $body) 32 | { 33 | $this->URL = $url; 34 | $this->Header = array(); 35 | $this->Body = $body; 36 | } 37 | } 38 | 39 | // -------------------------------------------------------------------------------- 40 | // class Qiniu_Response 41 | 42 | class Qiniu_Response 43 | { 44 | public $StatusCode; 45 | public $Header; 46 | public $ContentLength; 47 | public $Body; 48 | 49 | public function __construct($code, $body) 50 | { 51 | $this->StatusCode = $code; 52 | $this->Header = array(); 53 | $this->Body = $body; 54 | $this->ContentLength = strlen($body); 55 | } 56 | } 57 | 58 | // -------------------------------------------------------------------------------- 59 | // class Qiniu_Header 60 | 61 | function Qiniu_Header_Get($header, $key) // => $val 62 | { 63 | $val = @$header[$key]; 64 | if (isset($val)) { 65 | if (is_array($val)) { 66 | return $val[0]; 67 | } 68 | return $val; 69 | } else { 70 | return ''; 71 | } 72 | } 73 | 74 | function Qiniu_ResponseError($resp) // => $error 75 | { 76 | $header = $resp->Header; 77 | $details = Qiniu_Header_Get($header, 'X-Log'); 78 | $reqId = Qiniu_Header_Get($header, 'X-Reqid'); 79 | $err = new Qiniu_Error($resp->StatusCode, null); 80 | 81 | if ($err->Code > 299) { 82 | if ($resp->ContentLength !== 0) { 83 | if (Qiniu_Header_Get($header, 'Content-Type') === 'application/json') { 84 | $ret = json_decode($resp->Body, true); 85 | $err->Err = $ret['error']; 86 | } 87 | } 88 | } 89 | return $err; 90 | } 91 | 92 | // -------------------------------------------------------------------------------- 93 | // class Qiniu_Client 94 | 95 | function Qiniu_Client_incBody($req) // => $incbody 96 | { 97 | $body = $req->Body; 98 | if (!isset($body)) { 99 | return false; 100 | } 101 | 102 | $ct = Qiniu_Header_Get($req->Header, 'Content-Type'); 103 | if ($ct === 'application/x-www-form-urlencoded') { 104 | return true; 105 | } 106 | return false; 107 | } 108 | 109 | function Qiniu_Client_do($req) // => ($resp, $error) 110 | { 111 | $ch = curl_init(); 112 | $url = $req->URL; 113 | $options = array( 114 | CURLOPT_RETURNTRANSFER => true, 115 | CURLOPT_SSL_VERIFYPEER => false, 116 | CURLOPT_SSL_VERIFYHOST => false, 117 | CURLOPT_CUSTOMREQUEST => 'POST', 118 | CURLOPT_URL => $url['path'] 119 | ); 120 | $httpHeader = $req->Header; 121 | if (!empty($httpHeader)) 122 | { 123 | $header = array(); 124 | foreach($httpHeader as $key => $parsedUrlValue) { 125 | $header[] = "$key: $parsedUrlValue"; 126 | } 127 | $options[CURLOPT_HTTPHEADER] = $header; 128 | } 129 | $body = $req->Body; 130 | if (!empty($body)) { 131 | $options[CURLOPT_POSTFIELDS] = $body; 132 | } 133 | curl_setopt_array($ch, $options); 134 | $result = curl_exec($ch); 135 | $ret = curl_errno($ch); 136 | if ($ret !== 0) { 137 | $err = new Qiniu_Error(0, curl_error($ch)); 138 | curl_close($ch); 139 | return array(null, $err); 140 | } 141 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 142 | $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); 143 | curl_close($ch); 144 | $resp = new Qiniu_Response($code, $result); 145 | $resp->Header['Content-Type'] = $contentType; 146 | return array($resp, null); 147 | } 148 | 149 | class Qiniu_HttpClient 150 | { 151 | public function RoundTrip($req) // => ($resp, $error) 152 | { 153 | return Qiniu_Client_do($req); 154 | } 155 | } 156 | 157 | class Qiniu_MacHttpClient 158 | { 159 | public $Mac; 160 | 161 | public function __construct($mac) 162 | { 163 | $this->Mac = Qiniu_RequireMac($mac); 164 | } 165 | 166 | public function RoundTrip($req) // => ($resp, $error) 167 | { 168 | $incbody = Qiniu_Client_incBody($req); 169 | $token = $this->Mac->SignRequest($req, $incbody); 170 | $req->Header['Authorization'] = "QBox $token"; 171 | return Qiniu_Client_do($req); 172 | } 173 | } 174 | 175 | // -------------------------------------------------------------------------------- 176 | 177 | function Qiniu_Client_ret($resp) // => ($data, $error) 178 | { 179 | $code = $resp->StatusCode; 180 | $data = null; 181 | if ($code >= 200 && $code <= 299) { 182 | if ($resp->ContentLength !== 0) { 183 | $data = json_decode($resp->Body, true); 184 | if ($data === null) { 185 | $err_msg = function_exists('json_last_error_msg') ? json_last_error_msg() : "error with content:" . $resp->Body; 186 | $err = new Qiniu_Error(0, $err_msg); 187 | return array(null, $err); 188 | } 189 | } 190 | if ($code === 200) { 191 | return array($data, null); 192 | } 193 | } 194 | return array($data, Qiniu_ResponseError($resp)); 195 | } 196 | 197 | function Qiniu_Client_Call($self, $url) // => ($data, $error) 198 | { 199 | $u = array('path' => $url); 200 | $req = new Qiniu_Request($u, null); 201 | list($resp, $err) = $self->RoundTrip($req); 202 | if ($err !== null) { 203 | return array(null, $err); 204 | } 205 | return Qiniu_Client_ret($resp); 206 | } 207 | 208 | function Qiniu_Client_CallNoRet($self, $url) // => $error 209 | { 210 | $u = array('path' => $url); 211 | $req = new Qiniu_Request($u, null); 212 | list($resp, $err) = $self->RoundTrip($req); 213 | if ($err !== null) { 214 | return array(null, $err); 215 | } 216 | if ($resp->StatusCode === 200) { 217 | return null; 218 | } 219 | return Qiniu_ResponseError($resp); 220 | } 221 | 222 | function Qiniu_Client_CallWithForm( 223 | $self, $url, $params, $contentType = 'application/x-www-form-urlencoded') // => ($data, $error) 224 | { 225 | $u = array('path' => $url); 226 | if ($contentType === 'application/x-www-form-urlencoded') { 227 | if (is_array($params)) { 228 | $params = http_build_query($params); 229 | } 230 | } 231 | $req = new Qiniu_Request($u, $params); 232 | if ($contentType !== 'multipart/form-data') { 233 | $req->Header['Content-Type'] = $contentType; 234 | } 235 | list($resp, $err) = $self->RoundTrip($req); 236 | if ($err !== null) { 237 | return array(null, $err); 238 | } 239 | return Qiniu_Client_ret($resp); 240 | } 241 | 242 | // -------------------------------------------------------------------------------- 243 | 244 | function Qiniu_Client_CallWithMultipartForm($self, $url, $fields, $files) 245 | { 246 | list($contentType, $body) = Qiniu_Build_MultipartForm($fields, $files); 247 | return Qiniu_Client_CallWithForm($self, $url, $body, $contentType); 248 | } 249 | 250 | function Qiniu_Build_MultipartForm($fields, $files) // => ($contentType, $body) 251 | { 252 | $data = array(); 253 | $mimeBoundary = md5(microtime()); 254 | 255 | foreach ($fields as $name => $val) { 256 | array_push($data, '--' . $mimeBoundary); 257 | array_push($data, "Content-Disposition: form-data; name=\"$name\""); 258 | array_push($data, ''); 259 | array_push($data, $val); 260 | } 261 | 262 | foreach ($files as $file) { 263 | array_push($data, '--' . $mimeBoundary); 264 | list($name, $fileName, $fileBody, $mimeType) = $file; 265 | $mimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType; 266 | $fileName = Qiniu_escapeQuotes($fileName); 267 | array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$fileName\""); 268 | array_push($data, "Content-Type: $mimeType"); 269 | array_push($data, ''); 270 | array_push($data, $fileBody); 271 | } 272 | 273 | array_push($data, '--' . $mimeBoundary . '--'); 274 | array_push($data, ''); 275 | 276 | $body = implode("\r\n", $data); 277 | $contentType = 'multipart/form-data; boundary=' . $mimeBoundary; 278 | return array($contentType, $body); 279 | } 280 | 281 | function Qiniu_escapeQuotes($str) 282 | { 283 | $find = array("\\", "\""); 284 | $replace = array("\\\\", "\\\""); 285 | return str_replace($find, $replace, $str); 286 | } 287 | 288 | // -------------------------------------------------------------------------------- 289 | 290 | -------------------------------------------------------------------------------- /sdk/io.php: -------------------------------------------------------------------------------- 1 | ($putRet, $err) 18 | { 19 | global $QINIU_UP_HOST; 20 | 21 | if ($putExtra === null) { 22 | $putExtra = new Qiniu_PutExtra; 23 | } 24 | 25 | $fields = array('token' => $upToken); 26 | if ($key === null) { 27 | $fname = '?'; 28 | } else { 29 | $fname = $key; 30 | $fields['key'] = $key; 31 | } 32 | if ($putExtra->CheckCrc) { 33 | $fields['crc32'] = $putExtra->Crc32; 34 | } 35 | 36 | $files = array(array('file', $fname, $body, $putExtra->MimeType)); 37 | 38 | $client = new Qiniu_HttpClient; 39 | return Qiniu_Client_CallWithMultipartForm($client, $QINIU_UP_HOST, $fields, $files); 40 | } 41 | 42 | function Qiniu_PutFile($upToken, $key, $localFile, $putExtra) // => ($putRet, $err) 43 | { 44 | global $QINIU_UP_HOST; 45 | 46 | if ($putExtra === null) { 47 | $putExtra = new Qiniu_PutExtra; 48 | } 49 | 50 | if (!empty($putExtra->MimeType)) { 51 | $localFile .= ';type=' . $putExtra->MimeType; 52 | } 53 | 54 | $fields = array('token' => $upToken, 'file' => '@' . $localFile); 55 | if ($key === null) { 56 | $fname = '?'; 57 | } else { 58 | $fname = $key; 59 | $fields['key'] = $key; 60 | } 61 | if ($putExtra->CheckCrc) { 62 | if ($putExtra->CheckCrc === 1) { 63 | $hash = hash_file('crc32b', $localFile); 64 | $array = unpack('N', pack('H*', $hash)); 65 | $putExtra->Crc32 = $array[1]; 66 | } 67 | $fields['crc32'] = sprintf('%u', $putExtra->Crc32); 68 | } 69 | 70 | $client = new Qiniu_HttpClient; 71 | return Qiniu_Client_CallWithForm($client, $QINIU_UP_HOST, $fields, 'multipart/form-data'); 72 | } 73 | 74 | // ---------------------------------------------------------- 75 | 76 | -------------------------------------------------------------------------------- /sdk/resumable_io.php: -------------------------------------------------------------------------------- 1 | Bucket = $bucket; 22 | } 23 | } 24 | 25 | // ---------------------------------------------------------- 26 | // func Qiniu_Rio_BlockCount 27 | 28 | define('QINIU_RIO_BLOCK_BITS', 22); 29 | define('QINIU_RIO_BLOCK_SIZE', 1 << QINIU_RIO_BLOCK_BITS); // 4M 30 | 31 | function Qiniu_Rio_BlockCount($fsize) // => $blockCnt 32 | { 33 | return ($fsize + (QINIU_RIO_BLOCK_SIZE - 1)) >> QINIU_RIO_BLOCK_BITS; 34 | } 35 | 36 | // ---------------------------------------------------------- 37 | // internal func Qiniu_Rio_Mkblock/Mkfile 38 | 39 | function Qiniu_Rio_Mkblock($self, $host, $reader, $size) // => ($blkputRet, $err) 40 | { 41 | if (is_resource($reader)) { 42 | $body = fread($reader, $size); 43 | if ($body === false) { 44 | $err = Qiniu_NewError(0, 'fread failed'); 45 | return array(null, $err); 46 | } 47 | } else { 48 | list($body, $err) = $reader->Read($size); 49 | if ($err !== null) { 50 | return array(null, $err); 51 | } 52 | } 53 | if (strlen($body) != $size) { 54 | $err = Qiniu_NewError(0, 'fread failed: unexpected eof'); 55 | return array(null, $err); 56 | } 57 | 58 | $url = $host . '/mkblk/' . $size; 59 | return Qiniu_Client_CallWithForm($self, $url, $body, 'application/octet-stream'); 60 | } 61 | 62 | 63 | function Qiniu_Rio_Mkfile($self, $host, $key, $fsize, $extra) // => ($putRet, $err) 64 | { 65 | $url = $host . '/mkfile/' . $fsize; 66 | if ($key !== null) { 67 | $url .= '/key/' . Qiniu_Encode($key); 68 | } 69 | if (!empty($extra->MimeType)) { 70 | $url .= '/mimeType/' . Qiniu_Encode($extra->MimeType); 71 | } 72 | 73 | $ctxs = array(); 74 | foreach ($extra->Progresses as $prog) { 75 | $ctxs []= $prog['ctx']; 76 | } 77 | $body = implode(',', $ctxs); 78 | 79 | return Qiniu_Client_CallWithForm($self, $url, $body, 'application/octet-stream'); 80 | } 81 | 82 | // ---------------------------------------------------------- 83 | // class Qiniu_Rio_UploadClient 84 | 85 | class Qiniu_Rio_UploadClient 86 | { 87 | public $uptoken; 88 | 89 | public function __construct($uptoken) 90 | { 91 | $this->uptoken = $uptoken; 92 | } 93 | 94 | public function RoundTrip($req) // => ($resp, $error) 95 | { 96 | $token = $this->uptoken; 97 | $req->Header['Authorization'] = "UpToken $token"; 98 | return Qiniu_Client_do($req); 99 | } 100 | } 101 | 102 | // ---------------------------------------------------------- 103 | // class Qiniu_Rio_Put/PutFile 104 | 105 | function Qiniu_Rio_Put($upToken, $key, $body, $fsize, $putExtra) // => ($putRet, $err) 106 | { 107 | global $QINIU_UP_HOST; 108 | 109 | $self = new Qiniu_Rio_UploadClient($upToken); 110 | 111 | $progresses = array(); 112 | $uploaded = 0; 113 | while ($uploaded < $fsize) { 114 | if ($fsize < $uploaded + QINIU_RIO_BLOCK_SIZE) { 115 | $bsize = $fsize - $uploaded; 116 | } else { 117 | $bsize = QINIU_RIO_BLOCK_SIZE; 118 | } 119 | list($blkputRet, $err) = Qiniu_Rio_Mkblock($self, $QINIU_UP_HOST, $body, $bsize); 120 | $host = $blkputRet['host']; 121 | $uploaded += $bsize; 122 | $progresses []= $blkputRet; 123 | } 124 | 125 | $putExtra->Progresses = $progresses; 126 | return Qiniu_Rio_Mkfile($self, $QINIU_UP_HOST, $key, $fsize, $putExtra); 127 | } 128 | 129 | function Qiniu_Rio_PutFile($upToken, $key, $localFile, $putExtra) // => ($putRet, $err) 130 | { 131 | $fp = fopen($localFile, 'rb'); 132 | if ($fp === false) { 133 | $err = Qiniu_NewError(0, 'fopen failed'); 134 | return array(null, $err); 135 | } 136 | 137 | $fi = fstat($fp); 138 | $result = Qiniu_Rio_Put($upToken, $key, $fp, $fi['size'], $putExtra); 139 | fclose($fp); 140 | return $result; 141 | } 142 | 143 | // ---------------------------------------------------------- 144 | 145 | -------------------------------------------------------------------------------- /sdk/rs.php: -------------------------------------------------------------------------------- 1 | $privateUrl 13 | { 14 | $deadline = $this->Expires; 15 | if ($deadline == 0) { 16 | $deadline = 3600; 17 | } 18 | $deadline += time(); 19 | 20 | $pos = strpos($baseUrl, '?'); 21 | if ($pos !== false) { 22 | $baseUrl .= '&e='; 23 | } else { 24 | $baseUrl .= '?e='; 25 | } 26 | $baseUrl .= $deadline; 27 | 28 | $token = Qiniu_Sign($mac, $baseUrl); 29 | return "$baseUrl&token=$token"; 30 | } 31 | } 32 | 33 | function Qiniu_RS_MakeBaseUrl($domain, $key) // => $baseUrl 34 | { 35 | $keyEsc = rawurlencode($key); 36 | return "http://$domain/$keyEsc"; 37 | } 38 | 39 | // -------------------------------------------------------------------------------- 40 | // class Qiniu_RS_PutPolicy 41 | 42 | class Qiniu_RS_PutPolicy 43 | { 44 | public $Scope; //必填 45 | public $Expires; //默认为3600s 46 | public $CallbackUrl; 47 | public $CallbackBody; 48 | public $ReturnUrl; 49 | public $ReturnBody; 50 | public $AsyncOps; 51 | public $EndUser; 52 | public $InsertOnly; //若非0,则任何情况下无法覆盖上传 53 | public $DetectMime; //若非0,则服务端根据内容自动确定MimeType 54 | public $FsizeLimit; 55 | public $SaveKey; 56 | public $PersistentOps; 57 | public $PersistentNotifyUrl; 58 | public $Transform; 59 | public $FopTimeout; 60 | 61 | public function __construct($scope) 62 | { 63 | $this->Scope = $scope; 64 | } 65 | 66 | public function Token($mac) // => $token 67 | { 68 | $deadline = $this->Expires; 69 | if ($deadline == 0) { 70 | $deadline = 3600; 71 | } 72 | $deadline += time(); 73 | 74 | $policy = array('scope' => $this->Scope, 'deadline' => $deadline); 75 | if (!empty($this->CallbackUrl)) { 76 | $policy['callbackUrl'] = $this->CallbackUrl; 77 | } 78 | if (!empty($this->CallbackBody)) { 79 | $policy['callbackBody'] = $this->CallbackBody; 80 | } 81 | if (!empty($this->ReturnUrl)) { 82 | $policy['returnUrl'] = $this->ReturnUrl; 83 | } 84 | if (!empty($this->ReturnBody)) { 85 | $policy['returnBody'] = $this->ReturnBody; 86 | } 87 | if (!empty($this->AsyncOps)) { 88 | $policy['asyncOps'] = $this->AsyncOps; 89 | } 90 | if (!empty($this->EndUser)) { 91 | $policy['endUser'] = $this->EndUser; 92 | } 93 | if (!empty($this->InsertOnly)) { 94 | $policy['exclusive'] = $this->InsertOnly; 95 | } 96 | if (!empty($this->DetectMime)) { 97 | $policy['detectMime'] = $this->DetectMime; 98 | } 99 | if (!empty($this->FsizeLimit)) { 100 | $policy['fsizeLimit'] = $this->FsizeLimit; 101 | } 102 | if (!empty($this->SaveKey)) { 103 | $policy['saveKey'] = $this->SaveKey; 104 | } 105 | if (!empty($this->PersistentOps)) { 106 | $policy['persistentOps'] = $this->PersistentOps; 107 | } 108 | if (!empty($this->PersistentNotifyUrl)) { 109 | $policy['persistentNotifyUrl'] = $this->PersistentNotifyUrl; 110 | } 111 | if (!empty($this->Transform)) { 112 | $policy['transform'] = $this->Transform; 113 | } 114 | if (!empty($this->FopTimeout)) { 115 | $policy['fopTimeout'] = $this->FopTimeout; 116 | } 117 | 118 | $b = json_encode($policy); 119 | return Qiniu_SignWithData($mac, $b); 120 | } 121 | } 122 | 123 | // ---------------------------------------------------------- 124 | // class Qiniu_RS_EntryPath 125 | 126 | class Qiniu_RS_EntryPath 127 | { 128 | public $bucket; 129 | public $key; 130 | 131 | public function __construct($bucket, $key) 132 | { 133 | $this->bucket = $bucket; 134 | $this->key = $key; 135 | } 136 | } 137 | 138 | // ---------------------------------------------------------- 139 | // class Qiniu_RS_EntryPathPair 140 | 141 | class Qiniu_RS_EntryPathPair 142 | { 143 | public $src; 144 | public $dest; 145 | 146 | public function __construct($src, $dest) 147 | { 148 | $this->src = $src; 149 | $this->dest = $dest; 150 | } 151 | } 152 | 153 | // ---------------------------------------------------------- 154 | 155 | function Qiniu_RS_URIStat($bucket, $key) 156 | { 157 | return '/stat/' . Qiniu_Encode("$bucket:$key"); 158 | } 159 | 160 | function Qiniu_RS_URIDelete($bucket, $key) 161 | { 162 | return '/delete/' . Qiniu_Encode("$bucket:$key"); 163 | } 164 | 165 | function Qiniu_RS_URICopy($bucketSrc, $keySrc, $bucketDest, $keyDest) 166 | { 167 | return '/copy/' . Qiniu_Encode("$bucketSrc:$keySrc") . '/' . Qiniu_Encode("$bucketDest:$keyDest"); 168 | } 169 | 170 | function Qiniu_RS_URIMove($bucketSrc, $keySrc, $bucketDest, $keyDest) 171 | { 172 | return '/move/' . Qiniu_Encode("$bucketSrc:$keySrc") . '/' . Qiniu_Encode("$bucketDest:$keyDest"); 173 | } 174 | 175 | // ---------------------------------------------------------- 176 | 177 | function Qiniu_RS_Stat($self, $bucket, $key) // => ($statRet, $error) 178 | { 179 | global $QINIU_RS_HOST; 180 | $uri = Qiniu_RS_URIStat($bucket, $key); 181 | return Qiniu_Client_Call($self, $QINIU_RS_HOST . $uri); 182 | } 183 | 184 | function Qiniu_RS_Delete($self, $bucket, $key) // => $error 185 | { 186 | global $QINIU_RS_HOST; 187 | $uri = Qiniu_RS_URIDelete($bucket, $key); 188 | return Qiniu_Client_CallNoRet($self, $QINIU_RS_HOST . $uri); 189 | } 190 | 191 | function Qiniu_RS_Move($self, $bucketSrc, $keySrc, $bucketDest, $keyDest) // => $error 192 | { 193 | global $QINIU_RS_HOST; 194 | $uri = Qiniu_RS_URIMove($bucketSrc, $keySrc, $bucketDest, $keyDest); 195 | return Qiniu_Client_CallNoRet($self, $QINIU_RS_HOST . $uri); 196 | } 197 | 198 | function Qiniu_RS_Copy($self, $bucketSrc, $keySrc, $bucketDest, $keyDest) // => $error 199 | { 200 | global $QINIU_RS_HOST; 201 | $uri = Qiniu_RS_URICopy($bucketSrc, $keySrc, $bucketDest, $keyDest); 202 | return Qiniu_Client_CallNoRet($self, $QINIU_RS_HOST . $uri); 203 | } 204 | 205 | // ---------------------------------------------------------- 206 | // batch 207 | 208 | function Qiniu_RS_Batch($self, $ops) // => ($data, $error) 209 | { 210 | global $QINIU_RS_HOST; 211 | $url = $QINIU_RS_HOST . '/batch'; 212 | $params = 'op=' . implode('&op=', $ops); 213 | return Qiniu_Client_CallWithForm($self, $url, $params); 214 | } 215 | 216 | function Qiniu_RS_BatchStat($self, $entryPaths) 217 | { 218 | $params = array(); 219 | foreach ($entryPaths as $entryPath) { 220 | $params[] = Qiniu_RS_URIStat($entryPath->bucket, $entryPath->key); 221 | } 222 | return Qiniu_RS_Batch($self,$params); 223 | } 224 | 225 | function Qiniu_RS_BatchDelete($self, $entryPaths) 226 | { 227 | $params = array(); 228 | foreach ($entryPaths as $entryPath) { 229 | $params[] = Qiniu_RS_URIDelete($entryPath->bucket, $entryPath->key); 230 | } 231 | return Qiniu_RS_Batch($self, $params); 232 | } 233 | 234 | function Qiniu_RS_BatchMove($self, $entryPairs) 235 | { 236 | $params = array(); 237 | foreach ($entryPairs as $entryPair) { 238 | $src = $entryPair->src; 239 | $dest = $entryPair->dest; 240 | $params[] = Qiniu_RS_URIMove($src->bucket, $src->key, $dest->bucket, $dest->key); 241 | } 242 | return Qiniu_RS_Batch($self, $params); 243 | } 244 | 245 | function Qiniu_RS_BatchCopy($self, $entryPairs) 246 | { 247 | $params = array(); 248 | foreach ($entryPairs as $entryPair) { 249 | $src = $entryPair->src; 250 | $dest = $entryPair->dest; 251 | $params[] = Qiniu_RS_URICopy($src->bucket, $src->key, $dest->bucket, $dest->key); 252 | } 253 | return Qiniu_RS_Batch($self, $params); 254 | } 255 | 256 | // ---------------------------------------------------------- 257 | 258 | -------------------------------------------------------------------------------- /sdk/rs_utils.php: -------------------------------------------------------------------------------- 1 | ($putRet, $err) 8 | { 9 | $putPolicy = new Qiniu_RS_PutPolicy("$bucket:$key"); 10 | $upToken = $putPolicy->Token($self->Mac); 11 | return Qiniu_Put($upToken, $key, $body, $putExtra); 12 | } 13 | 14 | function Qiniu_RS_PutFile($self, $bucket, $key, $localFile, $putExtra) // => ($putRet, $err) 15 | { 16 | $putPolicy = new Qiniu_RS_PutPolicy("$bucket:$key"); 17 | $upToken = $putPolicy->Token($self->Mac); 18 | return Qiniu_PutFile($upToken, $key, $localFile, $putExtra); 19 | } 20 | 21 | function Qiniu_RS_Rput($self, $bucket, $key, $body, $fsize, $putExtra) // => ($putRet, $err) 22 | { 23 | $putPolicy = new Qiniu_RS_PutPolicy("$bucket:$key"); 24 | $upToken = $putPolicy->Token($self->Mac); 25 | if ($putExtra == null) { 26 | $putExtra = new Qiniu_Rio_PutExtra($bucket); 27 | } else { 28 | $putExtra->Bucket = $bucket; 29 | } 30 | return Qiniu_Rio_Put($upToken, $key, $body, $fsize, $putExtra); 31 | } 32 | 33 | function Qiniu_RS_RputFile($self, $bucket, $key, $localFile, $putExtra) // => ($putRet, $err) 34 | { 35 | $putPolicy = new Qiniu_RS_PutPolicy("$bucket:$key"); 36 | $upToken = $putPolicy->Token($self->Mac); 37 | if ($putExtra == null) { 38 | $putExtra = new Qiniu_Rio_PutExtra($bucket); 39 | } else { 40 | $putExtra->Bucket = $bucket; 41 | } 42 | return Qiniu_Rio_PutFile($upToken, $key, $localFile, $putExtra); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /sdk/rsf.php: -------------------------------------------------------------------------------- 1 | ($items, $markerOut, $err) 14 | { 15 | global $QINIU_RSF_HOST; 16 | 17 | $query = array('bucket' => $bucket); 18 | if (!empty($prefix)) { 19 | $query['prefix'] = $prefix; 20 | } 21 | if (!empty($marker)) { 22 | $query['marker'] = $marker; 23 | } 24 | if (!empty($limit)) { 25 | $query['limit'] = $limit; 26 | } 27 | 28 | $url = $QINIU_RSF_HOST . '/list?' . http_build_query($query); 29 | list($ret, $err) = Qiniu_Client_Call($self, $url); 30 | if ($err !== null) { 31 | return array(null, '', $err); 32 | } 33 | 34 | $items = $ret['items']; 35 | if (empty($ret['marker'])) { 36 | $markerOut = ''; 37 | $err = Qiniu_RSF_EOF; 38 | } else { 39 | $markerOut = $ret['marker']; 40 | } 41 | return array($items, $markerOut, $err); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /sdk/utils.php: -------------------------------------------------------------------------------- 1 |