├── 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 | require_once 'sdk/rsf.php';
72 | Qiniu_SetKeys($accesskey, $sercetkey);
73 | }
74 |
75 |
76 | // 删除文件
77 | public static function deleteFile($filepath)
78 | {
79 | // 获取插件配置
80 | $option = self::getConfig();
81 |
82 | // 初始化 SDK
83 | self::initSDK($option->accesskey, $option->sercetkey);
84 |
85 | // 删除
86 | $client = new Qiniu_MacHttpClient(null);
87 | return Qiniu_RS_Delete($client, $option->bucket, $filepath);
88 | }
89 |
90 |
91 | // 上传文件
92 | public static function uploadFile($file, $content = null)
93 | {
94 | // 获取上传文件
95 | if (empty($file['name'])) return false;
96 |
97 | // 校验扩展名
98 | $part = explode('.', $file['name']);
99 | $ext = (($length = count($part)) > 1) ? strtolower($part[$length-1]) : '';
100 | if (!Widget_Upload::checkFileType($ext)) return false;
101 |
102 | // 获取插件配置
103 | $option = self::getConfig();
104 | $date = new Typecho_Date(Typecho_Widget::widget('Widget_Options')->gmtTime);
105 |
106 | // 保存位置
107 | $savepath = preg_replace(array('/\{year\}/', '/\{month\}/', '/\{day\}/'), array($date->year, $date->month, $date->day), $option->savepath);
108 | $savename = $savepath . sprintf('%u', crc32(uniqid())) . '.' . $ext;
109 | if (isset($content))
110 | {
111 | $savename = $content['attachment']->path;
112 | self::deleteFile($savename);
113 | }
114 |
115 | // 上传文件
116 | $filename = $file['tmp_name'];
117 | if (!isset($filename)) return false;
118 |
119 | // 初始化 SDK
120 | self::initSDK($option->accesskey, $option->sercetkey);
121 |
122 | // 上传凭证
123 | $policy = new Qiniu_RS_PutPolicy($option->bucket);
124 | $token = $policy->Token(null);
125 | $extra = new Qiniu_PutExtra();
126 | $extra->Crc32 = 1;
127 |
128 | // 上传
129 | list($result, $error) = Qiniu_PutFile($token, $savename, $filename, $extra);
130 |
131 | if ($error == null)
132 | {
133 | return array
134 | (
135 | 'name' => $file['name'],
136 | 'path' => $savename,
137 | 'size' => $file['size'],
138 | 'type' => $ext,
139 | 'mime' => Typecho_Common::mimeContentType($savename)
140 | );
141 | }
142 | else return false;
143 | }
144 |
145 |
146 | // 上传文件处理函数
147 | public static function uploadHandle($file)
148 | {
149 | return self::uploadFile($file);
150 | }
151 |
152 |
153 | // 修改文件处理函数
154 | public static function modifyHandle($content, $file)
155 | {
156 | return self::uploadFile($file, $content);
157 | }
158 |
159 |
160 | // 删除文件
161 | public static function deleteHandle(array $content)
162 | {
163 | self::deleteFile($content['attachment']->path);
164 | }
165 |
166 |
167 | // 获取实际文件绝对访问路径
168 | public static function attachmentHandle(array $content)
169 | {
170 | $option = self::getConfig();
171 | return Typecho_Common::url($content['attachment']->path, $option->domain);
172 | }
173 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # typecho附件七牛云上传
2 |
3 | TODO:
4 | 七牛云文件管理
5 | ******
6 |
7 | >七牛云提供文件存储,音频处理,文档转换,CDN等服务。 —— [官网](https://www.qiniu.com)
8 |
9 | > 参考[七牛云存储使用指南] —— [七牛云文档](http://developer.qiniu.com/)
10 |
11 | **使用方法**
12 | - 上传至:/usr/plugins
13 | - 启用插件
14 | - 填写配置信息,保存
15 | - 开始撰写文章体验附件上传
16 |
17 |
18 | ###请注意:
19 | >文件夹名应为:QiniuFile,与plugin.php中的QiniuFile_Plugin一致,
20 |
21 | ---------
22 | 感谢使用。若觉得不错,别忘了**star**。
23 |
--------------------------------------------------------------------------------
/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 | public function VerifyCallback($auth, $url, $body) // ==> bool
51 | {
52 | $url = parse_url($url);
53 | $data = '';
54 | if (isset($url['path'])) {
55 | $data = $url['path'];
56 | }
57 | if (isset($url['query'])) {
58 | $data .= '?' . $url['query'];
59 | }
60 | $data .= "\n";
61 |
62 | $data .= $body;
63 | $token = 'QBox ' . $this->Sign($data);
64 | return $auth === $token;
65 | }
66 | }
67 |
68 | function Qiniu_SetKeys($accessKey, $secretKey)
69 | {
70 | global $QINIU_ACCESS_KEY;
71 | global $QINIU_SECRET_KEY;
72 |
73 | $QINIU_ACCESS_KEY = $accessKey;
74 | $QINIU_SECRET_KEY = $secretKey;
75 | }
76 |
77 | function Qiniu_RequireMac($mac) // => $mac
78 | {
79 | if (isset($mac)) {
80 | return $mac;
81 | }
82 |
83 | global $QINIU_ACCESS_KEY;
84 | global $QINIU_SECRET_KEY;
85 |
86 | return new Qiniu_Mac($QINIU_ACCESS_KEY, $QINIU_SECRET_KEY);
87 | }
88 |
89 | function Qiniu_Sign($mac, $data) // => $token
90 | {
91 | return Qiniu_RequireMac($mac)->Sign($data);
92 | }
93 |
94 | function Qiniu_SignWithData($mac, $data) // => $token
95 | {
96 | return Qiniu_RequireMac($mac)->SignWithData($data);
97 | }
98 |
99 | // ----------------------------------------------------------
100 |
101 |
--------------------------------------------------------------------------------
/sdk/conf.php:
--------------------------------------------------------------------------------
1 | ';
19 | $QINIU_SECRET_KEY = '';
20 |
21 |
--------------------------------------------------------------------------------
/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;
19 | $this->Err = $err;
20 | }
21 | }
22 |
23 | // --------------------------------------------------------------------------------
24 | // class Qiniu_Request
25 |
26 | class Qiniu_Request
27 | {
28 | public $URL;
29 | public $Header;
30 | public $Body;
31 | public $UA;
32 |
33 | public function __construct($url, $body)
34 | {
35 | $this->URL = $url;
36 | $this->Header = array();
37 | $this->Body = $body;
38 | $this->UA = Qiniu_UserAgent();
39 | }
40 | }
41 |
42 | // --------------------------------------------------------------------------------
43 | // class Qiniu_Response
44 |
45 | class Qiniu_Response
46 | {
47 | public $StatusCode;
48 | public $Header;
49 | public $ContentLength;
50 | public $Body;
51 |
52 | public function __construct($code, $body)
53 | {
54 | $this->StatusCode = $code;
55 | $this->Header = array();
56 | $this->Body = $body;
57 | $this->ContentLength = strlen($body);
58 | }
59 | }
60 |
61 | // --------------------------------------------------------------------------------
62 | // class Qiniu_Header
63 |
64 | function Qiniu_Header_Get($header, $key) // => $val
65 | {
66 | $val = @$header[$key];
67 | if (isset($val)) {
68 | if (is_array($val)) {
69 | return $val[0];
70 | }
71 | return $val;
72 | } else {
73 | return '';
74 | }
75 | }
76 |
77 | function Qiniu_ResponseError($resp) // => $error
78 | {
79 | $header = $resp->Header;
80 | $details = Qiniu_Header_Get($header, 'X-Log');
81 | $reqId = Qiniu_Header_Get($header, 'X-Reqid');
82 | $err = new Qiniu_Error($resp->StatusCode, null);
83 |
84 | if ($err->Code > 299) {
85 | if ($resp->ContentLength !== 0) {
86 | if (Qiniu_Header_Get($header, 'Content-Type') === 'application/json') {
87 | $ret = json_decode($resp->Body, true);
88 | $err->Err = $ret['error'];
89 | }
90 | }
91 | }
92 | $err->Reqid = $reqId;
93 | $err->Details = $details;
94 | return $err;
95 | }
96 |
97 | // --------------------------------------------------------------------------------
98 | // class Qiniu_Client
99 |
100 | function Qiniu_Client_incBody($req) // => $incbody
101 | {
102 | $body = $req->Body;
103 | if (!isset($body)) {
104 | return false;
105 | }
106 |
107 | $ct = Qiniu_Header_Get($req->Header, 'Content-Type');
108 | if ($ct === 'application/x-www-form-urlencoded') {
109 | return true;
110 | }
111 | return false;
112 | }
113 |
114 | function Qiniu_Client_do($req) // => ($resp, $error)
115 | {
116 | $ch = curl_init();
117 | $url = $req->URL;
118 | $options = array(
119 | CURLOPT_USERAGENT => $req->UA,
120 | CURLOPT_RETURNTRANSFER => true,
121 | CURLOPT_SSL_VERIFYPEER => false,
122 | CURLOPT_SSL_VERIFYHOST => false,
123 | CURLOPT_HEADER => true,
124 | CURLOPT_NOBODY => false,
125 | CURLOPT_CUSTOMREQUEST => 'POST',
126 | CURLOPT_URL => $url['path']
127 | );
128 | $httpHeader = $req->Header;
129 | if (!empty($httpHeader))
130 | {
131 | $header = array();
132 | foreach($httpHeader as $key => $parsedUrlValue) {
133 | $header[] = "$key: $parsedUrlValue";
134 | }
135 | $options[CURLOPT_HTTPHEADER] = $header;
136 | }
137 | $body = $req->Body;
138 | if (!empty($body)) {
139 | $options[CURLOPT_POSTFIELDS] = $body;
140 | } else {
141 | $options[CURLOPT_POSTFIELDS] = "";
142 | }
143 | curl_setopt_array($ch, $options);
144 | $result = curl_exec($ch);
145 | $ret = curl_errno($ch);
146 | if ($ret !== 0) {
147 | $err = new Qiniu_Error(0, curl_error($ch));
148 | curl_close($ch);
149 | return array(null, $err);
150 | }
151 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
152 | $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
153 | curl_close($ch);
154 |
155 | $responseArray = explode("\r\n\r\n", $result);
156 | $responseArraySize = sizeof($responseArray);
157 | $respHeader = $responseArray[$responseArraySize-2];
158 | $respBody = $responseArray[$responseArraySize-1];
159 |
160 | list($reqid, $xLog) = getReqInfo($respHeader);
161 |
162 | $resp = new Qiniu_Response($code, $respBody);
163 | $resp->Header['Content-Type'] = $contentType;
164 | $resp->Header["X-Reqid"] = $reqid;
165 | return array($resp, null);
166 | }
167 |
168 | function getReqInfo($headerContent) {
169 | $headers = explode("\r\n", $headerContent);
170 | $reqid = null;
171 | $xLog = null;
172 | foreach($headers as $header) {
173 | $header = trim($header);
174 | if(strpos($header, 'X-Reqid') !== false) {
175 | list($k, $v) = explode(':', $header);
176 | $reqid = trim($v);
177 | } elseif(strpos($header, 'X-Log') !== false) {
178 | list($k, $v) = explode(':', $header);
179 | $xLog = trim($v);
180 | }
181 | }
182 | return array($reqid, $xLog);
183 | }
184 |
185 | class Qiniu_HttpClient
186 | {
187 | public function RoundTrip($req) // => ($resp, $error)
188 | {
189 | return Qiniu_Client_do($req);
190 | }
191 | }
192 |
193 | class Qiniu_MacHttpClient
194 | {
195 | public $Mac;
196 |
197 | public function __construct($mac)
198 | {
199 | $this->Mac = Qiniu_RequireMac($mac);
200 | }
201 |
202 | public function RoundTrip($req) // => ($resp, $error)
203 | {
204 | $incbody = Qiniu_Client_incBody($req);
205 | $token = $this->Mac->SignRequest($req, $incbody);
206 | $req->Header['Authorization'] = "QBox $token";
207 | return Qiniu_Client_do($req);
208 | }
209 | }
210 |
211 | // --------------------------------------------------------------------------------
212 |
213 | function Qiniu_Client_ret($resp) // => ($data, $error)
214 | {
215 | $code = $resp->StatusCode;
216 | $data = null;
217 | if ($code >= 200 && $code <= 299) {
218 | if ($resp->ContentLength !== 0) {
219 | $data = json_decode($resp->Body, true);
220 | if ($data === null) {
221 | $err_msg = function_exists('json_last_error_msg') ? json_last_error_msg() : "error with content:" . $resp->Body;
222 | $err = new Qiniu_Error(0, $err_msg);
223 | return array(null, $err);
224 | }
225 | }
226 | if ($code === 200) {
227 | return array($data, null);
228 | }
229 | }
230 | return array($data, Qiniu_ResponseError($resp));
231 | }
232 |
233 | function Qiniu_Client_Call($self, $url) // => ($data, $error)
234 | {
235 | $u = array('path' => $url);
236 | $req = new Qiniu_Request($u, null);
237 | list($resp, $err) = $self->RoundTrip($req);
238 | if ($err !== null) {
239 | return array(null, $err);
240 | }
241 | return Qiniu_Client_ret($resp);
242 | }
243 |
244 | function Qiniu_Client_CallNoRet($self, $url) // => $error
245 | {
246 | $u = array('path' => $url);
247 | $req = new Qiniu_Request($u, null);
248 | list($resp, $err) = $self->RoundTrip($req);
249 | if ($err !== null) {
250 | return array(null, $err);
251 | }
252 | if ($resp->StatusCode === 200) {
253 | return null;
254 | }
255 | return Qiniu_ResponseError($resp);
256 | }
257 |
258 | function Qiniu_Client_CallWithForm(
259 | $self, $url, $params, $contentType = 'application/x-www-form-urlencoded') // => ($data, $error)
260 | {
261 | $u = array('path' => $url);
262 | if ($contentType === 'application/x-www-form-urlencoded') {
263 | if (is_array($params)) {
264 | $params = http_build_query($params);
265 | }
266 | }
267 | $req = new Qiniu_Request($u, $params);
268 | if ($contentType !== 'multipart/form-data') {
269 | $req->Header['Content-Type'] = $contentType;
270 | }
271 | list($resp, $err) = $self->RoundTrip($req);
272 | if ($err !== null) {
273 | return array(null, $err);
274 | }
275 | return Qiniu_Client_ret($resp);
276 | }
277 |
278 | // --------------------------------------------------------------------------------
279 |
280 | function Qiniu_Client_CallWithMultipartForm($self, $url, $fields, $files)
281 | {
282 | list($contentType, $body) = Qiniu_Build_MultipartForm($fields, $files);
283 | return Qiniu_Client_CallWithForm($self, $url, $body, $contentType);
284 | }
285 |
286 | function Qiniu_Build_MultipartForm($fields, $files) // => ($contentType, $body)
287 | {
288 | $data = array();
289 | $mimeBoundary = md5(microtime());
290 |
291 | foreach ($fields as $name => $val) {
292 | array_push($data, '--' . $mimeBoundary);
293 | array_push($data, "Content-Disposition: form-data; name=\"$name\"");
294 | array_push($data, '');
295 | array_push($data, $val);
296 | }
297 |
298 | foreach ($files as $file) {
299 | array_push($data, '--' . $mimeBoundary);
300 | list($name, $fileName, $fileBody, $mimeType) = $file;
301 | $mimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType;
302 | $fileName = Qiniu_escapeQuotes($fileName);
303 | array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$fileName\"");
304 | array_push($data, "Content-Type: $mimeType");
305 | array_push($data, '');
306 | array_push($data, $fileBody);
307 | }
308 |
309 | array_push($data, '--' . $mimeBoundary . '--');
310 | array_push($data, '');
311 |
312 | $body = implode("\r\n", $data);
313 | $contentType = 'multipart/form-data; boundary=' . $mimeBoundary;
314 | return array($contentType, $body);
315 | }
316 |
317 | function Qiniu_UserAgent() {
318 | global $SDK_VER;
319 | $sdkInfo = "QiniuPHP/$SDK_VER";
320 |
321 | $systemInfo = php_uname("s");
322 | $machineInfo = php_uname("m");
323 |
324 | $envInfo = "($systemInfo/$machineInfo)";
325 |
326 | $phpVer = phpversion();
327 |
328 | $ua = "$sdkInfo $envInfo PHP/$phpVer";
329 | return $ua;
330 | }
331 |
332 | function Qiniu_escapeQuotes($str)
333 | {
334 | $find = array("\\", "\"");
335 | $replace = array("\\\\", "\\\"");
336 | return str_replace($find, $replace, $str);
337 | }
338 |
339 | // --------------------------------------------------------------------------------
340 |
341 |
--------------------------------------------------------------------------------
/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 | if ($putExtra->Params) {
36 | foreach ($putExtra->Params as $k=>$v) {
37 | $fields[$k] = $v;
38 | }
39 | }
40 |
41 | $files = array(array('file', $fname, $body, $putExtra->MimeType));
42 |
43 | $client = new Qiniu_HttpClient;
44 | return Qiniu_Client_CallWithMultipartForm($client, $QINIU_UP_HOST, $fields, $files);
45 | }
46 |
47 | function createFile($filename, $mime)
48 | {
49 | // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax
50 | // See: https://wiki.php.net/rfc/curl-file-upload
51 | if (function_exists('curl_file_create')) {
52 | return curl_file_create($filename, $mime);
53 | }
54 |
55 | // Use the old style if using an older version of PHP
56 | $value = "@{$filename}";
57 | if (!empty($mime)) {
58 | $value .= ';type=' . $mime;
59 | }
60 |
61 | return $value;
62 | }
63 |
64 | function Qiniu_PutFile($upToken, $key, $localFile, $putExtra) // => ($putRet, $err)
65 | {
66 | global $QINIU_UP_HOST;
67 |
68 | if ($putExtra === null) {
69 | $putExtra = new Qiniu_PutExtra;
70 | }
71 |
72 | $fields = array('token' => $upToken, 'file' => createFile($localFile, $putExtra->MimeType));
73 | if ($key === null) {
74 | $fname = '?';
75 | } else {
76 | $fname = $key;
77 | $fields['key'] = $key;
78 | }
79 | if ($putExtra->CheckCrc) {
80 | if ($putExtra->CheckCrc === 1) {
81 | $hash = hash_file('crc32b', $localFile);
82 | $array = unpack('N', pack('H*', $hash));
83 | $putExtra->Crc32 = $array[1];
84 | }
85 | $fields['crc32'] = sprintf('%u', $putExtra->Crc32);
86 | }
87 | if ($putExtra->Params) {
88 | foreach ($putExtra->Params as $k=>$v) {
89 | $fields[$k] = $v;
90 | }
91 | }
92 |
93 | $client = new Qiniu_HttpClient;
94 | return Qiniu_Client_CallWithForm($client, $QINIU_UP_HOST, $fields, 'multipart/form-data');
95 | }
96 |
97 | // ----------------------------------------------------------
98 |
99 |
--------------------------------------------------------------------------------
/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 = new Qiniu_Error(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 = new Qiniu_Error(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 | if (!empty($extra->Params)) {
74 | foreach ($extra->Params as $k=>$v) {
75 | $url .= "/" . $k . "/" . Qiniu_Encode($v);
76 | }
77 | }
78 |
79 | $ctxs = array();
80 | foreach ($extra->Progresses as $prog) {
81 | $ctxs []= $prog['ctx'];
82 | }
83 | $body = implode(',', $ctxs);
84 |
85 | return Qiniu_Client_CallWithForm($self, $url, $body, 'application/octet-stream');
86 | }
87 |
88 | // ----------------------------------------------------------
89 | // class Qiniu_Rio_UploadClient
90 |
91 | class Qiniu_Rio_UploadClient
92 | {
93 | public $uptoken;
94 |
95 | public function __construct($uptoken)
96 | {
97 | $this->uptoken = $uptoken;
98 | }
99 |
100 | public function RoundTrip($req) // => ($resp, $error)
101 | {
102 | $token = $this->uptoken;
103 | $req->Header['Authorization'] = "UpToken $token";
104 | return Qiniu_Client_do($req);
105 | }
106 | }
107 |
108 | // ----------------------------------------------------------
109 | // class Qiniu_Rio_Put/PutFile
110 |
111 | function Qiniu_Rio_Put($upToken, $key, $body, $fsize, $putExtra) // => ($putRet, $err)
112 | {
113 | global $QINIU_UP_HOST;
114 |
115 | $self = new Qiniu_Rio_UploadClient($upToken);
116 |
117 | $progresses = array();
118 | $uploaded = 0;
119 | while ($uploaded < $fsize) {
120 | $tried = 0;
121 | $tryTimes = ($putExtra->TryTimes > 0) ? $putExtra->TryTimes : 1;
122 | $blkputRet = null;
123 | $err = null;
124 | if ($fsize < $uploaded + QINIU_RIO_BLOCK_SIZE) {
125 | $bsize = $fsize - $uploaded;
126 | } else {
127 | $bsize = QINIU_RIO_BLOCK_SIZE;
128 | }
129 | while ($tried < $tryTimes) {
130 | list($blkputRet, $err) = Qiniu_Rio_Mkblock($self, $QINIU_UP_HOST, $body, $bsize);
131 | if ($err === null) {
132 | break;
133 | }
134 | $tried += 1;
135 | continue;
136 | }
137 | if ($err !== null) {
138 | return array(null, $err);
139 | }
140 | if ($blkputRet === null ) {
141 | $err = new Qiniu_Error(0, "rio: uploaded without ret");
142 | return array(null, $err);
143 | }
144 | $uploaded += $bsize;
145 | $progresses []= $blkputRet;
146 | }
147 |
148 | $putExtra->Progresses = $progresses;
149 | return Qiniu_Rio_Mkfile($self, $QINIU_UP_HOST, $key, $fsize, $putExtra);
150 | }
151 |
152 | function Qiniu_Rio_PutFile($upToken, $key, $localFile, $putExtra) // => ($putRet, $err)
153 | {
154 | $fp = fopen($localFile, 'rb');
155 | if ($fp === false) {
156 | $err = new Qiniu_Error(0, 'fopen failed');
157 | return array(null, $err);
158 | }
159 |
160 | $fi = fstat($fp);
161 | $result = Qiniu_Rio_Put($upToken, $key, $fp, $fi['size'], $putExtra);
162 | fclose($fp);
163 | return $result;
164 | }
165 |
166 | // ----------------------------------------------------------
167 |
168 |
--------------------------------------------------------------------------------
/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 = str_replace("%2F", "/", 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 $PersistentPipeline;
58 | public $PersistentNotifyUrl;
59 | public $FopTimeout;
60 | public $MimeLimit;
61 |
62 | public function __construct($scope)
63 | {
64 | $this->Scope = $scope;
65 | }
66 |
67 | public function Token($mac) // => $token
68 | {
69 | $deadline = $this->Expires;
70 | if ($deadline == 0) {
71 | $deadline = 3600;
72 | }
73 | $deadline += time();
74 |
75 | $policy = array('scope' => $this->Scope, 'deadline' => $deadline);
76 | if (!empty($this->CallbackUrl)) {
77 | $policy['callbackUrl'] = $this->CallbackUrl;
78 | }
79 | if (!empty($this->CallbackBody)) {
80 | $policy['callbackBody'] = $this->CallbackBody;
81 | }
82 | if (!empty($this->ReturnUrl)) {
83 | $policy['returnUrl'] = $this->ReturnUrl;
84 | }
85 | if (!empty($this->ReturnBody)) {
86 | $policy['returnBody'] = $this->ReturnBody;
87 | }
88 | if (!empty($this->AsyncOps)) {
89 | $policy['asyncOps'] = $this->AsyncOps;
90 | }
91 | if (!empty($this->EndUser)) {
92 | $policy['endUser'] = $this->EndUser;
93 | }
94 | if (!empty($this->InsertOnly)) {
95 | $policy['exclusive'] = $this->InsertOnly;
96 | }
97 | if (!empty($this->DetectMime)) {
98 | $policy['detectMime'] = $this->DetectMime;
99 | }
100 | if (!empty($this->FsizeLimit)) {
101 | $policy['fsizeLimit'] = $this->FsizeLimit;
102 | }
103 | if (!empty($this->SaveKey)) {
104 | $policy['saveKey'] = $this->SaveKey;
105 | }
106 | if (!empty($this->PersistentOps)) {
107 | $policy['persistentOps'] = $this->PersistentOps;
108 | }
109 | if (!empty($this->PersistentPipeline)) {
110 | $policy['persistentPipeline'] = $this->PersistentPipeline;
111 | }
112 | if (!empty($this->PersistentNotifyUrl)) {
113 | $policy['persistentNotifyUrl'] = $this->PersistentNotifyUrl;
114 | }
115 | if (!empty($this->FopTimeout)) {
116 | $policy['fopTimeout'] = $this->FopTimeout;
117 | }
118 | if (!empty($this->MimeLimit)) {
119 | $policy['mimeLimit'] = $this->MimeLimit;
120 | }
121 |
122 |
123 | $b = json_encode($policy);
124 | return Qiniu_SignWithData($mac, $b);
125 | }
126 | }
127 |
128 | // ----------------------------------------------------------
129 | // class Qiniu_RS_EntryPath
130 |
131 | class Qiniu_RS_EntryPath
132 | {
133 | public $bucket;
134 | public $key;
135 |
136 | public function __construct($bucket, $key)
137 | {
138 | $this->bucket = $bucket;
139 | $this->key = $key;
140 | }
141 | }
142 |
143 | // ----------------------------------------------------------
144 | // class Qiniu_RS_EntryPathPair
145 |
146 | class Qiniu_RS_EntryPathPair
147 | {
148 | public $src;
149 | public $dest;
150 |
151 | public function __construct($src, $dest)
152 | {
153 | $this->src = $src;
154 | $this->dest = $dest;
155 | }
156 | }
157 |
158 | // ----------------------------------------------------------
159 |
160 | function Qiniu_RS_URIStat($bucket, $key)
161 | {
162 | return '/stat/' . Qiniu_Encode("$bucket:$key");
163 | }
164 |
165 | function Qiniu_RS_URIDelete($bucket, $key)
166 | {
167 | return '/delete/' . Qiniu_Encode("$bucket:$key");
168 | }
169 |
170 | function Qiniu_RS_URICopy($bucketSrc, $keySrc, $bucketDest, $keyDest)
171 | {
172 | return '/copy/' . Qiniu_Encode("$bucketSrc:$keySrc") . '/' . Qiniu_Encode("$bucketDest:$keyDest");
173 | }
174 |
175 | function Qiniu_RS_URIMove($bucketSrc, $keySrc, $bucketDest, $keyDest)
176 | {
177 | return '/move/' . Qiniu_Encode("$bucketSrc:$keySrc") . '/' . Qiniu_Encode("$bucketDest:$keyDest");
178 | }
179 |
180 | // ----------------------------------------------------------
181 |
182 | function Qiniu_RS_Stat($self, $bucket, $key) // => ($statRet, $error)
183 | {
184 | global $QINIU_RS_HOST;
185 | $uri = Qiniu_RS_URIStat($bucket, $key);
186 | return Qiniu_Client_Call($self, $QINIU_RS_HOST . $uri);
187 | }
188 |
189 | function Qiniu_RS_Delete($self, $bucket, $key) // => $error
190 | {
191 | global $QINIU_RS_HOST;
192 | $uri = Qiniu_RS_URIDelete($bucket, $key);
193 | return Qiniu_Client_CallNoRet($self, $QINIU_RS_HOST . $uri);
194 | }
195 |
196 | function Qiniu_RS_Move($self, $bucketSrc, $keySrc, $bucketDest, $keyDest) // => $error
197 | {
198 | global $QINIU_RS_HOST;
199 | $uri = Qiniu_RS_URIMove($bucketSrc, $keySrc, $bucketDest, $keyDest);
200 | return Qiniu_Client_CallNoRet($self, $QINIU_RS_HOST . $uri);
201 | }
202 |
203 | function Qiniu_RS_Copy($self, $bucketSrc, $keySrc, $bucketDest, $keyDest) // => $error
204 | {
205 | global $QINIU_RS_HOST;
206 | $uri = Qiniu_RS_URICopy($bucketSrc, $keySrc, $bucketDest, $keyDest);
207 | return Qiniu_Client_CallNoRet($self, $QINIU_RS_HOST . $uri);
208 | }
209 |
210 | // ----------------------------------------------------------
211 | // batch
212 |
213 | function Qiniu_RS_Batch($self, $ops) // => ($data, $error)
214 | {
215 | global $QINIU_RS_HOST;
216 | $url = $QINIU_RS_HOST . '/batch';
217 | $params = 'op=' . implode('&op=', $ops);
218 | return Qiniu_Client_CallWithForm($self, $url, $params);
219 | }
220 |
221 | function Qiniu_RS_BatchStat($self, $entryPaths)
222 | {
223 | $params = array();
224 | foreach ($entryPaths as $entryPath) {
225 | $params[] = Qiniu_RS_URIStat($entryPath->bucket, $entryPath->key);
226 | }
227 | return Qiniu_RS_Batch($self,$params);
228 | }
229 |
230 | function Qiniu_RS_BatchDelete($self, $entryPaths)
231 | {
232 | $params = array();
233 | foreach ($entryPaths as $entryPath) {
234 | $params[] = Qiniu_RS_URIDelete($entryPath->bucket, $entryPath->key);
235 | }
236 | return Qiniu_RS_Batch($self, $params);
237 | }
238 |
239 | function Qiniu_RS_BatchMove($self, $entryPairs)
240 | {
241 | $params = array();
242 | foreach ($entryPairs as $entryPair) {
243 | $src = $entryPair->src;
244 | $dest = $entryPair->dest;
245 | $params[] = Qiniu_RS_URIMove($src->bucket, $src->key, $dest->bucket, $dest->key);
246 | }
247 | return Qiniu_RS_Batch($self, $params);
248 | }
249 |
250 | function Qiniu_RS_BatchCopy($self, $entryPairs)
251 | {
252 | $params = array();
253 | foreach ($entryPairs as $entryPair) {
254 | $src = $entryPair->src;
255 | $dest = $entryPair->dest;
256 | $params[] = Qiniu_RS_URICopy($src->bucket, $src->key, $dest->bucket, $dest->key);
257 | }
258 | return Qiniu_RS_Batch($self, $params);
259 | }
260 |
261 | // ----------------------------------------------------------
262 |
263 |
--------------------------------------------------------------------------------
/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,
14 | // $markerOut, $err)
15 | {
16 | global $QINIU_RSF_HOST;
17 |
18 | $query = array (
19 | 'bucket' => $bucket
20 | );
21 | if (! empty ( $prefix )) {
22 | $query ['prefix'] = $prefix;
23 | }
24 | if (! empty ( $marker )) {
25 | $query ['marker'] = $marker;
26 | }
27 | if (! empty ( $limit )) {
28 | $query ['limit'] = $limit;
29 | }
30 |
31 | $url = $QINIU_RSF_HOST . '/list?' . http_build_query ( $query );
32 | list ( $ret, $err ) = Qiniu_Client_Call ( $self, $url );
33 | if ($err !== null) {
34 | return array (
35 | null,
36 | '',
37 | $err
38 | );
39 | }
40 |
41 | $items = $ret ['items'];
42 | if (empty ( $ret ['marker'] )) {
43 | $markerOut = '';
44 | $err = Qiniu_RSF_EOF;
45 | } else {
46 | $markerOut = $ret ['marker'];
47 | }
48 | return array (
49 | $items,
50 | $markerOut,
51 | $err
52 | );
53 | }
54 |
55 | /**
56 | * 从指定URL抓取资源,并将该资源存储到指定空间中
57 | *
58 | * @param $url 指定的URL
59 | * @param $bucket 目标资源空间
60 | * @param $key 目标资源文件名
61 | *
62 | * @return array[] 包含已拉取的文件信息。
63 | * 成功时: [
64 | * [
65 | * "hash" => "",
66 | * "key" => ""
67 | * ],
68 | * null
69 | * ]
70 | *
71 | * 失败时: [
72 | * null,
73 | * Qiniu/Http/Error
74 | * ]
75 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/fetch.html
76 | */
77 | function Qiniu_Fetch($self,$url, $bucket, $key) {
78 | global $QINIU_FETCH_HOST;
79 | $resource = base64_urlSafeEncode ( $url );
80 | $to = entry ( $bucket, $key );
81 | $url = $QINIU_FETCH_HOST . '/fetch/' . $resource . '/to/' . $to;
82 | return Qiniu_Client_Call ( $self, $url );
83 | }
84 |
85 | /**
86 | * 计算七牛API中的数据格式
87 | *
88 | * @param $bucket 待操作的空间名
89 | * @param $key 待操作的文件名
90 | *
91 | * @return 符合七牛API规格的数据格式
92 | * @link http://developer.qiniu.com/docs/v6/api/reference/data-formats.html
93 | */
94 | function entry($bucket, $key) {
95 | $en = $bucket;
96 | if (! empty ( $key )) {
97 | $en = $bucket . ':' . $key;
98 | }
99 | return base64_urlSafeEncode ( $en );
100 | }
101 |
102 |
103 | /**
104 | * 对提供的数据进行urlsafe的base64编码。
105 | *
106 | * @param string $data 待编码的数据,一般为字符串
107 | *
108 | * @return string 编码后的字符串
109 | * @link http://developer.qiniu.com/docs/v6/api/overview/appendix.html#urlsafe-base64
110 | */
111 | function base64_urlSafeEncode($data)
112 | {
113 | $find = array('+', '/');
114 | $replace = array('-', '_');
115 | return str_replace($find, $replace, base64_encode($data));
116 | }
--------------------------------------------------------------------------------
/sdk/utils.php:
--------------------------------------------------------------------------------
1 |