正在显示
29 个修改的文件
包含
4864 行增加
和
2 行删除
addons/qiniu/.addonrc
0 → 100644
1 | +{"license":"regular","licenseto":"44234","licensekey":"o5H8NqLjYQiTFa7C LedaRIu7u+RcuKDQofF9RQ=="} |
addons/qiniu/Qiniu.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\qiniu; | ||
4 | + | ||
5 | +use fast\Http; | ||
6 | +use Qiniu\Auth; | ||
7 | +use think\Addons; | ||
8 | +use think\Loader; | ||
9 | + | ||
10 | +/** | ||
11 | + * 七牛云储存插件 | ||
12 | + */ | ||
13 | +class Qiniu extends Addons | ||
14 | +{ | ||
15 | + | ||
16 | + /** | ||
17 | + * 插件安装方法 | ||
18 | + * @return bool | ||
19 | + */ | ||
20 | + public function install() | ||
21 | + { | ||
22 | + return true; | ||
23 | + } | ||
24 | + | ||
25 | + /** | ||
26 | + * 插件卸载方法 | ||
27 | + * @return bool | ||
28 | + */ | ||
29 | + public function uninstall() | ||
30 | + { | ||
31 | + return true; | ||
32 | + } | ||
33 | + | ||
34 | + /** | ||
35 | + * 上传初始化时 | ||
36 | + */ | ||
37 | + public function uploadConfigInit(&$upload) | ||
38 | + { | ||
39 | + $config = $this->getConfig(); | ||
40 | + | ||
41 | + $policy = array( | ||
42 | + 'saveKey' => ltrim($config['savekey'], '/'), | ||
43 | + ); | ||
44 | + | ||
45 | + $config['savekey'] = str_replace(['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)'], ['{year}', '{mon}', '{day}', '{filemd5}', '{.suffix}'], $config['savekey']); | ||
46 | + $auth = new Auth($config['accessKey'], $config['secretKey']); | ||
47 | + $multipart['qiniutoken'] = $auth->uploadToken($config['bucket'], null, $config['expire'], $policy); | ||
48 | + $upload = array_merge($upload, [ | ||
49 | + 'cdnurl' => $config['cdnurl'], | ||
50 | + 'uploadurl' => $config['uploadmode'] == 'client' ? $config['uploadurl'] : addon_url('qiniu/index/upload', [], false, true), | ||
51 | + 'uploadmode' => $config['uploadmode'], | ||
52 | + 'bucket' => $config['bucket'], | ||
53 | + 'maxsize' => $config['maxsize'], | ||
54 | + 'mimetype' => $config['mimetype'], | ||
55 | + 'savekey' => $config['savekey'], | ||
56 | + 'chunking' => (bool)($config['chunking'] ?? $upload['chunking']), | ||
57 | + 'chunksize' => (int)($config['chunksize'] ?? $upload['chunksize']), | ||
58 | + 'multipart' => $multipart, | ||
59 | + 'storage' => $this->getName(), | ||
60 | + 'multiple' => $config['multiple'] ? true : false, | ||
61 | + ]); | ||
62 | + } | ||
63 | + | ||
64 | + /** | ||
65 | + * 附件删除后 | ||
66 | + */ | ||
67 | + public function uploadDelete($attachment) | ||
68 | + { | ||
69 | + $config = $this->getConfig(); | ||
70 | + if ($attachment['storage'] == 'qiniu' && isset($config['syncdelete']) && $config['syncdelete']) { | ||
71 | + $auth = new Auth($config['accessKey'], $config['secretKey']); | ||
72 | + $entry = $config['bucket'] . ':' . ltrim($attachment->url, '/'); | ||
73 | + $encodedEntryURI = \Qiniu\base64_urlSafeEncode($entry); | ||
74 | + $url = 'http://rs.qiniu.com/delete/' . $encodedEntryURI; | ||
75 | + $headers = $auth->authorization($url); | ||
76 | + //删除云储存文件 | ||
77 | + $ret = Http::sendRequest($url, [], 'POST', [CURLOPT_HTTPHEADER => ['Authorization: ' . $headers['Authorization']]]); | ||
78 | + //如果是服务端中转,还需要删除本地文件 | ||
79 | + //if ($config['uploadmode'] == 'server') { | ||
80 | + // $filePath = ROOT_PATH . 'public' . str_replace('/', DS, $attachment->url); | ||
81 | + // if ($filePath) { | ||
82 | + // @unlink($filePath); | ||
83 | + // } | ||
84 | + //} | ||
85 | + } | ||
86 | + return true; | ||
87 | + } | ||
88 | + public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true) | ||
89 | + { | ||
90 | + $deadline = time() + $expires; | ||
91 | + $scope = $bucket; | ||
92 | + if ($key !== null) { | ||
93 | + $scope .= ':' . $key; | ||
94 | + } | ||
95 | + | ||
96 | + $args = self::copyPolicy($args, $policy, $strictPolicy); | ||
97 | + $args['scope'] = $scope; | ||
98 | + $args['deadline'] = $deadline; | ||
99 | + | ||
100 | + $b = json_encode($args); | ||
101 | + return $this->signWithData($b); | ||
102 | + } | ||
103 | + public function appInit() | ||
104 | + { | ||
105 | + if (!class_exists('\Qiniu\Config')) { | ||
106 | + Loader::addNamespace('Qiniu', ADDON_PATH . 'qiniu' . DS . 'library' . DS . 'Qiniu' . DS); | ||
107 | + require_once ADDON_PATH . 'qiniu' . DS . 'library' . DS . 'Qiniu' . DS . 'functions.php'; | ||
108 | + } | ||
109 | + } | ||
110 | + | ||
111 | +} |
addons/qiniu/bootstrap.js
0 → 100644
1 | +//修改上传的接口调用 | ||
2 | +require(['upload'], function (Upload) { | ||
3 | + | ||
4 | + //初始化中完成判断 | ||
5 | + Upload.events.onInit = function () { | ||
6 | + //如果上传接口不是七牛云,则不处理 | ||
7 | + if (this.options.url !== Config.upload.uploadurl) { | ||
8 | + return; | ||
9 | + } | ||
10 | + var _success = this.options.success; | ||
11 | + | ||
12 | + $.extend(this.options, { | ||
13 | + chunkSuccess: function (chunk, file, response) { | ||
14 | + this.contexts = this.contexts ? this.contexts : []; | ||
15 | + this.contexts.push(typeof response.ctx !== 'undefined' ? response.ctx : response.data.ctx); | ||
16 | + }, | ||
17 | + chunksUploaded: function (file, done) { | ||
18 | + var that = this; | ||
19 | + var params = $(that.element).data("params") || {}; | ||
20 | + var category = typeof params.category !== 'undefined' ? params.category : ($(that.element).data("category") || ''); | ||
21 | + Fast.api.ajax({ | ||
22 | + url: "/addons/qiniu/index/upload", | ||
23 | + data: { | ||
24 | + action: 'merge', | ||
25 | + filesize: file.size, | ||
26 | + filename: file.name, | ||
27 | + chunkid: file.upload.uuid, | ||
28 | + chunkcount: file.upload.totalChunkCount, | ||
29 | + width: file.width || 0, | ||
30 | + height: file.height || 0, | ||
31 | + type: file.type, | ||
32 | + category: category, | ||
33 | + qiniutoken: Config.upload.multipart.qiniutoken, | ||
34 | + contexts: this.contexts | ||
35 | + }, | ||
36 | + }, function (data, ret) { | ||
37 | + done(JSON.stringify(ret)); | ||
38 | + return false; | ||
39 | + }, function (data, ret) { | ||
40 | + file.accepted = false; | ||
41 | + that._errorProcessing([file], ret.msg); | ||
42 | + return false; | ||
43 | + }); | ||
44 | + | ||
45 | + }, | ||
46 | + }); | ||
47 | + | ||
48 | + //先移除已有的事件 | ||
49 | + this.off("success", _success).on("success", function (file, response) { | ||
50 | + var that = this; | ||
51 | + var ret = {code: 0, msg: response}; | ||
52 | + try { | ||
53 | + ret = typeof response === 'string' ? JSON.parse(response) : response; | ||
54 | + if (file.xhr.status === 200) { | ||
55 | + if (typeof ret.key !== 'undefined') { | ||
56 | + ret = {code: 1, msg: "", data: {url: '/' + ret.key, hash: ret.hash}}; | ||
57 | + } | ||
58 | + console.log(ret); | ||
59 | + var params = $(that.element).data("params") || {}; | ||
60 | + var category = typeof params.category !== 'undefined' ? params.category : ($(that.element).data("category") || ''); | ||
61 | + Fast.api.ajax({ | ||
62 | + url: "/addons/qiniu/index/notify", | ||
63 | + data: {name: file.name, url: ret.data.url, hash: ret.data.hash, size: file.size, width: file.width || 0, height: file.height || 0, type: file.type, category: category, qiniutoken: Config.upload.multipart.qiniutoken} | ||
64 | + }, function () { | ||
65 | + return false; | ||
66 | + }, function () { | ||
67 | + return false; | ||
68 | + }); | ||
69 | + } | ||
70 | + } catch (e) { | ||
71 | + console.error(e); | ||
72 | + } | ||
73 | + _success.call(this, file, ret); | ||
74 | + }); | ||
75 | + | ||
76 | + //如果是直传模式 | ||
77 | + if (Config.upload.uploadmode === 'client') { | ||
78 | + var _url = this.options.url; | ||
79 | + | ||
80 | + //分片上传时URL链接不同 | ||
81 | + this.options.url = function (files) { | ||
82 | + this.options.headers = {"Authorization": "UpToken " + Config.upload.multipart.qiniutoken}; | ||
83 | + if (files[0].upload.chunked) { | ||
84 | + var chunk = null; | ||
85 | + files[0].upload.chunks.forEach(function (item) { | ||
86 | + if (item.status === 'uploading') { | ||
87 | + chunk = item; | ||
88 | + } | ||
89 | + }); | ||
90 | + if (!chunk) { | ||
91 | + return Config.upload.uploadurl + '/mkfile/' + files[0].size; | ||
92 | + } else { | ||
93 | + return Config.upload.uploadurl + '/mkblk/' + chunk.dataBlock.data.size; | ||
94 | + } | ||
95 | + } | ||
96 | + return _url; | ||
97 | + }; | ||
98 | + | ||
99 | + this.options.params = function (files, xhr, chunk) { | ||
100 | + var params = Config.upload.multipart; | ||
101 | + if (chunk) { | ||
102 | + return $.extend({}, params, { | ||
103 | + filesize: chunk.file.size, | ||
104 | + filename: chunk.file.name, | ||
105 | + chunkid: chunk.file.upload.uuid, | ||
106 | + chunkindex: chunk.index, | ||
107 | + chunkcount: chunk.file.upload.totalChunkCount, | ||
108 | + chunkfilesize: chunk.dataBlock.data.size, | ||
109 | + width: chunk.file.width || 0, | ||
110 | + height: chunk.file.height || 0, | ||
111 | + type: chunk.file.type, | ||
112 | + }); | ||
113 | + } else { | ||
114 | + var retParams = $.extend({}, params); | ||
115 | + //七牛云直传使用的是token参数 | ||
116 | + retParams.token = retParams.qiniutoken; | ||
117 | + delete retParams.qiniutoken; | ||
118 | + return retParams; | ||
119 | + } | ||
120 | + }; | ||
121 | + | ||
122 | + //分片上传时需要变更提交的内容 | ||
123 | + this.on("sending", function (file, xhr, formData) { | ||
124 | + if (file.upload.chunked) { | ||
125 | + var _send = xhr.send; | ||
126 | + xhr.send = function () { | ||
127 | + var chunk = null; | ||
128 | + file.upload.chunks.forEach(function (item) { | ||
129 | + if (item.status == 'uploading') { | ||
130 | + chunk = item; | ||
131 | + } | ||
132 | + }); | ||
133 | + if (chunk) { | ||
134 | + _send.call(xhr, chunk.dataBlock.data); | ||
135 | + } | ||
136 | + }; | ||
137 | + } | ||
138 | + }); | ||
139 | + } | ||
140 | + }; | ||
141 | + | ||
142 | +}); |
addons/qiniu/config.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + [ | ||
5 | + 'name' => 'accessKey', | ||
6 | + 'title' => 'accessKey', | ||
7 | + 'type' => 'string', | ||
8 | + 'content' => [], | ||
9 | + 'value' => 'Eb_QX9JpdaILVbUx0ChfMfo0AFK-12J-eD0uVy25', | ||
10 | + 'rule' => 'required', | ||
11 | + 'msg' => '', | ||
12 | + 'tip' => '请在个人中心 > 密钥管理中获取 > AK', | ||
13 | + 'ok' => '', | ||
14 | + 'extend' => '', | ||
15 | + ], | ||
16 | + [ | ||
17 | + 'name' => 'secretKey', | ||
18 | + 'title' => 'secretKey', | ||
19 | + 'type' => 'string', | ||
20 | + 'content' => [], | ||
21 | + 'value' => 'VeqduMD6UzUvxkAiXc6e2N6w51N_KwppZXT3Kaix', | ||
22 | + 'rule' => 'required', | ||
23 | + 'msg' => '', | ||
24 | + 'tip' => '请在个人中心 > 密钥管理中获取 > SK', | ||
25 | + 'ok' => '', | ||
26 | + 'extend' => '', | ||
27 | + ], | ||
28 | + [ | ||
29 | + 'name' => 'bucket', | ||
30 | + 'title' => 'bucket', | ||
31 | + 'type' => 'string', | ||
32 | + 'content' => [], | ||
33 | + 'value' => 'shuiku', | ||
34 | + 'rule' => 'required', | ||
35 | + 'msg' => '', | ||
36 | + 'tip' => '存储空间名称', | ||
37 | + 'ok' => '', | ||
38 | + 'extend' => '', | ||
39 | + ], | ||
40 | + [ | ||
41 | + 'name' => 'uploadurl', | ||
42 | + 'title' => '上传接口地址', | ||
43 | + 'type' => 'select', | ||
44 | + 'content' => [ | ||
45 | + 'https://upload-z0.qiniup.com' => '华东 https://upload-z0.qiniup.com', | ||
46 | + 'https://upload-z1.qiniup.com' => '华北 https://upload-z1.qiniup.com', | ||
47 | + 'https://upload-z2.qiniup.com' => '华南 https://upload-z2.qiniup.com', | ||
48 | + 'https://upload-na0.qiniup.com' => '北美 https://upload-na0.qiniup.com', | ||
49 | + 'https://upload-as0.qiniup.com' => '东南亚 https://upload-as0.qiniup.com', | ||
50 | + 'https://up-cn-east-2.qiniup.com' => 'https://up-cn-east-2.qiniup.com', | ||
51 | + ], | ||
52 | + 'value' => 'https://upload-z2.qiniup.com', | ||
53 | + 'rule' => 'required', | ||
54 | + 'msg' => '', | ||
55 | + 'tip' => '推荐选择最近的地址', | ||
56 | + 'ok' => '', | ||
57 | + 'extend' => '', | ||
58 | + ], | ||
59 | + [ | ||
60 | + 'name' => 'cdnurl', | ||
61 | + 'title' => 'CDN地址', | ||
62 | + 'type' => 'string', | ||
63 | + 'content' => [], | ||
64 | + 'value' => 'https://qiniu.ynzhsk.cn', | ||
65 | + 'rule' => 'required', | ||
66 | + 'msg' => '', | ||
67 | + 'tip' => '未绑定CDN的话可使用七牛分配的测试域名', | ||
68 | + 'ok' => '', | ||
69 | + 'extend' => '', | ||
70 | + ], | ||
71 | + [ | ||
72 | + 'name' => 'uploadmode', | ||
73 | + 'title' => '上传模式', | ||
74 | + 'type' => 'select', | ||
75 | + 'content' => [ | ||
76 | + 'client' => '客户端直传(速度快,无备份)', | ||
77 | + 'server' => '服务器中转(占用服务器带宽,可备份)', | ||
78 | + ], | ||
79 | + 'value' => 'client', | ||
80 | + 'rule' => '', | ||
81 | + 'msg' => '', | ||
82 | + 'tip' => '启用服务器中转时务必配置操作员和密码', | ||
83 | + 'ok' => '', | ||
84 | + 'extend' => '', | ||
85 | + ], | ||
86 | + [ | ||
87 | + 'name' => 'serverbackup', | ||
88 | + 'title' => '服务器中转模式备份', | ||
89 | + 'type' => 'radio', | ||
90 | + 'content' => [ | ||
91 | + 1 => '备份(附件管理将产生2条记录)', | ||
92 | + 0 => '不备份', | ||
93 | + ], | ||
94 | + 'value' => '0', | ||
95 | + 'rule' => '', | ||
96 | + 'msg' => '', | ||
97 | + 'tip' => '服务器中转模式下是否备份文件', | ||
98 | + 'ok' => '', | ||
99 | + 'extend' => '', | ||
100 | + ], | ||
101 | + [ | ||
102 | + 'name' => 'savekey', | ||
103 | + 'title' => '保存文件名', | ||
104 | + 'type' => 'string', | ||
105 | + 'content' => [], | ||
106 | + 'value' => '/uploads/$(year)$(mon)$(day)/$(etag)$(ext)', | ||
107 | + 'rule' => 'required', | ||
108 | + 'msg' => '', | ||
109 | + 'tip' => '', | ||
110 | + 'ok' => '', | ||
111 | + 'extend' => '', | ||
112 | + ], | ||
113 | + [ | ||
114 | + 'name' => 'expire', | ||
115 | + 'title' => '上传有效时长', | ||
116 | + 'type' => 'string', | ||
117 | + 'content' => [], | ||
118 | + 'value' => '6000', | ||
119 | + 'rule' => 'required', | ||
120 | + 'msg' => '', | ||
121 | + 'tip' => '', | ||
122 | + 'ok' => '', | ||
123 | + 'extend' => '', | ||
124 | + ], | ||
125 | + [ | ||
126 | + 'name' => 'maxsize', | ||
127 | + 'title' => '最大可上传', | ||
128 | + 'type' => 'string', | ||
129 | + 'content' => [], | ||
130 | + 'value' => '500M', | ||
131 | + 'rule' => 'required', | ||
132 | + 'msg' => '', | ||
133 | + 'tip' => '', | ||
134 | + 'ok' => '', | ||
135 | + 'extend' => '', | ||
136 | + ], | ||
137 | + [ | ||
138 | + 'name' => 'mimetype', | ||
139 | + 'title' => '可上传后缀格式', | ||
140 | + 'type' => 'string', | ||
141 | + 'content' => [], | ||
142 | + 'value' => 'jpg,png,bmp,jpeg,gif,zip,rar,xls,xlsx,mp4,mov,doc,docx,html,gltf,apk,wgt', | ||
143 | + 'rule' => 'required', | ||
144 | + 'msg' => '', | ||
145 | + 'tip' => '', | ||
146 | + 'ok' => '', | ||
147 | + 'extend' => '', | ||
148 | + ], | ||
149 | + [ | ||
150 | + 'name' => 'multiple', | ||
151 | + 'title' => '多文件上传', | ||
152 | + 'type' => 'radio', | ||
153 | + 'content' => [ | ||
154 | + 1 => '开启', | ||
155 | + 0 => '关闭', | ||
156 | + ], | ||
157 | + 'value' => '0', | ||
158 | + 'rule' => 'required', | ||
159 | + 'msg' => '', | ||
160 | + 'tip' => '', | ||
161 | + 'ok' => '', | ||
162 | + 'extend' => '', | ||
163 | + ], | ||
164 | + [ | ||
165 | + 'name' => 'thumbstyle', | ||
166 | + 'title' => '缩略图样式', | ||
167 | + 'type' => 'string', | ||
168 | + 'content' => [], | ||
169 | + 'value' => '', | ||
170 | + 'rule' => '', | ||
171 | + 'msg' => '', | ||
172 | + 'tip' => '用于附件管理缩略图样式,可使用:?imageView2/2/w/120/h/90/q/80', | ||
173 | + 'ok' => '', | ||
174 | + 'extend' => '', | ||
175 | + ], | ||
176 | + [ | ||
177 | + 'name' => 'chunking', | ||
178 | + 'title' => '分片上传', | ||
179 | + 'type' => 'radio', | ||
180 | + 'content' => [ | ||
181 | + 1 => '开启', | ||
182 | + 0 => '关闭', | ||
183 | + ], | ||
184 | + 'value' => '0', | ||
185 | + 'rule' => 'required', | ||
186 | + 'msg' => '', | ||
187 | + 'tip' => '', | ||
188 | + 'ok' => '', | ||
189 | + 'extend' => '', | ||
190 | + ], | ||
191 | + [ | ||
192 | + 'name' => 'chunksize', | ||
193 | + 'title' => '分片大小', | ||
194 | + 'type' => 'number', | ||
195 | + 'content' => [], | ||
196 | + 'value' => '4194304', | ||
197 | + 'rule' => 'required', | ||
198 | + 'msg' => '', | ||
199 | + 'tip' => '固定大小,不能修改', | ||
200 | + 'ok' => '', | ||
201 | + 'extend' => 'readonly', | ||
202 | + ], | ||
203 | + [ | ||
204 | + 'name' => 'syncdelete', | ||
205 | + 'title' => '附件删除时是否同步删除文件', | ||
206 | + 'type' => 'bool', | ||
207 | + 'content' => [], | ||
208 | + 'value' => '1', | ||
209 | + 'rule' => 'required', | ||
210 | + 'msg' => '', | ||
211 | + 'tip' => '', | ||
212 | + 'ok' => '', | ||
213 | + 'extend' => '', | ||
214 | + ], | ||
215 | +]; |
addons/qiniu/controller/Index.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\qiniu\controller; | ||
4 | + | ||
5 | +use app\common\exception\UploadException; | ||
6 | +use app\common\library\Upload; | ||
7 | +use app\common\model\Attachment; | ||
8 | +use Qiniu\Auth; | ||
9 | +use Qiniu\Storage\ResumeUploader; | ||
10 | +use Qiniu\Storage\UploadManager; | ||
11 | +use think\addons\Controller; | ||
12 | +use think\Config; | ||
13 | + | ||
14 | +/** | ||
15 | + * 七牛管理 | ||
16 | + * | ||
17 | + */ | ||
18 | +class Index extends Controller | ||
19 | +{ | ||
20 | + | ||
21 | + public function _initialize() | ||
22 | + { | ||
23 | + //跨域检测 | ||
24 | + check_cors_request(); | ||
25 | + | ||
26 | + parent::_initialize(); | ||
27 | + Config::set('default_return_type', 'json'); | ||
28 | + } | ||
29 | + | ||
30 | + public function index() | ||
31 | + { | ||
32 | + Config::set('default_return_type', 'html'); | ||
33 | + $this->error("当前插件暂无前台页面"); | ||
34 | + } | ||
35 | + | ||
36 | + /** | ||
37 | + * 中转上传文件 | ||
38 | + * 上传分片 | ||
39 | + * 合并分片 | ||
40 | + */ | ||
41 | + public function upload() | ||
42 | + { | ||
43 | + Config::set('default_return_type', 'json'); | ||
44 | + | ||
45 | + //$this->check(); | ||
46 | + $config = get_addon_config('qiniu'); | ||
47 | + $config['savekey'] = str_replace(['{year}', '{mon}', '{day}', '{filemd5}', '{.suffix}'], ['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)'], $config['savekey']); | ||
48 | + | ||
49 | + // 构建鉴权对象 | ||
50 | + $auth = new Auth($config['accessKey'], $config['secretKey']); | ||
51 | + | ||
52 | + // 生成上传 Token | ||
53 | + $token = $auth->uploadToken($config['bucket'], null, 3600, ['saveKey' => ltrim($config['savekey'], '/')]); | ||
54 | + // 初始化 UploadManager 对象并进行文件的上传。 | ||
55 | + $uploadMgr = new UploadManager(); | ||
56 | + | ||
57 | + //检测删除文件或附件 | ||
58 | + $checkDeleteFile = function ($attachment, $upload, $force = false) use ($config) { | ||
59 | + //如果设定为不备份则删除文件和记录 或 强制删除 | ||
60 | + if ((isset($config['serverbackup']) && !$config['serverbackup']) || $force) { | ||
61 | + if ($attachment) { | ||
62 | + $attachment->delete(); | ||
63 | + } | ||
64 | + if ($upload) { | ||
65 | + //文件绝对路径 | ||
66 | + $filePath = $upload->getFile()->getRealPath() ?: $upload->getFile()->getPathname(); | ||
67 | + @unlink($filePath); | ||
68 | + } | ||
69 | + } | ||
70 | + }; | ||
71 | + | ||
72 | + $chunkid = $this->request->post("chunkid"); | ||
73 | + if ($chunkid) { | ||
74 | + $action = $this->request->post("action"); | ||
75 | + $chunkindex = $this->request->post("chunkindex/d"); | ||
76 | + $chunkcount = $this->request->post("chunkcount/d"); | ||
77 | + $filesize = $this->request->post("filesize"); | ||
78 | + $filename = $this->request->post("filename"); | ||
79 | + if ($action == 'merge') { | ||
80 | + $attachment = null; | ||
81 | + $upload = null; | ||
82 | + if ($config['uploadmode'] == 'server') { | ||
83 | + //合并分片文件 | ||
84 | + try { | ||
85 | + $upload = new Upload(); | ||
86 | + $attachment = $upload->merge($chunkid, $chunkcount, $filename); | ||
87 | + } catch (UploadException $e) { | ||
88 | + $this->error($e->getMessage()); | ||
89 | + } | ||
90 | + } | ||
91 | + | ||
92 | + $contexts = $this->request->post("contexts/a", []); | ||
93 | + $uploader = new ResumeUploader($token, null, null, $filesize); | ||
94 | + list($ret, $err) = $uploader->setContexts($contexts)->makeFile($filename); | ||
95 | + if ($err !== null) { | ||
96 | + $checkDeleteFile($attachment, $upload, true); | ||
97 | + $this->error("上传失败"); | ||
98 | + } else { | ||
99 | + $checkDeleteFile($attachment, $upload); | ||
100 | + $this->success("上传成功", '', ['url' => '/' . $ret['key'], 'fullurl' => cdnurl('/' . $ret['key'], true), 'hash' => $ret['hash']]); | ||
101 | + } | ||
102 | + } else { | ||
103 | + //默认普通上传文件 | ||
104 | + $file = $this->request->file('file'); | ||
105 | + try { | ||
106 | + $upload = new Upload($file); | ||
107 | + $file = $upload->chunk($chunkid, $chunkindex, $chunkcount); | ||
108 | + } catch (UploadException $e) { | ||
109 | + $this->error($e->getMessage()); | ||
110 | + } | ||
111 | + | ||
112 | + //上传分片文件 | ||
113 | + //$file = $this->request->file('file'); | ||
114 | + $filesize = $file->getSize(); | ||
115 | + //合并分片文件 | ||
116 | + $uploader = new ResumeUploader($token, null, fopen($file->getRealPath(), 'rb'), $filesize); | ||
117 | + $ret = $uploader->uploadChunk($chunkindex, $file, $filesize); | ||
118 | + $this->success("上传成功", "", $ret); | ||
119 | + } | ||
120 | + } else { | ||
121 | + $attachment = null; | ||
122 | + //默认普通上传文件 | ||
123 | + $file = $this->request->file('file'); | ||
124 | + try { | ||
125 | + $upload = new Upload($file); | ||
126 | + | ||
127 | + $suffix = $upload->getSuffix(); | ||
128 | + $md5 = md5_file($file->getRealPath()); | ||
129 | + | ||
130 | + | ||
131 | + $search = ['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)']; | ||
132 | + $replace = [date("Y"), date("m"), date("d"), $md5, '.' . $suffix]; | ||
133 | + $savekey = ltrim(str_replace($search, $replace, $config['savekey']), '/'); | ||
134 | + $size = $upload->getFile()->getSize(); | ||
135 | + $attachment = $upload->upload($savekey); | ||
136 | + } catch (UploadException $e) { | ||
137 | + $this->error($e->getMessage()); | ||
138 | + } | ||
139 | + | ||
140 | + //文件绝对路径 | ||
141 | + $filePath = $upload->getFile()->getRealPath() ?: $upload->getFile()->getPathname(); | ||
142 | + | ||
143 | + //上传到七牛后保存的文件名 | ||
144 | + $saveKey = ltrim($attachment->url, '/'); | ||
145 | + | ||
146 | + $url = $attachment->url; | ||
147 | + | ||
148 | + try { | ||
149 | + // 调用 UploadManager 的 putFile 方法进行文件的上传。 | ||
150 | + list($ret, $err) = $uploadMgr->putFile($token, $saveKey, $filePath); | ||
151 | + | ||
152 | + if ($err !== null) { | ||
153 | + throw new \Exception("上传失败"); | ||
154 | + } | ||
155 | + //成功不做任何操作 | ||
156 | + } catch (\Exception $e) { | ||
157 | + $checkDeleteFile($attachment, $upload, true); | ||
158 | + $this->error("上传失败"); | ||
159 | + } | ||
160 | + $hash = md5_file($filePath); | ||
161 | + $checkDeleteFile($attachment, $upload); | ||
162 | + $this->success("上传成功", '', ['url' => $url, 'fullurl' => cdnurl($url, true), 'hash' => $hash, 'size' => $size]); | ||
163 | + } | ||
164 | + } | ||
165 | + | ||
166 | + /** | ||
167 | + * 通知回调 | ||
168 | + */ | ||
169 | + public function notify() | ||
170 | + { | ||
171 | + Config::set('default_return_type', 'json'); | ||
172 | + | ||
173 | + $this->check(); | ||
174 | + | ||
175 | + $size = $this->request->post('size/d'); | ||
176 | + $name = $this->request->post('name', ''); | ||
177 | + $hash = $this->request->post('hash', ''); | ||
178 | + $type = $this->request->post('type', ''); | ||
179 | + $url = $this->request->post('url', ''); | ||
180 | + $width = $this->request->post('width/d'); | ||
181 | + $height = $this->request->post('height/d'); | ||
182 | + $category = $this->request->post('category', ''); | ||
183 | + $suffix = substr($name, stripos($name, '.') + 1); | ||
184 | + $attachment = Attachment::where('url', $url)->where('storage', 'qiniu')->find(); | ||
185 | + if (!$attachment) { | ||
186 | + $params = array( | ||
187 | + 'category' => $category, | ||
188 | + 'admin_id' => (int)session('admin.id'), | ||
189 | + 'user_id' => (int)cookie('uid'), | ||
190 | + 'filename' => $name, | ||
191 | + 'filesize' => $size, | ||
192 | + 'imagewidth' => $width, | ||
193 | + 'imageheight' => $height, | ||
194 | + 'imagetype' => $suffix, | ||
195 | + 'imageframes' => 0, | ||
196 | + 'mimetype' => $type, | ||
197 | + 'url' => $url, | ||
198 | + 'uploadtime' => time(), | ||
199 | + 'storage' => 'qiniu', | ||
200 | + 'sha1' => $hash, | ||
201 | + ); | ||
202 | + Attachment::create($params); | ||
203 | + } | ||
204 | + $this->success(); | ||
205 | + } | ||
206 | + | ||
207 | + /** | ||
208 | + * 检查签名是否正确或过期 | ||
209 | + */ | ||
210 | + protected function check() | ||
211 | + { | ||
212 | + $qiniutoken = $this->request->post('qiniutoken', $this->request->server('AUTHORIZATION'), 'trim'); | ||
213 | + if (!$qiniutoken) { | ||
214 | + $this->error("参数不正确"); | ||
215 | + } | ||
216 | + $config = get_addon_config('qiniu'); | ||
217 | + $auth = new Auth($config['accessKey'], $config['secretKey']); | ||
218 | + list($accessKey, $sign, $data) = explode(':', $qiniutoken); | ||
219 | + if (!$accessKey || !$sign || !$data) { | ||
220 | + $this->error("参数不正确"); | ||
221 | + } | ||
222 | + if ($accessKey !== $config['accessKey']) { | ||
223 | + $this->error("参数不正确"); | ||
224 | + } | ||
225 | + if ($accessKey . ':' . $sign !== $auth->sign($data)) { | ||
226 | + $this->error("签名不正确"); | ||
227 | + } | ||
228 | + $json = json_decode(\Qiniu\base64_urlSafeDecode($data), true); | ||
229 | + if ($json['deadline'] < time()) { | ||
230 | + $this->error("请求已经超时"); | ||
231 | + } | ||
232 | + } | ||
233 | +} |
addons/qiniu/info.ini
0 → 100644
addons/qiniu/library/Qiniu/Auth.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu; | ||
3 | + | ||
4 | +use Qiniu\Zone; | ||
5 | + | ||
6 | +final class Auth | ||
7 | +{ | ||
8 | + private $accessKey; | ||
9 | + private $secretKey; | ||
10 | + | ||
11 | + public function __construct($accessKey, $secretKey) | ||
12 | + { | ||
13 | + $this->accessKey = $accessKey; | ||
14 | + $this->secretKey = $secretKey; | ||
15 | + } | ||
16 | + | ||
17 | + public function getAccessKey() | ||
18 | + { | ||
19 | + return $this->accessKey; | ||
20 | + } | ||
21 | + | ||
22 | + public function sign($data) | ||
23 | + { | ||
24 | + $hmac = hash_hmac('sha1', $data, $this->secretKey, true); | ||
25 | + return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac); | ||
26 | + } | ||
27 | + | ||
28 | + public function signWithData($data) | ||
29 | + { | ||
30 | + $encodedData = \Qiniu\base64_urlSafeEncode($data); | ||
31 | + return $this->sign($encodedData) . ':' . $encodedData; | ||
32 | + } | ||
33 | + | ||
34 | + public function signRequest($urlString, $body, $contentType = null) | ||
35 | + { | ||
36 | + $url = parse_url($urlString); | ||
37 | + $data = ''; | ||
38 | + if (array_key_exists('path', $url)) { | ||
39 | + $data = $url['path']; | ||
40 | + } | ||
41 | + if (array_key_exists('query', $url)) { | ||
42 | + $data .= '?' . $url['query']; | ||
43 | + } | ||
44 | + $data .= "\n"; | ||
45 | + | ||
46 | + if ($body !== null && $contentType === 'application/x-www-form-urlencoded') { | ||
47 | + $data .= $body; | ||
48 | + } | ||
49 | + return $this->sign($data); | ||
50 | + } | ||
51 | + | ||
52 | + public function verifyCallback($contentType, $originAuthorization, $url, $body) | ||
53 | + { | ||
54 | + $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); | ||
55 | + return $originAuthorization === $authorization; | ||
56 | + } | ||
57 | + | ||
58 | + public function privateDownloadUrl($baseUrl, $expires = 3600) | ||
59 | + { | ||
60 | + $deadline = time() + $expires; | ||
61 | + | ||
62 | + $pos = strpos($baseUrl, '?'); | ||
63 | + if ($pos !== false) { | ||
64 | + $baseUrl .= '&e='; | ||
65 | + } else { | ||
66 | + $baseUrl .= '?e='; | ||
67 | + } | ||
68 | + $baseUrl .= $deadline; | ||
69 | + | ||
70 | + $token = $this->sign($baseUrl); | ||
71 | + return "$baseUrl&token=$token"; | ||
72 | + } | ||
73 | + | ||
74 | + public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true) | ||
75 | + { | ||
76 | + $deadline = time() + $expires; | ||
77 | + $scope = $bucket; | ||
78 | + if ($key !== null) { | ||
79 | + $scope .= ':' . $key; | ||
80 | + } | ||
81 | + | ||
82 | + $args = self::copyPolicy($args, $policy, $strictPolicy); | ||
83 | + $args['scope'] = $scope; | ||
84 | + $args['deadline'] = $deadline; | ||
85 | + | ||
86 | + $b = json_encode($args); | ||
87 | + return $this->signWithData($b); | ||
88 | + } | ||
89 | + | ||
90 | + /** | ||
91 | + *上传策略,参数规格详见 | ||
92 | + *http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html | ||
93 | + */ | ||
94 | + private static $policyFields = array( | ||
95 | + 'callbackUrl', | ||
96 | + 'callbackBody', | ||
97 | + 'callbackHost', | ||
98 | + 'callbackBodyType', | ||
99 | + 'callbackFetchKey', | ||
100 | + | ||
101 | + 'returnUrl', | ||
102 | + 'returnBody', | ||
103 | + | ||
104 | + 'endUser', | ||
105 | + 'saveKey', | ||
106 | + 'insertOnly', | ||
107 | + | ||
108 | + 'detectMime', | ||
109 | + 'mimeLimit', | ||
110 | + 'fsizeMin', | ||
111 | + 'fsizeLimit', | ||
112 | + | ||
113 | + 'persistentOps', | ||
114 | + 'persistentNotifyUrl', | ||
115 | + 'persistentPipeline', | ||
116 | + | ||
117 | + 'deleteAfterDays', | ||
118 | + 'fileType', | ||
119 | + 'isPrefixalScope', | ||
120 | + ); | ||
121 | + | ||
122 | + private static function copyPolicy(&$policy, $originPolicy, $strictPolicy) | ||
123 | + { | ||
124 | + if ($originPolicy === null) { | ||
125 | + return array(); | ||
126 | + } | ||
127 | + foreach ($originPolicy as $key => $value) { | ||
128 | + if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) { | ||
129 | + $policy[$key] = $value; | ||
130 | + } | ||
131 | + } | ||
132 | + return $policy; | ||
133 | + } | ||
134 | + | ||
135 | + public function authorization($url, $body = null, $contentType = null) | ||
136 | + { | ||
137 | + $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); | ||
138 | + return array('Authorization' => $authorization); | ||
139 | + } | ||
140 | + | ||
141 | + public function authorizationV2($url, $method, $body = null, $contentType = null) | ||
142 | + { | ||
143 | + $urlItems = parse_url($url); | ||
144 | + $host = $urlItems['host']; | ||
145 | + | ||
146 | + if (isset($urlItems['port'])) { | ||
147 | + $port = $urlItems['port']; | ||
148 | + } else { | ||
149 | + $port = ''; | ||
150 | + } | ||
151 | + | ||
152 | + $path = $urlItems['path']; | ||
153 | + if (isset($urlItems['query'])) { | ||
154 | + $query = $urlItems['query']; | ||
155 | + } else { | ||
156 | + $query = ''; | ||
157 | + } | ||
158 | + | ||
159 | + //write request uri | ||
160 | + $toSignStr = $method . ' ' . $path; | ||
161 | + if (!empty($query)) { | ||
162 | + $toSignStr .= '?' . $query; | ||
163 | + } | ||
164 | + | ||
165 | + //write host and port | ||
166 | + $toSignStr .= "\nHost: " . $host; | ||
167 | + if (!empty($port)) { | ||
168 | + $toSignStr .= ":" . $port; | ||
169 | + } | ||
170 | + | ||
171 | + //write content type | ||
172 | + if (!empty($contentType)) { | ||
173 | + $toSignStr .= "\nContent-Type: " . $contentType; | ||
174 | + } | ||
175 | + | ||
176 | + $toSignStr .= "\n\n"; | ||
177 | + | ||
178 | + //write body | ||
179 | + if (!empty($body)) { | ||
180 | + $toSignStr .= $body; | ||
181 | + } | ||
182 | + | ||
183 | + $sign = $this->sign($toSignStr); | ||
184 | + $auth = 'Qiniu ' . $sign; | ||
185 | + return array('Authorization' => $auth); | ||
186 | + } | ||
187 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu\Cdn; | ||
4 | + | ||
5 | +use Qiniu\Auth; | ||
6 | +use Qiniu\Http\Error; | ||
7 | +use Qiniu\Http\Client; | ||
8 | + | ||
9 | +final class CdnManager | ||
10 | +{ | ||
11 | + | ||
12 | + private $auth; | ||
13 | + private $server; | ||
14 | + | ||
15 | + public function __construct(Auth $auth) | ||
16 | + { | ||
17 | + $this->auth = $auth; | ||
18 | + $this->server = 'http://fusion.qiniuapi.com'; | ||
19 | + } | ||
20 | + | ||
21 | + /** | ||
22 | + * @param array $urls 待刷新的文件链接数组 | ||
23 | + * @return array | ||
24 | + */ | ||
25 | + public function refreshUrls(array $urls) | ||
26 | + { | ||
27 | + return $this->refreshUrlsAndDirs($urls, array()); | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * @param array $dirs 待刷新的文件链接数组 | ||
32 | + * @return array | ||
33 | + * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh | ||
34 | + * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category | ||
35 | + */ | ||
36 | + public function refreshDirs(array $dirs) | ||
37 | + { | ||
38 | + return $this->refreshUrlsAndDirs(array(), $dirs); | ||
39 | + } | ||
40 | + | ||
41 | + /** | ||
42 | + * @param array $urls 待刷新的文件链接数组 | ||
43 | + * @param array $dirs 待刷新的目录链接数组 | ||
44 | + * | ||
45 | + * @return array 刷新的请求回复和错误,参考 examples/cdn_manager.php 代码 | ||
46 | + * @link http://developer.qiniu.com/article/fusion/api/refresh.html | ||
47 | + * | ||
48 | + * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh | ||
49 | + * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category | ||
50 | + */ | ||
51 | + public function refreshUrlsAndDirs(array $urls, array $dirs) | ||
52 | + { | ||
53 | + $req = array(); | ||
54 | + if (!empty($urls)) { | ||
55 | + $req['urls'] = $urls; | ||
56 | + } | ||
57 | + if (!empty($dirs)) { | ||
58 | + $req['dirs'] = $dirs; | ||
59 | + } | ||
60 | + | ||
61 | + $url = $this->server . '/v2/tune/refresh'; | ||
62 | + $body = json_encode($req); | ||
63 | + return $this->post($url, $body); | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * @param array $urls 待预取的文件链接数组 | ||
68 | + * | ||
69 | + * @return array 预取的请求回复和错误,参考 examples/cdn_manager.php 代码 | ||
70 | + * | ||
71 | + * @link http://developer.qiniu.com/article/fusion/api/refresh.html | ||
72 | + */ | ||
73 | + public function prefetchUrls(array $urls) | ||
74 | + { | ||
75 | + $req = array( | ||
76 | + 'urls' => $urls, | ||
77 | + ); | ||
78 | + | ||
79 | + $url = $this->server . '/v2/tune/prefetch'; | ||
80 | + $body = json_encode($req); | ||
81 | + return $this->post($url, $body); | ||
82 | + } | ||
83 | + | ||
84 | + /** | ||
85 | + * @param array $domains 待获取带宽数据的域名数组 | ||
86 | + * @param string $startDate 开始的日期,格式类似 2017-01-01 | ||
87 | + * @param string $endDate 结束的日期,格式类似 2017-01-01 | ||
88 | + * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day | ||
89 | + * | ||
90 | + * @return array 带宽数据和错误信息,参考 examples/cdn_manager.php 代码 | ||
91 | + * | ||
92 | + * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html | ||
93 | + */ | ||
94 | + public function getBandwidthData(array $domains, $startDate, $endDate, $granularity) | ||
95 | + { | ||
96 | + $req = array(); | ||
97 | + $req['domains'] = implode(';', $domains); | ||
98 | + $req['startDate'] = $startDate; | ||
99 | + $req['endDate'] = $endDate; | ||
100 | + $req['granularity'] = $granularity; | ||
101 | + | ||
102 | + $url = $this->server . '/v2/tune/bandwidth'; | ||
103 | + $body = json_encode($req); | ||
104 | + return $this->post($url, $body); | ||
105 | + } | ||
106 | + | ||
107 | + /** | ||
108 | + * @param array $domains 待获取流量数据的域名数组 | ||
109 | + * @param string $startDate 开始的日期,格式类似 2017-01-01 | ||
110 | + * @param string $endDate 结束的日期,格式类似 2017-01-01 | ||
111 | + * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day | ||
112 | + * | ||
113 | + * @return array 流量数据和错误信息,参考 examples/cdn_manager.php 代码 | ||
114 | + * | ||
115 | + * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html | ||
116 | + */ | ||
117 | + public function getFluxData(array $domains, $startDate, $endDate, $granularity) | ||
118 | + { | ||
119 | + $req = array(); | ||
120 | + $req['domains'] = implode(';', $domains); | ||
121 | + $req['startDate'] = $startDate; | ||
122 | + $req['endDate'] = $endDate; | ||
123 | + $req['granularity'] = $granularity; | ||
124 | + | ||
125 | + $url = $this->server . '/v2/tune/flux'; | ||
126 | + $body = json_encode($req); | ||
127 | + return $this->post($url, $body); | ||
128 | + } | ||
129 | + | ||
130 | + /** | ||
131 | + * @param array $domains 待获取日志下载链接的域名数组 | ||
132 | + * @param string $logDate 获取指定日期的日志下载链接,格式类似 2017-01-01 | ||
133 | + * | ||
134 | + * @return array 日志下载链接数据和错误信息,参考 examples/cdn_manager.php 代码 | ||
135 | + * | ||
136 | + * @link http://developer.qiniu.com/article/fusion/api/log.html | ||
137 | + */ | ||
138 | + public function getCdnLogList(array $domains, $logDate) | ||
139 | + { | ||
140 | + $req = array(); | ||
141 | + $req['domains'] = implode(';', $domains); | ||
142 | + $req['day'] = $logDate; | ||
143 | + | ||
144 | + $url = $this->server . '/v2/tune/log/list'; | ||
145 | + $body = json_encode($req); | ||
146 | + return $this->post($url, $body); | ||
147 | + } | ||
148 | + | ||
149 | + private function post($url, $body) | ||
150 | + { | ||
151 | + $headers = $this->auth->authorization($url, $body, 'application/json'); | ||
152 | + $headers['Content-Type'] = 'application/json'; | ||
153 | + $ret = Client::post($url, $body, $headers); | ||
154 | + if (!$ret->ok()) { | ||
155 | + return array(null, new Error($url, $ret)); | ||
156 | + } | ||
157 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
158 | + return array($r, null); | ||
159 | + } | ||
160 | + | ||
161 | + /** | ||
162 | + * 构建时间戳防盗链鉴权的访问外链 | ||
163 | + * | ||
164 | + * @param string $rawUrl 需要签名的资源url | ||
165 | + * @param string $encryptKey 时间戳防盗链密钥 | ||
166 | + * @param string $durationInSeconds 链接的有效期(以秒为单位) | ||
167 | + * | ||
168 | + * @return string 带鉴权信息的资源外链,参考 examples/cdn_timestamp_antileech.php 代码 | ||
169 | + */ | ||
170 | + public static function createTimestampAntiLeechUrl($rawUrl, $encryptKey, $durationInSeconds) | ||
171 | + { | ||
172 | + $parsedUrl = parse_url($rawUrl); | ||
173 | + $deadline = time() + $durationInSeconds; | ||
174 | + $expireHex = dechex($deadline); | ||
175 | + $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : ''; | ||
176 | + $strToSign = $encryptKey . $path . $expireHex; | ||
177 | + $signStr = md5($strToSign); | ||
178 | + if (isset($parsedUrl['query'])) { | ||
179 | + $signedUrl = $rawUrl . '&sign=' . $signStr . '&t=' . $expireHex; | ||
180 | + } else { | ||
181 | + $signedUrl = $rawUrl . '?sign=' . $signStr . '&t=' . $expireHex; | ||
182 | + } | ||
183 | + return $signedUrl; | ||
184 | + } | ||
185 | +} |
addons/qiniu/library/Qiniu/Config.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu; | ||
3 | + | ||
4 | +final class Config | ||
5 | +{ | ||
6 | + const SDK_VER = '7.2.10'; | ||
7 | + | ||
8 | + const BLOCK_SIZE = 4194304; //4*1024*1024 分块上传块大小,该参数为接口规格,不能修改 | ||
9 | + | ||
10 | + const RSF_HOST = 'rsf.qiniu.com'; | ||
11 | + const API_HOST = 'api.qiniu.com'; | ||
12 | + const RS_HOST = 'rs.qiniu.com'; //RS Host | ||
13 | + const UC_HOST = 'uc.qbox.me'; //UC Host | ||
14 | + const RTCAPI_HOST = 'http://rtc.qiniuapi.com'; | ||
15 | + const ARGUS_HOST = 'argus.atlab.ai'; | ||
16 | + const CASTER_HOST = 'pili-caster.qiniuapi.com'; | ||
17 | + const SMS_HOST="https://sms.qiniuapi.com"; | ||
18 | + const RTCAPI_VERSION = 'v3'; | ||
19 | + const SMS_VERSION='v1'; | ||
20 | + | ||
21 | + // Zone 空间对应的存储区域 | ||
22 | + public $region; | ||
23 | + //BOOL 是否使用https域名 | ||
24 | + public $useHTTPS; | ||
25 | + //BOOL 是否使用CDN加速上传域名 | ||
26 | + public $useCdnDomains; | ||
27 | + // Zone Cache | ||
28 | + private $regionCache; | ||
29 | + | ||
30 | + // 构造函数 | ||
31 | + public function __construct(Region $z = null) | ||
32 | + { | ||
33 | + $this->zone = $z; | ||
34 | + $this->useHTTPS = false; | ||
35 | + $this->useCdnDomains = false; | ||
36 | + $this->regionCache = array(); | ||
37 | + } | ||
38 | + | ||
39 | + public function getUpHost($accessKey, $bucket) | ||
40 | + { | ||
41 | + $region = $this->getRegion($accessKey, $bucket); | ||
42 | + if ($this->useHTTPS === true) { | ||
43 | + $scheme = "https://"; | ||
44 | + } else { | ||
45 | + $scheme = "http://"; | ||
46 | + } | ||
47 | + | ||
48 | + $host = $region->srcUpHosts[0]; | ||
49 | + if ($this->useCdnDomains === true) { | ||
50 | + $host = $region->cdnUpHosts[0]; | ||
51 | + } | ||
52 | + | ||
53 | + return $scheme . $host; | ||
54 | + } | ||
55 | + | ||
56 | + public function getUpBackupHost($accessKey, $bucket) | ||
57 | + { | ||
58 | + $region = $this->getRegion($accessKey, $bucket); | ||
59 | + if ($this->useHTTPS === true) { | ||
60 | + $scheme = "https://"; | ||
61 | + } else { | ||
62 | + $scheme = "http://"; | ||
63 | + } | ||
64 | + | ||
65 | + $host = $region->cdnUpHosts[0]; | ||
66 | + if ($this->useCdnDomains === true) { | ||
67 | + $host = $region->srcUpHosts[0]; | ||
68 | + } | ||
69 | + | ||
70 | + return $scheme . $host; | ||
71 | + } | ||
72 | + | ||
73 | + public function getRsHost($accessKey, $bucket) | ||
74 | + { | ||
75 | + $region = $this->getRegion($accessKey, $bucket); | ||
76 | + | ||
77 | + if ($this->useHTTPS === true) { | ||
78 | + $scheme = "https://"; | ||
79 | + } else { | ||
80 | + $scheme = "http://"; | ||
81 | + } | ||
82 | + | ||
83 | + return $scheme . $region->rsHost; | ||
84 | + } | ||
85 | + | ||
86 | + public function getRsfHost($accessKey, $bucket) | ||
87 | + { | ||
88 | + $region = $this->getRegion($accessKey, $bucket); | ||
89 | + | ||
90 | + if ($this->useHTTPS === true) { | ||
91 | + $scheme = "https://"; | ||
92 | + } else { | ||
93 | + $scheme = "http://"; | ||
94 | + } | ||
95 | + | ||
96 | + return $scheme . $region->rsfHost; | ||
97 | + } | ||
98 | + | ||
99 | + public function getIovipHost($accessKey, $bucket) | ||
100 | + { | ||
101 | + $region = $this->getRegion($accessKey, $bucket); | ||
102 | + | ||
103 | + if ($this->useHTTPS === true) { | ||
104 | + $scheme = "https://"; | ||
105 | + } else { | ||
106 | + $scheme = "http://"; | ||
107 | + } | ||
108 | + | ||
109 | + return $scheme . $region->iovipHost; | ||
110 | + } | ||
111 | + | ||
112 | + public function getApiHost($accessKey, $bucket) | ||
113 | + { | ||
114 | + $region = $this->getRegion($accessKey, $bucket); | ||
115 | + | ||
116 | + if ($this->useHTTPS === true) { | ||
117 | + $scheme = "https://"; | ||
118 | + } else { | ||
119 | + $scheme = "http://"; | ||
120 | + } | ||
121 | + | ||
122 | + return $scheme . $region->apiHost; | ||
123 | + } | ||
124 | + | ||
125 | + private function getRegion($accessKey, $bucket) | ||
126 | + { | ||
127 | + $cacheId = "$accessKey:$bucket"; | ||
128 | + | ||
129 | + if (isset($this->regionCache[$cacheId])) { | ||
130 | + $region = $this->regionCache[$cacheId]; | ||
131 | + } elseif (isset($this->zone)) { | ||
132 | + $region = $this->zone; | ||
133 | + $this->regionCache[$cacheId] = $region; | ||
134 | + } else { | ||
135 | + $region = Zone::queryZone($accessKey, $bucket); | ||
136 | + $this->regionCache[$cacheId] = $region; | ||
137 | + } | ||
138 | + return $region; | ||
139 | + } | ||
140 | +} |
addons/qiniu/library/Qiniu/Etag.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu; | ||
4 | + | ||
5 | +use Qiniu\Config; | ||
6 | + | ||
7 | +final class Etag | ||
8 | +{ | ||
9 | + private static function packArray($v, $a) | ||
10 | + { | ||
11 | + return call_user_func_array('pack', array_merge(array($v), (array)$a)); | ||
12 | + } | ||
13 | + | ||
14 | + private static function blockCount($fsize) | ||
15 | + { | ||
16 | + return intval(($fsize + (Config::BLOCK_SIZE - 1)) / Config::BLOCK_SIZE); | ||
17 | + } | ||
18 | + | ||
19 | + private static function calcSha1($data) | ||
20 | + { | ||
21 | + $sha1Str = sha1($data, true); | ||
22 | + $err = error_get_last(); | ||
23 | + if ($err !== null) { | ||
24 | + return array(null, $err); | ||
25 | + } | ||
26 | + $byteArray = unpack('C*', $sha1Str); | ||
27 | + return array($byteArray, null); | ||
28 | + } | ||
29 | + | ||
30 | + | ||
31 | + public static function sum($filename) | ||
32 | + { | ||
33 | + $fhandler = fopen($filename, 'r'); | ||
34 | + $err = error_get_last(); | ||
35 | + if ($err !== null) { | ||
36 | + return array(null, $err); | ||
37 | + } | ||
38 | + | ||
39 | + $fstat = fstat($fhandler); | ||
40 | + $fsize = $fstat['size']; | ||
41 | + if ((int)$fsize === 0) { | ||
42 | + fclose($fhandler); | ||
43 | + return array('Fto5o-5ea0sNMlW_75VgGJCv2AcJ', null); | ||
44 | + } | ||
45 | + $blockCnt = self::blockCount($fsize); | ||
46 | + $sha1Buf = array(); | ||
47 | + | ||
48 | + if ($blockCnt <= 1) { | ||
49 | + array_push($sha1Buf, 0x16); | ||
50 | + $fdata = fread($fhandler, Config::BLOCK_SIZE); | ||
51 | + if ($err !== null) { | ||
52 | + fclose($fhandler); | ||
53 | + return array(null, $err); | ||
54 | + } | ||
55 | + list($sha1Code,) = self::calcSha1($fdata); | ||
56 | + $sha1Buf = array_merge($sha1Buf, $sha1Code); | ||
57 | + } else { | ||
58 | + array_push($sha1Buf, 0x96); | ||
59 | + $sha1BlockBuf = array(); | ||
60 | + for ($i = 0; $i < $blockCnt; $i++) { | ||
61 | + $fdata = fread($fhandler, Config::BLOCK_SIZE); | ||
62 | + list($sha1Code, $err) = self::calcSha1($fdata); | ||
63 | + if ($err !== null) { | ||
64 | + fclose($fhandler); | ||
65 | + return array(null, $err); | ||
66 | + } | ||
67 | + $sha1BlockBuf = array_merge($sha1BlockBuf, $sha1Code); | ||
68 | + } | ||
69 | + $tmpData = self::packArray('C*', $sha1BlockBuf); | ||
70 | + list($sha1Final,) = self::calcSha1($tmpData); | ||
71 | + $sha1Buf = array_merge($sha1Buf, $sha1Final); | ||
72 | + } | ||
73 | + $etag = \Qiniu\base64_urlSafeEncode(self::packArray('C*', $sha1Buf)); | ||
74 | + return array($etag, null); | ||
75 | + } | ||
76 | +} |
addons/qiniu/library/Qiniu/Http/Client.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu\Http; | ||
3 | + | ||
4 | +use Qiniu\Config; | ||
5 | +use Qiniu\Http\Request; | ||
6 | +use Qiniu\Http\Response; | ||
7 | + | ||
8 | +final class Client | ||
9 | +{ | ||
10 | + public static function get($url, array $headers = array()) | ||
11 | + { | ||
12 | + $request = new Request('GET', $url, $headers); | ||
13 | + return self::sendRequest($request); | ||
14 | + } | ||
15 | + | ||
16 | + public static function delete($url, array $headers = array()) | ||
17 | + { | ||
18 | + $request = new Request('DELETE', $url, $headers); | ||
19 | + return self::sendRequest($request); | ||
20 | + } | ||
21 | + | ||
22 | + public static function post($url, $body, array $headers = array()) | ||
23 | + { | ||
24 | + $request = new Request('POST', $url, $headers, $body); | ||
25 | + return self::sendRequest($request); | ||
26 | + } | ||
27 | + | ||
28 | + public static function PUT($url, $body, array $headers = array()) | ||
29 | + { | ||
30 | + $request = new Request('PUT', $url, $headers, $body); | ||
31 | + return self::sendRequest($request); | ||
32 | + } | ||
33 | + | ||
34 | + public static function multipartPost( | ||
35 | + $url, | ||
36 | + $fields, | ||
37 | + $name, | ||
38 | + $fileName, | ||
39 | + $fileBody, | ||
40 | + $mimeType = null, | ||
41 | + array $headers = array() | ||
42 | + ) { | ||
43 | + $data = array(); | ||
44 | + $mimeBoundary = md5(microtime()); | ||
45 | + | ||
46 | + foreach ($fields as $key => $val) { | ||
47 | + array_push($data, '--' . $mimeBoundary); | ||
48 | + array_push($data, "Content-Disposition: form-data; name=\"$key\""); | ||
49 | + array_push($data, ''); | ||
50 | + array_push($data, $val); | ||
51 | + } | ||
52 | + | ||
53 | + array_push($data, '--' . $mimeBoundary); | ||
54 | + $finalMimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType; | ||
55 | + $finalFileName = self::escapeQuotes($fileName); | ||
56 | + array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$finalFileName\""); | ||
57 | + array_push($data, "Content-Type: $finalMimeType"); | ||
58 | + array_push($data, ''); | ||
59 | + array_push($data, $fileBody); | ||
60 | + | ||
61 | + array_push($data, '--' . $mimeBoundary . '--'); | ||
62 | + array_push($data, ''); | ||
63 | + | ||
64 | + $body = implode("\r\n", $data); | ||
65 | + // var_dump($data);exit; | ||
66 | + $contentType = 'multipart/form-data; boundary=' . $mimeBoundary; | ||
67 | + $headers['Content-Type'] = $contentType; | ||
68 | + $request = new Request('POST', $url, $headers, $body); | ||
69 | + return self::sendRequest($request); | ||
70 | + } | ||
71 | + | ||
72 | + private static function userAgent() | ||
73 | + { | ||
74 | + $sdkInfo = "QiniuPHP/" . Config::SDK_VER; | ||
75 | + | ||
76 | + $systemInfo = php_uname("s"); | ||
77 | + $machineInfo = php_uname("m"); | ||
78 | + | ||
79 | + $envInfo = "($systemInfo/$machineInfo)"; | ||
80 | + | ||
81 | + $phpVer = phpversion(); | ||
82 | + | ||
83 | + $ua = "$sdkInfo $envInfo PHP/$phpVer"; | ||
84 | + return $ua; | ||
85 | + } | ||
86 | + | ||
87 | + public static function sendRequest($request) | ||
88 | + { | ||
89 | + $t1 = microtime(true); | ||
90 | + $ch = curl_init(); | ||
91 | + $options = array( | ||
92 | + CURLOPT_USERAGENT => self::userAgent(), | ||
93 | + CURLOPT_RETURNTRANSFER => true, | ||
94 | + CURLOPT_SSL_VERIFYPEER => false, | ||
95 | + CURLOPT_SSL_VERIFYHOST => false, | ||
96 | + CURLOPT_HEADER => true, | ||
97 | + CURLOPT_NOBODY => false, | ||
98 | + CURLOPT_CUSTOMREQUEST => $request->method, | ||
99 | + CURLOPT_URL => $request->url, | ||
100 | + ); | ||
101 | + // Handle open_basedir & safe mode | ||
102 | + if (!ini_get('safe_mode') && !ini_get('open_basedir')) { | ||
103 | + $options[CURLOPT_FOLLOWLOCATION] = true; | ||
104 | + } | ||
105 | + if (!empty($request->headers)) { | ||
106 | + $headers = array(); | ||
107 | + foreach ($request->headers as $key => $val) { | ||
108 | + array_push($headers, "$key: $val"); | ||
109 | + } | ||
110 | + $options[CURLOPT_HTTPHEADER] = $headers; | ||
111 | + } | ||
112 | + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); | ||
113 | + if (!empty($request->body)) { | ||
114 | + $options[CURLOPT_POSTFIELDS] = $request->body; | ||
115 | + } | ||
116 | + curl_setopt_array($ch, $options); | ||
117 | + $result = curl_exec($ch); | ||
118 | + $t2 = microtime(true); | ||
119 | + $duration = round($t2 - $t1, 3); | ||
120 | + $ret = curl_errno($ch); | ||
121 | + if ($ret !== 0) { | ||
122 | + $r = new Response(-1, $duration, array(), null, curl_error($ch)); | ||
123 | + curl_close($ch); | ||
124 | + return $r; | ||
125 | + } | ||
126 | + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); | ||
127 | + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); | ||
128 | + $headers = self::parseHeaders(substr($result, 0, $header_size)); | ||
129 | + $body = substr($result, $header_size); | ||
130 | + curl_close($ch); | ||
131 | + return new Response($code, $duration, $headers, $body, null); | ||
132 | + } | ||
133 | + | ||
134 | + private static function parseHeaders($raw) | ||
135 | + { | ||
136 | + $headers = array(); | ||
137 | + $headerLines = explode("\r\n", $raw); | ||
138 | + foreach ($headerLines as $line) { | ||
139 | + $headerLine = trim($line); | ||
140 | + $kv = explode(':', $headerLine); | ||
141 | + if (count($kv) > 1) { | ||
142 | + $kv[0] =self::ucwordsHyphen($kv[0]); | ||
143 | + $headers[$kv[0]] = trim($kv[1]); | ||
144 | + } | ||
145 | + } | ||
146 | + return $headers; | ||
147 | + } | ||
148 | + | ||
149 | + private static function escapeQuotes($str) | ||
150 | + { | ||
151 | + $find = array("\\", "\""); | ||
152 | + $replace = array("\\\\", "\\\""); | ||
153 | + return str_replace($find, $replace, $str); | ||
154 | + } | ||
155 | + | ||
156 | + private static function ucwordsHyphen($str) | ||
157 | + { | ||
158 | + return str_replace('- ', '-', ucwords(str_replace('-', '- ', $str))); | ||
159 | + } | ||
160 | +} |
addons/qiniu/library/Qiniu/Http/Error.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu\Http; | ||
3 | + | ||
4 | +/** | ||
5 | + * 七牛业务请求逻辑错误封装类,主要用来解析API请求返回如下的内容: | ||
6 | + * <pre> | ||
7 | + * {"error" : "detailed error message"} | ||
8 | + * </pre> | ||
9 | + */ | ||
10 | +final class Error | ||
11 | +{ | ||
12 | + private $url; | ||
13 | + private $response; | ||
14 | + | ||
15 | + public function __construct($url, $response) | ||
16 | + { | ||
17 | + $this->url = $url; | ||
18 | + $this->response = $response; | ||
19 | + } | ||
20 | + | ||
21 | + public function code() | ||
22 | + { | ||
23 | + return $this->response->statusCode; | ||
24 | + } | ||
25 | + | ||
26 | + public function getResponse() | ||
27 | + { | ||
28 | + return $this->response; | ||
29 | + } | ||
30 | + | ||
31 | + public function message() | ||
32 | + { | ||
33 | + return $this->response->error; | ||
34 | + } | ||
35 | +} |
addons/qiniu/library/Qiniu/Http/Request.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu\Http; | ||
3 | + | ||
4 | +final class Request | ||
5 | +{ | ||
6 | + public $url; | ||
7 | + public $headers; | ||
8 | + public $body; | ||
9 | + public $method; | ||
10 | + | ||
11 | + public function __construct($method, $url, array $headers = array(), $body = null) | ||
12 | + { | ||
13 | + $this->method = strtoupper($method); | ||
14 | + $this->url = $url; | ||
15 | + $this->headers = $headers; | ||
16 | + $this->body = $body; | ||
17 | + } | ||
18 | +} |
addons/qiniu/library/Qiniu/Http/Response.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu\Http; | ||
4 | + | ||
5 | +/** | ||
6 | + * HTTP response Object | ||
7 | + */ | ||
8 | +final class Response | ||
9 | +{ | ||
10 | + public $statusCode; | ||
11 | + public $headers; | ||
12 | + public $body; | ||
13 | + public $error; | ||
14 | + private $jsonData; | ||
15 | + public $duration; | ||
16 | + | ||
17 | + /** @var array Mapping of status codes to reason phrases */ | ||
18 | + private static $statusTexts = array( | ||
19 | + 100 => 'Continue', | ||
20 | + 101 => 'Switching Protocols', | ||
21 | + 102 => 'Processing', | ||
22 | + 200 => 'OK', | ||
23 | + 201 => 'Created', | ||
24 | + 202 => 'Accepted', | ||
25 | + 203 => 'Non-Authoritative Information', | ||
26 | + 204 => 'No Content', | ||
27 | + 205 => 'Reset Content', | ||
28 | + 206 => 'Partial Content', | ||
29 | + 207 => 'Multi-Status', | ||
30 | + 208 => 'Already Reported', | ||
31 | + 226 => 'IM Used', | ||
32 | + 300 => 'Multiple Choices', | ||
33 | + 301 => 'Moved Permanently', | ||
34 | + 302 => 'Found', | ||
35 | + 303 => 'See Other', | ||
36 | + 304 => 'Not Modified', | ||
37 | + 305 => 'Use Proxy', | ||
38 | + 307 => 'Temporary Redirect', | ||
39 | + 308 => 'Permanent Redirect', | ||
40 | + 400 => 'Bad Request', | ||
41 | + 401 => 'Unauthorized', | ||
42 | + 402 => 'Payment Required', | ||
43 | + 403 => 'Forbidden', | ||
44 | + 404 => 'Not Found', | ||
45 | + 405 => 'Method Not Allowed', | ||
46 | + 406 => 'Not Acceptable', | ||
47 | + 407 => 'Proxy Authentication Required', | ||
48 | + 408 => 'Request Timeout', | ||
49 | + 409 => 'Conflict', | ||
50 | + 410 => 'Gone', | ||
51 | + 411 => 'Length Required', | ||
52 | + 412 => 'Precondition Failed', | ||
53 | + 413 => 'Request Entity Too Large', | ||
54 | + 414 => 'Request-URI Too Long', | ||
55 | + 415 => 'Unsupported Media Type', | ||
56 | + 416 => 'Requested Range Not Satisfiable', | ||
57 | + 417 => 'Expectation Failed', | ||
58 | + 422 => 'Unprocessable Entity', | ||
59 | + 423 => 'Locked', | ||
60 | + 424 => 'Failed Dependency', | ||
61 | + 425 => 'Reserved for WebDAV advanced collections expired proposal', | ||
62 | + 426 => 'Upgrade required', | ||
63 | + 428 => 'Precondition Required', | ||
64 | + 429 => 'Too Many Requests', | ||
65 | + 431 => 'Request Header Fields Too Large', | ||
66 | + 500 => 'Internal Server Error', | ||
67 | + 501 => 'Not Implemented', | ||
68 | + 502 => 'Bad Gateway', | ||
69 | + 503 => 'Service Unavailable', | ||
70 | + 504 => 'Gateway Timeout', | ||
71 | + 505 => 'HTTP Version Not Supported', | ||
72 | + 506 => 'Variant Also Negotiates (Experimental)', | ||
73 | + 507 => 'Insufficient Storage', | ||
74 | + 508 => 'Loop Detected', | ||
75 | + 510 => 'Not Extended', | ||
76 | + 511 => 'Network Authentication Required', | ||
77 | + ); | ||
78 | + | ||
79 | + /** | ||
80 | + * @param int $code 状态码 | ||
81 | + * @param double $duration 请求时长 | ||
82 | + * @param array $headers 响应头部 | ||
83 | + * @param string $body 响应内容 | ||
84 | + * @param string $error 错误描述 | ||
85 | + */ | ||
86 | + public function __construct($code, $duration, array $headers = array(), $body = null, $error = null) | ||
87 | + { | ||
88 | + $this->statusCode = $code; | ||
89 | + $this->duration = $duration; | ||
90 | + $this->headers = $headers; | ||
91 | + $this->body = $body; | ||
92 | + $this->error = $error; | ||
93 | + $this->jsonData = null; | ||
94 | + if ($error !== null) { | ||
95 | + return; | ||
96 | + } | ||
97 | + | ||
98 | + if ($body === null) { | ||
99 | + if ($code >= 400) { | ||
100 | + $this->error = self::$statusTexts[$code]; | ||
101 | + } | ||
102 | + return; | ||
103 | + } | ||
104 | + if (self::isJson($headers)) { | ||
105 | + try { | ||
106 | + $jsonData = self::bodyJson($body); | ||
107 | + if ($code >= 400) { | ||
108 | + $this->error = $body; | ||
109 | + if ($jsonData['error'] !== null) { | ||
110 | + $this->error = $jsonData['error']; | ||
111 | + } | ||
112 | + } | ||
113 | + $this->jsonData = $jsonData; | ||
114 | + } catch (\InvalidArgumentException $e) { | ||
115 | + $this->error = $body; | ||
116 | + if ($code >= 200 && $code < 300) { | ||
117 | + $this->error = $e->getMessage(); | ||
118 | + } | ||
119 | + } | ||
120 | + } elseif ($code >= 400) { | ||
121 | + $this->error = $body; | ||
122 | + } | ||
123 | + return; | ||
124 | + } | ||
125 | + | ||
126 | + public function json() | ||
127 | + { | ||
128 | + return $this->jsonData; | ||
129 | + } | ||
130 | + | ||
131 | + private static function bodyJson($body) | ||
132 | + { | ||
133 | + return \Qiniu\json_decode((string) $body, true, 512); | ||
134 | + } | ||
135 | + | ||
136 | + public function xVia() | ||
137 | + { | ||
138 | + $via = $this->headers['X-Via']; | ||
139 | + if ($via === null) { | ||
140 | + $via = $this->headers['X-Px']; | ||
141 | + } | ||
142 | + if ($via === null) { | ||
143 | + $via = $this->headers['Fw-Via']; | ||
144 | + } | ||
145 | + return $via; | ||
146 | + } | ||
147 | + | ||
148 | + public function xLog() | ||
149 | + { | ||
150 | + return $this->headers['X-Log']; | ||
151 | + } | ||
152 | + | ||
153 | + public function xReqId() | ||
154 | + { | ||
155 | + return $this->headers['X-Reqid']; | ||
156 | + } | ||
157 | + | ||
158 | + public function ok() | ||
159 | + { | ||
160 | + return $this->statusCode >= 200 && $this->statusCode < 300 && $this->error === null; | ||
161 | + } | ||
162 | + | ||
163 | + public function needRetry() | ||
164 | + { | ||
165 | + $code = $this->statusCode; | ||
166 | + if ($code < 0 || ($code / 100 === 5 and $code !== 579) || $code === 996) { | ||
167 | + return true; | ||
168 | + } | ||
169 | + } | ||
170 | + | ||
171 | + private static function isJson($headers) | ||
172 | + { | ||
173 | + return array_key_exists('Content-Type', $headers) && | ||
174 | + strpos($headers['Content-Type'], 'application/json') === 0; | ||
175 | + } | ||
176 | +} |
1 | +<?php | ||
2 | +namespace Qiniu\Processing; | ||
3 | + | ||
4 | +use Qiniu; | ||
5 | + | ||
6 | +/** | ||
7 | + * 主要涉及图片链接拼接 | ||
8 | + * | ||
9 | + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/imageview2.html | ||
10 | + */ | ||
11 | +final class ImageUrlBuilder | ||
12 | +{ | ||
13 | + /** | ||
14 | + * mode合法范围值 | ||
15 | + * | ||
16 | + * @var array | ||
17 | + */ | ||
18 | + protected $modeArr = array(0, 1, 2, 3, 4, 5); | ||
19 | + | ||
20 | + /** | ||
21 | + * format合法值 | ||
22 | + * | ||
23 | + * @var array | ||
24 | + */ | ||
25 | + protected $formatArr = array('psd', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'bmp'); | ||
26 | + | ||
27 | + /** | ||
28 | + * 水印图片位置合法值 | ||
29 | + * | ||
30 | + * @var array | ||
31 | + */ | ||
32 | + protected $gravityArr = array('NorthWest', 'North', 'NorthEast', | ||
33 | + 'West', 'Center', 'East', 'SouthWest', 'South', 'SouthEast'); | ||
34 | + | ||
35 | + /** | ||
36 | + * 缩略图链接拼接 | ||
37 | + * | ||
38 | + * @param string $url 图片链接 | ||
39 | + * @param int $mode 缩略模式 | ||
40 | + * @param int $width 宽度 | ||
41 | + * @param int $height 长度 | ||
42 | + * @param string $format 输出类型 | ||
43 | + * @param int $quality 图片质量 | ||
44 | + * @param int $interlace 是否支持渐进显示 | ||
45 | + * @param int $ignoreError 忽略结果 | ||
46 | + * @return string | ||
47 | + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/imageview2.html | ||
48 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
49 | + */ | ||
50 | + public function thumbnail( | ||
51 | + $url, | ||
52 | + $mode, | ||
53 | + $width, | ||
54 | + $height, | ||
55 | + $format = null, | ||
56 | + $interlace = null, | ||
57 | + $quality = null, | ||
58 | + $ignoreError = 1 | ||
59 | + ) { | ||
60 | + | ||
61 | + // url合法效验 | ||
62 | + if (!$this->isUrl($url)) { | ||
63 | + return $url; | ||
64 | + } | ||
65 | + | ||
66 | + // 参数合法性效验 | ||
67 | + if (!in_array(intval($mode), $this->modeArr, true)) { | ||
68 | + return $url; | ||
69 | + } | ||
70 | + | ||
71 | + if (!$width || !$height) { | ||
72 | + return $url; | ||
73 | + } | ||
74 | + | ||
75 | + $thumbStr = 'imageView2/' . $mode . '/w/' . $width . '/h/' . $height . '/'; | ||
76 | + | ||
77 | + // 拼接输出格式 | ||
78 | + if (!is_null($format) | ||
79 | + && in_array($format, $this->formatArr) | ||
80 | + ) { | ||
81 | + $thumbStr .= 'format/' . $format . '/'; | ||
82 | + } | ||
83 | + | ||
84 | + // 拼接渐进显示 | ||
85 | + if (!is_null($interlace) | ||
86 | + && in_array(intval($interlace), array(0, 1), true) | ||
87 | + ) { | ||
88 | + $thumbStr .= 'interlace/' . $interlace . '/'; | ||
89 | + } | ||
90 | + | ||
91 | + // 拼接图片质量 | ||
92 | + if (!is_null($quality) | ||
93 | + && intval($quality) >= 0 | ||
94 | + && intval($quality) <= 100 | ||
95 | + ) { | ||
96 | + $thumbStr .= 'q/' . $quality . '/'; | ||
97 | + } | ||
98 | + | ||
99 | + $thumbStr .= 'ignore-error/' . $ignoreError . '/'; | ||
100 | + | ||
101 | + // 如果有query_string用|线分割实现多参数 | ||
102 | + return $url . ($this->hasQuery($url) ? '|' : '?') . $thumbStr; | ||
103 | + } | ||
104 | + | ||
105 | + /** | ||
106 | + * 图片水印 | ||
107 | + * | ||
108 | + * @param string $url 图片链接 | ||
109 | + * @param string $image 水印图片链接 | ||
110 | + * @param numeric $dissolve 透明度 | ||
111 | + * @param string $gravity 水印位置 | ||
112 | + * @param numeric $dx 横轴边距 | ||
113 | + * @param numeric $dy 纵轴边距 | ||
114 | + * @param numeric $watermarkScale 自适应原图的短边比例 | ||
115 | + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html | ||
116 | + * @return string | ||
117 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
118 | + */ | ||
119 | + public function waterImg( | ||
120 | + $url, | ||
121 | + $image, | ||
122 | + $dissolve = 100, | ||
123 | + $gravity = 'SouthEast', | ||
124 | + $dx = null, | ||
125 | + $dy = null, | ||
126 | + $watermarkScale = null | ||
127 | + ) { | ||
128 | + // url合法效验 | ||
129 | + if (!$this->isUrl($url)) { | ||
130 | + return $url; | ||
131 | + } | ||
132 | + | ||
133 | + $waterStr = 'watermark/1/image/' . \Qiniu\base64_urlSafeEncode($image) . '/'; | ||
134 | + | ||
135 | + // 拼接水印透明度 | ||
136 | + if (is_numeric($dissolve) | ||
137 | + && $dissolve <= 100 | ||
138 | + ) { | ||
139 | + $waterStr .= 'dissolve/' . $dissolve . '/'; | ||
140 | + } | ||
141 | + | ||
142 | + // 拼接水印位置 | ||
143 | + if (in_array($gravity, $this->gravityArr, true)) { | ||
144 | + $waterStr .= 'gravity/' . $gravity . '/'; | ||
145 | + } | ||
146 | + | ||
147 | + // 拼接横轴边距 | ||
148 | + if (!is_null($dx) | ||
149 | + && is_numeric($dx) | ||
150 | + ) { | ||
151 | + $waterStr .= 'dx/' . $dx . '/'; | ||
152 | + } | ||
153 | + | ||
154 | + // 拼接纵轴边距 | ||
155 | + if (!is_null($dy) | ||
156 | + && is_numeric($dy) | ||
157 | + ) { | ||
158 | + $waterStr .= 'dy/' . $dy . '/'; | ||
159 | + } | ||
160 | + | ||
161 | + // 拼接自适应原图的短边比例 | ||
162 | + if (!is_null($watermarkScale) | ||
163 | + && is_numeric($watermarkScale) | ||
164 | + && $watermarkScale > 0 | ||
165 | + && $watermarkScale < 1 | ||
166 | + ) { | ||
167 | + $waterStr .= 'ws/' . $watermarkScale . '/'; | ||
168 | + } | ||
169 | + | ||
170 | + // 如果有query_string用|线分割实现多参数 | ||
171 | + return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; | ||
172 | + } | ||
173 | + | ||
174 | + /** | ||
175 | + * 文字水印 | ||
176 | + * | ||
177 | + * @param string $url 图片链接 | ||
178 | + * @param string $text 文字 | ||
179 | + * @param string $font 文字字体 | ||
180 | + * @param string $fontSize 文字字号 | ||
181 | + * @param string $fontColor 文字颜色 | ||
182 | + * @param numeric $dissolve 透明度 | ||
183 | + * @param string $gravity 水印位置 | ||
184 | + * @param numeric $dx 横轴边距 | ||
185 | + * @param numeric $dy 纵轴边距 | ||
186 | + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark | ||
187 | + * @return string | ||
188 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
189 | + */ | ||
190 | + public function waterText( | ||
191 | + $url, | ||
192 | + $text, | ||
193 | + $font = '黑体', | ||
194 | + $fontSize = 0, | ||
195 | + $fontColor = null, | ||
196 | + $dissolve = 100, | ||
197 | + $gravity = 'SouthEast', | ||
198 | + $dx = null, | ||
199 | + $dy = null | ||
200 | + ) { | ||
201 | + // url合法效验 | ||
202 | + if (!$this->isUrl($url)) { | ||
203 | + return $url; | ||
204 | + } | ||
205 | + | ||
206 | + $waterStr = 'watermark/2/text/' | ||
207 | + . \Qiniu\base64_urlSafeEncode($text) . '/font/' | ||
208 | + . \Qiniu\base64_urlSafeEncode($font) . '/'; | ||
209 | + | ||
210 | + // 拼接文字大小 | ||
211 | + if (is_int($fontSize)) { | ||
212 | + $waterStr .= 'fontsize/' . $fontSize . '/'; | ||
213 | + } | ||
214 | + | ||
215 | + // 拼接文字颜色 | ||
216 | + if (!is_null($fontColor) | ||
217 | + && $fontColor | ||
218 | + ) { | ||
219 | + $waterStr .= 'fill/' . \Qiniu\base64_urlSafeEncode($fontColor) . '/'; | ||
220 | + } | ||
221 | + | ||
222 | + // 拼接水印透明度 | ||
223 | + if (is_numeric($dissolve) | ||
224 | + && $dissolve <= 100 | ||
225 | + ) { | ||
226 | + $waterStr .= 'dissolve/' . $dissolve . '/'; | ||
227 | + } | ||
228 | + | ||
229 | + // 拼接水印位置 | ||
230 | + if (in_array($gravity, $this->gravityArr, true)) { | ||
231 | + $waterStr .= 'gravity/' . $gravity . '/'; | ||
232 | + } | ||
233 | + | ||
234 | + // 拼接横轴边距 | ||
235 | + if (!is_null($dx) | ||
236 | + && is_numeric($dx) | ||
237 | + ) { | ||
238 | + $waterStr .= 'dx/' . $dx . '/'; | ||
239 | + } | ||
240 | + | ||
241 | + // 拼接纵轴边距 | ||
242 | + if (!is_null($dy) | ||
243 | + && is_numeric($dy) | ||
244 | + ) { | ||
245 | + $waterStr .= 'dy/' . $dy . '/'; | ||
246 | + } | ||
247 | + | ||
248 | + // 如果有query_string用|线分割实现多参数 | ||
249 | + return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; | ||
250 | + } | ||
251 | + | ||
252 | + /** | ||
253 | + * 效验url合法性 | ||
254 | + * | ||
255 | + * @param string $url url链接 | ||
256 | + * @return string | ||
257 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
258 | + */ | ||
259 | + protected function isUrl($url) | ||
260 | + { | ||
261 | + $urlArr = parse_url($url); | ||
262 | + | ||
263 | + return $urlArr['scheme'] | ||
264 | + && in_array($urlArr['scheme'], array('http', 'https')) | ||
265 | + && $urlArr['host'] | ||
266 | + && $urlArr['path']; | ||
267 | + } | ||
268 | + | ||
269 | + /** | ||
270 | + * 检测是否有query | ||
271 | + * | ||
272 | + * @param string $url url链接 | ||
273 | + * @return string | ||
274 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
275 | + */ | ||
276 | + protected function hasQuery($url) | ||
277 | + { | ||
278 | + $urlArr = parse_url($url); | ||
279 | + | ||
280 | + return !empty($urlArr['query']); | ||
281 | + } | ||
282 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu\Processing; | ||
4 | + | ||
5 | +use Qiniu\Http\Client; | ||
6 | +use Qiniu\Http\Error; | ||
7 | + | ||
8 | +final class Operation | ||
9 | +{ | ||
10 | + | ||
11 | + private $auth; | ||
12 | + private $token_expire; | ||
13 | + private $domain; | ||
14 | + | ||
15 | + public function __construct($domain, $auth = null, $token_expire = 3600) | ||
16 | + { | ||
17 | + $this->auth = $auth; | ||
18 | + $this->domain = $domain; | ||
19 | + $this->token_expire = $token_expire; | ||
20 | + } | ||
21 | + | ||
22 | + | ||
23 | + /** | ||
24 | + * 对资源文件进行处理 | ||
25 | + * | ||
26 | + * @param $key 待处理的资源文件名 | ||
27 | + * @param $fops string|array fop操作,多次fop操作以array的形式传入。 | ||
28 | + * eg. imageView2/1/w/200/h/200, imageMogr2/thumbnail/!75px | ||
29 | + * | ||
30 | + * @return array 文件处理后的结果及错误。 | ||
31 | + * | ||
32 | + * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ | ||
33 | + */ | ||
34 | + public function execute($key, $fops) | ||
35 | + { | ||
36 | + $url = $this->buildUrl($key, $fops); | ||
37 | + $resp = Client::get($url); | ||
38 | + if (!$resp->ok()) { | ||
39 | + return array(null, new Error($url, $resp)); | ||
40 | + } | ||
41 | + if ($resp->json() !== null) { | ||
42 | + return array($resp->json(), null); | ||
43 | + } | ||
44 | + return array($resp->body, null); | ||
45 | + } | ||
46 | + | ||
47 | + public function buildUrl($key, $fops, $protocol = 'http') | ||
48 | + { | ||
49 | + if (is_array($fops)) { | ||
50 | + $fops = implode('|', $fops); | ||
51 | + } | ||
52 | + | ||
53 | + $url = $protocol . "://$this->domain/$key?$fops"; | ||
54 | + if ($this->auth !== null) { | ||
55 | + $url = $this->auth->privateDownloadUrl($url, $this->token_expire); | ||
56 | + } | ||
57 | + | ||
58 | + return $url; | ||
59 | + } | ||
60 | +} |
1 | +<?php | ||
2 | +namespace Qiniu\Processing; | ||
3 | + | ||
4 | +use Qiniu\Config; | ||
5 | +use Qiniu\Http\Client; | ||
6 | +use Qiniu\Http\Error; | ||
7 | +use Qiniu\Processing\Operation; | ||
8 | + | ||
9 | +/** | ||
10 | + * 持久化处理类,该类用于主动触发异步持久化操作. | ||
11 | + * | ||
12 | + * @link http://developer.qiniu.com/docs/v6/api/reference/fop/pfop/pfop.html | ||
13 | + */ | ||
14 | +final class PersistentFop | ||
15 | +{ | ||
16 | + /** | ||
17 | + * @var 账号管理密钥对,Auth对象 | ||
18 | + */ | ||
19 | + private $auth; | ||
20 | + | ||
21 | + /* | ||
22 | + * @var 配置对象,Config 对象 | ||
23 | + * */ | ||
24 | + private $config; | ||
25 | + | ||
26 | + | ||
27 | + public function __construct($auth, $config = null) | ||
28 | + { | ||
29 | + $this->auth = $auth; | ||
30 | + if ($config == null) { | ||
31 | + $this->config = new Config(); | ||
32 | + } else { | ||
33 | + $this->config = $config; | ||
34 | + } | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * 对资源文件进行异步持久化处理 | ||
39 | + * @param $bucket 资源所在空间 | ||
40 | + * @param $key 待处理的源文件 | ||
41 | + * @param $fops string|array 待处理的pfop操作,多个pfop操作以array的形式传入。 | ||
42 | + * eg. avthumb/mp3/ab/192k, vframe/jpg/offset/7/w/480/h/360 | ||
43 | + * @param $pipeline 资源处理队列 | ||
44 | + * @param $notify_url 处理结果通知地址 | ||
45 | + * @param $force 是否强制执行一次新的指令 | ||
46 | + * | ||
47 | + * | ||
48 | + * @return array 返回持久化处理的persistentId, 和返回的错误。 | ||
49 | + * | ||
50 | + * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ | ||
51 | + */ | ||
52 | + public function execute($bucket, $key, $fops, $pipeline = null, $notify_url = null, $force = false) | ||
53 | + { | ||
54 | + if (is_array($fops)) { | ||
55 | + $fops = implode(';', $fops); | ||
56 | + } | ||
57 | + $params = array('bucket' => $bucket, 'key' => $key, 'fops' => $fops); | ||
58 | + \Qiniu\setWithoutEmpty($params, 'pipeline', $pipeline); | ||
59 | + \Qiniu\setWithoutEmpty($params, 'notifyURL', $notify_url); | ||
60 | + if ($force) { | ||
61 | + $params['force'] = 1; | ||
62 | + } | ||
63 | + $data = http_build_query($params); | ||
64 | + $scheme = "http://"; | ||
65 | + if ($this->config->useHTTPS === true) { | ||
66 | + $scheme = "https://"; | ||
67 | + } | ||
68 | + $url = $scheme . Config::API_HOST . '/pfop/'; | ||
69 | + $headers = $this->auth->authorization($url, $data, 'application/x-www-form-urlencoded'); | ||
70 | + $headers['Content-Type'] = 'application/x-www-form-urlencoded'; | ||
71 | + $response = Client::post($url, $data, $headers); | ||
72 | + if (!$response->ok()) { | ||
73 | + return array(null, new Error($url, $response)); | ||
74 | + } | ||
75 | + $r = $response->json(); | ||
76 | + $id = $r['persistentId']; | ||
77 | + return array($id, null); | ||
78 | + } | ||
79 | + | ||
80 | + public function status($id) | ||
81 | + { | ||
82 | + $scheme = "http://"; | ||
83 | + | ||
84 | + if ($this->config->useHTTPS === true) { | ||
85 | + $scheme = "https://"; | ||
86 | + } | ||
87 | + $url = $scheme . Config::API_HOST . "/status/get/prefop?id=$id"; | ||
88 | + $response = Client::get($url); | ||
89 | + if (!$response->ok()) { | ||
90 | + return array(null, new Error($url, $response)); | ||
91 | + } | ||
92 | + return array($response->json(), null); | ||
93 | + } | ||
94 | +} |
addons/qiniu/library/Qiniu/Region.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu; | ||
3 | + | ||
4 | +use Qiniu\Http\Client; | ||
5 | +use Qiniu\Http\Error; | ||
6 | + | ||
7 | +class Region | ||
8 | +{ | ||
9 | + | ||
10 | + //源站上传域名 | ||
11 | + public $srcUpHosts; | ||
12 | + //CDN加速上传域名 | ||
13 | + public $cdnUpHosts; | ||
14 | + //资源管理域名 | ||
15 | + public $rsHost; | ||
16 | + //资源列举域名 | ||
17 | + public $rsfHost; | ||
18 | + //资源处理域名 | ||
19 | + public $apiHost; | ||
20 | + //IOVIP域名 | ||
21 | + public $iovipHost; | ||
22 | + | ||
23 | + //构造一个Region对象 | ||
24 | + public function __construct( | ||
25 | + $srcUpHosts = array(), | ||
26 | + $cdnUpHosts = array(), | ||
27 | + $rsHost = "rs.qiniu.com", | ||
28 | + $rsfHost = "rsf.qiniu.com", | ||
29 | + $apiHost = "api.qiniu.com", | ||
30 | + $iovipHost = null | ||
31 | + ) { | ||
32 | + | ||
33 | + $this->srcUpHosts = $srcUpHosts; | ||
34 | + $this->cdnUpHosts = $cdnUpHosts; | ||
35 | + $this->rsHost = $rsHost; | ||
36 | + $this->rsfHost = $rsfHost; | ||
37 | + $this->apiHost = $apiHost; | ||
38 | + $this->iovipHost = $iovipHost; | ||
39 | + } | ||
40 | + | ||
41 | + //华东机房 | ||
42 | + public static function regionHuadong() | ||
43 | + { | ||
44 | + $regionHuadong = new Region( | ||
45 | + array("up.qiniup.com", 'up-jjh.qiniup.com', 'up-xs.qiniup.com'), | ||
46 | + array('upload.qiniup.com', 'upload-jjh.qiniup.com', 'upload-xs.qiniup.com'), | ||
47 | + 'rs.qbox.me', | ||
48 | + 'rsf.qbox.me', | ||
49 | + 'api.qiniu.com', | ||
50 | + 'iovip.qbox.me' | ||
51 | + ); | ||
52 | + return $regionHuadong; | ||
53 | + } | ||
54 | + | ||
55 | + //华东机房内网上传 | ||
56 | + public static function qvmRegionHuadong() | ||
57 | + { | ||
58 | + $qvmRegionHuadong = new Region( | ||
59 | + array("free-qvm-z0-xs.qiniup.com"), | ||
60 | + 'rs.qbox.me', | ||
61 | + 'rsf.qbox.me', | ||
62 | + 'api.qiniu.com', | ||
63 | + 'iovip.qbox.me' | ||
64 | + ); | ||
65 | + return $qvmRegionHuadong; | ||
66 | + } | ||
67 | + | ||
68 | + //华北机房内网上传 | ||
69 | + public static function qvmRegionHuabei() | ||
70 | + { | ||
71 | + $qvmRegionHuabei = new Region( | ||
72 | + array("free-qvm-z1-zz.qiniup.com"), | ||
73 | + "rs-z1.qbox.me", | ||
74 | + "rsf-z1.qbox.me", | ||
75 | + "api-z1.qiniu.com", | ||
76 | + "iovip-z1.qbox.me" | ||
77 | + ); | ||
78 | + return $qvmRegionHuabei; | ||
79 | + } | ||
80 | + | ||
81 | + //华北机房 | ||
82 | + public static function regionHuabei() | ||
83 | + { | ||
84 | + $regionHuabei = new Region( | ||
85 | + array('up-z1.qiniup.com'), | ||
86 | + array('upload-z1.qiniup.com'), | ||
87 | + "rs-z1.qbox.me", | ||
88 | + "rsf-z1.qbox.me", | ||
89 | + "api-z1.qiniu.com", | ||
90 | + "iovip-z1.qbox.me" | ||
91 | + ); | ||
92 | + | ||
93 | + return $regionHuabei; | ||
94 | + } | ||
95 | + | ||
96 | + //华南机房 | ||
97 | + public static function regionHuanan() | ||
98 | + { | ||
99 | + $regionHuanan = new Region( | ||
100 | + array('up-z2.qiniup.com', 'up-dg.qiniup.com', 'up-fs.qiniup.com'), | ||
101 | + array('upload-z2.qiniup.com', 'upload-dg.qiniup.com', 'upload-fs.qiniup.com'), | ||
102 | + "rs-z2.qbox.me", | ||
103 | + "rsf-z2.qbox.me", | ||
104 | + "api-z2.qiniu.com", | ||
105 | + "iovip-z2.qbox.me" | ||
106 | + ); | ||
107 | + return $regionHuanan; | ||
108 | + } | ||
109 | + | ||
110 | + //北美机房 | ||
111 | + public static function regionNorthAmerica() | ||
112 | + { | ||
113 | + //北美机房 | ||
114 | + $regionNorthAmerica = new Region( | ||
115 | + array('up-na0.qiniup.com'), | ||
116 | + array('upload-na0.qiniup.com'), | ||
117 | + "rs-na0.qbox.me", | ||
118 | + "rsf-na0.qbox.me", | ||
119 | + "api-na0.qiniu.com", | ||
120 | + "iovip-na0.qbox.me" | ||
121 | + ); | ||
122 | + return $regionNorthAmerica; | ||
123 | + } | ||
124 | + | ||
125 | + //新加坡机房 | ||
126 | + public static function regionSingapore() | ||
127 | + { | ||
128 | + //新加坡机房 | ||
129 | + $regionSingapore = new Region( | ||
130 | + array('up-as0.qiniup.com'), | ||
131 | + array('upload-as0.qiniup.com'), | ||
132 | + "rs-as0.qbox.me", | ||
133 | + "rsf-as0.qbox.me", | ||
134 | + "api-as0.qiniu.com", | ||
135 | + "iovip-as0.qbox.me" | ||
136 | + ); | ||
137 | + return $regionSingapore; | ||
138 | + } | ||
139 | + | ||
140 | + /* | ||
141 | + * GET /v2/query?ak=<ak>&&bucket=<bucket> | ||
142 | + **/ | ||
143 | + public static function queryRegion($ak, $bucket) | ||
144 | + { | ||
145 | + $Region = new Region(); | ||
146 | + $url = Config::API_HOST . '/v2/query' . "?ak=$ak&bucket=$bucket"; | ||
147 | + $ret = Client::Get($url); | ||
148 | + if (!$ret->ok()) { | ||
149 | + return array(null, new Error($url, $ret)); | ||
150 | + } | ||
151 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
152 | + //parse Region; | ||
153 | + | ||
154 | + $iovipHost = $r['io']['src']['main'][0]; | ||
155 | + $Region->iovipHost = $iovipHost; | ||
156 | + $accMain = $r['up']['acc']['main'][0]; | ||
157 | + array_push($Region->cdnUpHosts, $accMain); | ||
158 | + if (isset($r['up']['acc']['backup'])) { | ||
159 | + foreach ($r['up']['acc']['backup'] as $key => $value) { | ||
160 | + array_push($Region->cdnUpHosts, $value); | ||
161 | + } | ||
162 | + } | ||
163 | + $srcMain = $r['up']['src']['main'][0]; | ||
164 | + array_push($Region->srcUpHosts, $srcMain); | ||
165 | + if (isset($r['up']['src']['backup'])) { | ||
166 | + foreach ($r['up']['src']['backup'] as $key => $value) { | ||
167 | + array_push($Region->srcUpHosts, $value); | ||
168 | + } | ||
169 | + } | ||
170 | + | ||
171 | + //set specific hosts | ||
172 | + if (strstr($Region->iovipHost, "z1") !== false) { | ||
173 | + $Region->rsHost = "rs-z1.qbox.me"; | ||
174 | + $Region->rsfHost = "rsf-z1.qbox.me"; | ||
175 | + $Region->apiHost = "api-z1.qiniu.com"; | ||
176 | + } elseif (strstr($Region->iovipHost, "z2") !== false) { | ||
177 | + $Region->rsHost = "rs-z2.qbox.me"; | ||
178 | + $Region->rsfHost = "rsf-z2.qbox.me"; | ||
179 | + $Region->apiHost = "api-z2.qiniu.com"; | ||
180 | + } elseif (strstr($Region->iovipHost, "na0") !== false) { | ||
181 | + $Region->rsHost = "rs-na0.qbox.me"; | ||
182 | + $Region->rsfHost = "rsf-na0.qbox.me"; | ||
183 | + $Region->apiHost = "api-na0.qiniu.com"; | ||
184 | + } elseif (strstr($Region->iovipHost, "as0") !== false) { | ||
185 | + $Region->rsHost = "rs-as0.qbox.me"; | ||
186 | + $Region->rsfHost = "rsf-as0.qbox.me"; | ||
187 | + $Region->apiHost = "api-as0.qiniu.com"; | ||
188 | + } else { | ||
189 | + $Region->rsHost = "rs.qbox.me"; | ||
190 | + $Region->rsfHost = "rsf.qbox.me"; | ||
191 | + $Region->apiHost = "api.qiniu.com"; | ||
192 | + } | ||
193 | + | ||
194 | + return $Region; | ||
195 | + } | ||
196 | +} |
addons/qiniu/library/Qiniu/Rtc/AppClient.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu\Rtc; | ||
3 | + | ||
4 | +use Qiniu\Http\Client; | ||
5 | +use Qiniu\Http\Error; | ||
6 | +use Qiniu\Config; | ||
7 | +use Qiniu\Auth; | ||
8 | + | ||
9 | +class AppClient | ||
10 | +{ | ||
11 | + private $auth; | ||
12 | + private $baseURL; | ||
13 | + | ||
14 | + public function __construct(Auth $auth) | ||
15 | + { | ||
16 | + $this->auth = $auth; | ||
17 | + | ||
18 | + $this->baseURL = sprintf("%s/%s/apps", Config::RTCAPI_HOST, Config::RTCAPI_VERSION); | ||
19 | + } | ||
20 | + | ||
21 | + /* | ||
22 | + * 创建应用 | ||
23 | + * hub: 直播空间名 | ||
24 | + * title: app 的名称 注意,Title 不是唯一标识,重复 create 动作将生成多个 app | ||
25 | + * maxUsers:人数限制 | ||
26 | + * NoAutoKickUser: bool 类型,可选,禁止自动踢人(抢流)。默认为 false , | ||
27 | + 即同一个身份的 client (app/room/user) ,新的连麦请求可以成功,旧连接被关闭。 | ||
28 | + */ | ||
29 | + public function createApp($hub, $title, $maxUsers = null, $noAutoKickUser = null) | ||
30 | + { | ||
31 | + $params['hub'] = $hub; | ||
32 | + $params['title'] = $title; | ||
33 | + if (!empty($maxUsers)) { | ||
34 | + $params['maxUsers'] = $maxUsers; | ||
35 | + } | ||
36 | + if ($noAutoKickUser !== null) { | ||
37 | + $params['noAutoKickUser'] = $noAutoKickUser; | ||
38 | + } | ||
39 | + $body = json_encode($params); | ||
40 | + $ret = $this->post($this->baseURL, $body); | ||
41 | + return $ret; | ||
42 | + } | ||
43 | + | ||
44 | + /* | ||
45 | + * 更新应用 | ||
46 | + * appId: app 的唯一标识,创建的时候由系统生成。 | ||
47 | + * Title: app 的名称, 可选。 | ||
48 | + * Hub: 绑定的直播 hub,可选,用于合流后 rtmp 推流。 | ||
49 | + * MaxUsers: int 类型,可选,连麦房间支持的最大在线人数。 | ||
50 | + * NoAutoKickUser: bool 类型,可选,禁止自动踢人。 | ||
51 | + * MergePublishRtmp: 连麦合流转推 RTMP 的配置,可选择。其详细配置包括如下 | ||
52 | + Enable: 布尔类型,用于开启和关闭所有房间的合流功能。 | ||
53 | + AudioOnly: 布尔类型,可选,指定是否只合成音频。 | ||
54 | + Height, Width: int64,可选,指定合流输出的高和宽,默认为 640 x 480。 | ||
55 | + OutputFps: int64,可选,指定合流输出的帧率,默认为 25 fps 。 | ||
56 | + OutputKbps: int64,可选,指定合流输出的码率,默认为 1000 。 | ||
57 | + URL: 合流后转推旁路直播的地址,可选,支持魔法变量配置按照连麦房间号生成不同的推流地址。如果是转推到七牛直播云,不建议使用该配置。 | ||
58 | + StreamTitle: 转推七牛直播云的流名,可选,支持魔法变量配置按照连麦房间号生成不同的流名。例如,配置 Hub 为 qn-zhibo ,配置 StreamTitle 为 $(roomName) ,则房间 meeting-001 的合流将会被转推到 rtmp://pili-publish.qn-zhibo.***.com/qn-zhibo/meeting-001地址。详细配置细则,请咨询七牛技术支持。 | ||
59 | + */ | ||
60 | + public function updateApp($appId, $hub, $title, $maxUsers = null, $mergePublishRtmp = null, $noAutoKickUser = null) | ||
61 | + { | ||
62 | + $url = $this->baseURL . '/' . $appId; | ||
63 | + $params['hub'] = $hub; | ||
64 | + $params['title'] = $title; | ||
65 | + if (!empty($maxUsers)) { | ||
66 | + $params['maxUsers'] = $maxUsers; | ||
67 | + } | ||
68 | + if ($noAutoKickUser !== null) { | ||
69 | + $params['noAutoKickUser'] = $noAutoKickUser; | ||
70 | + } | ||
71 | + if (!empty($mergePublishRtmp)) { | ||
72 | + $params['mergePublishRtmp'] = $mergePublishRtmp; | ||
73 | + } | ||
74 | + $body = json_encode($params); | ||
75 | + $ret = $this->post($url, $body); | ||
76 | + return $ret; | ||
77 | + } | ||
78 | + | ||
79 | + /* | ||
80 | + * 获取应用信息 | ||
81 | + * appId: app 的唯一标识,创建的时候由系统生成。 | ||
82 | + */ | ||
83 | + public function getApp($appId) | ||
84 | + { | ||
85 | + $url = $this->baseURL . '/' . $appId; | ||
86 | + $ret = $this->get($url); | ||
87 | + return $ret; | ||
88 | + } | ||
89 | + | ||
90 | + /* | ||
91 | + * 删除应用 | ||
92 | + * appId: app 的唯一标识,创建的时候由系统生成 | ||
93 | + */ | ||
94 | + public function deleteApp($appId) | ||
95 | + { | ||
96 | + $url = $this->baseURL . '/' . $appId; | ||
97 | + list(, $err) = $this->delete($url); | ||
98 | + return $err; | ||
99 | + } | ||
100 | + | ||
101 | + /* | ||
102 | + * 获取房间内用户列表 | ||
103 | + * appId: app 的唯一标识,创建的时候由系统生成。 | ||
104 | + * roomName: 操作所查询的连麦房间。 | ||
105 | + */ | ||
106 | + public function listUser($appId, $roomName) | ||
107 | + { | ||
108 | + $url = sprintf("%s/%s/rooms/%s/users", $this->baseURL, $appId, $roomName); | ||
109 | + $ret = $this->get($url); | ||
110 | + return $ret; | ||
111 | + } | ||
112 | + | ||
113 | + /* | ||
114 | + * 踢出用户 | ||
115 | + * appId: app 的唯一标识,创建的时候由系统生成。 | ||
116 | + * roomName: 连麦房间 | ||
117 | + * userId: 请求加入房间的用户ID | ||
118 | + */ | ||
119 | + public function kickUser($appId, $roomName, $userId) | ||
120 | + { | ||
121 | + $url = sprintf("%s/%s/rooms/%s/users/%s", $this->baseURL, $appId, $roomName, $userId); | ||
122 | + list(, $err) = $this->delete($url); | ||
123 | + return $err; | ||
124 | + } | ||
125 | + | ||
126 | + /* | ||
127 | + * 获取应用中活跃房间 | ||
128 | + * appId: app 的唯一标识,创建的时候由系统生成。 | ||
129 | + * prefix: 所查询房间名的前缀索引,可以为空。 | ||
130 | + * offset: int 类型,分页查询的位移标记。 | ||
131 | + * limit: int 类型,此次查询的最大长度。 | ||
132 | + * GET /v3/apps/<AppID>/rooms?prefix=<RoomNamePrefix>&offset=<Offset>&limit=<Limit> | ||
133 | + */ | ||
134 | + public function listActiveRooms($appId, $prefix = null, $offset = null, $limit = null) | ||
135 | + { | ||
136 | + if (isset($prefix)) { | ||
137 | + $query['prefix'] = $prefix; | ||
138 | + } | ||
139 | + if (isset($offset)) { | ||
140 | + $query['offset'] = $offset; | ||
141 | + } | ||
142 | + if (isset($limit)) { | ||
143 | + $query['limit'] = $limit; | ||
144 | + } | ||
145 | + if (isset($query) && !empty($query)) { | ||
146 | + $query = '?' . http_build_query($query); | ||
147 | + $url = sprintf("%s/%s/rooms%s", $this->baseURL, $appId, $query); | ||
148 | + } else { | ||
149 | + $url = sprintf("%s/%s/rooms", $this->baseURL, $appId); | ||
150 | + } | ||
151 | + $ret = $this->get($url); | ||
152 | + return $ret; | ||
153 | + } | ||
154 | + | ||
155 | + /* | ||
156 | + * 生成加入房间的令牌 | ||
157 | + * appId: app 的唯一标识,创建的时候由系统生成。 | ||
158 | + * roomName: 房间名称,需满足规格 ^[a-zA-Z0-9_-]{3,64}$ | ||
159 | + * userId: 请求加入房间的用户 ID,需满足规格 ^[a-zA-Z0-9_-]{3,50}$ | ||
160 | + * expireAt: int64 类型,鉴权的有效时间,传入以秒为单位的64位Unix | ||
161 | + 绝对时间,token 将在该时间后失效。 | ||
162 | + * permission: 该用户的房间管理权限,"admin" 或 "user",默认为 "user" 。 | ||
163 | + 当权限角色为 "admin" 时,拥有将其他用户移除出房间等特权. | ||
164 | + */ | ||
165 | + public function appToken($appId, $roomName, $userId, $expireAt, $permission) | ||
166 | + { | ||
167 | + $params['appId'] = $appId; | ||
168 | + $params['userId'] = $userId; | ||
169 | + $params['roomName'] = $roomName; | ||
170 | + $params['permission'] = $permission; | ||
171 | + $params['expireAt'] = $expireAt; | ||
172 | + $appAccessString = json_encode($params); | ||
173 | + return $this->auth->signWithData($appAccessString); | ||
174 | + } | ||
175 | + | ||
176 | + private function get($url, $cType = null) | ||
177 | + { | ||
178 | + $rtcToken = $this->auth->authorizationV2($url, "GET", null, $cType); | ||
179 | + $rtcToken['Content-Type'] = $cType; | ||
180 | + $ret = Client::get($url, $rtcToken); | ||
181 | + if (!$ret->ok()) { | ||
182 | + return array(null, new Error($url, $ret)); | ||
183 | + } | ||
184 | + return array($ret->json(), null); | ||
185 | + } | ||
186 | + | ||
187 | + private function delete($url, $contentType = 'application/json') | ||
188 | + { | ||
189 | + $rtcToken = $this->auth->authorizationV2($url, "DELETE", null, $contentType); | ||
190 | + $rtcToken['Content-Type'] = $contentType; | ||
191 | + $ret = Client::delete($url, $rtcToken); | ||
192 | + if (!$ret->ok()) { | ||
193 | + return array(null, new Error($url, $ret)); | ||
194 | + } | ||
195 | + return array($ret->json(), null); | ||
196 | + } | ||
197 | + | ||
198 | + private function post($url, $body, $contentType = 'application/json') | ||
199 | + { | ||
200 | + $rtcToken = $this->auth->authorizationV2($url, "POST", $body, $contentType); | ||
201 | + $rtcToken['Content-Type'] = $contentType; | ||
202 | + $ret = Client::post($url, $body, $rtcToken); | ||
203 | + if (!$ret->ok()) { | ||
204 | + return array(null, new Error($url, $ret)); | ||
205 | + } | ||
206 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
207 | + return array($r, null); | ||
208 | + } | ||
209 | +} |
addons/qiniu/library/Qiniu/Sms/Sms.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu\Sms; | ||
3 | + | ||
4 | +use Qiniu\Http\Client; | ||
5 | +use Qiniu\Http\Error; | ||
6 | +use Qiniu\Config; | ||
7 | +use Qiniu\Auth; | ||
8 | + | ||
9 | +class Sms | ||
10 | +{ | ||
11 | + private $auth; | ||
12 | + private $baseURL; | ||
13 | + | ||
14 | + public function __construct(Auth $auth) | ||
15 | + { | ||
16 | + $this->auth = $auth; | ||
17 | + | ||
18 | + $this->baseURL = sprintf("%s/%s/", Config::SMS_HOST, Config::SMS_VERSION); | ||
19 | + } | ||
20 | + | ||
21 | + /* | ||
22 | + * 创建签名 | ||
23 | + * signature: string 类型,必填,【长度限制8个字符内】超过长度会报错 | ||
24 | + * source: string 类型,必填,申请签名时必须指定签名来源。取值范围为: | ||
25 | + nterprises_and_institutions 企事业单位的全称或简称 | ||
26 | + website 工信部备案网站的全称或简称 | ||
27 | + app APP应用的全称或简称 | ||
28 | + public_number_or_small_program 公众号或小程序的全称或简称 | ||
29 | + store_name 电商平台店铺名的全称或简称 | ||
30 | + trade_name 商标名的全称或简称, | ||
31 | + * pics: 本地的图片路径 string 类型,可选 | ||
32 | + *@return: 类型array { | ||
33 | + "signature_id": <signature_id> | ||
34 | + } | ||
35 | + */ | ||
36 | + public function createSignature($signature, $source, $pics = null) | ||
37 | + { | ||
38 | + $params['signature'] = $signature; | ||
39 | + $params['source'] = $source; | ||
40 | + if (!empty($pics)) { | ||
41 | + $params['pics'] = $this->imgToBase64($pics); | ||
42 | + } | ||
43 | + $body = json_encode($params); | ||
44 | + $url =$this->baseURL.'signature'; | ||
45 | + $ret = $this->post($url, $body); | ||
46 | + return $ret; | ||
47 | + } | ||
48 | + | ||
49 | + /* | ||
50 | + * 编辑签名 | ||
51 | + * id 签名id : string 类型,必填, | ||
52 | + * signature: string 类型,必填, | ||
53 | + * source: string 类型,必填,申请签名时必须指定签名来源。取值范围为: | ||
54 | + enterprises_and_institutions 企事业单位的全称或简称 | ||
55 | + website 工信部备案网站的全称或简称 | ||
56 | + app APP应用的全称或简称 | ||
57 | + public_number_or_small_program 公众号或小程序的全称或简称 | ||
58 | + store_name 电商平台店铺名的全称或简称 | ||
59 | + trade_name 商标名的全称或简称, | ||
60 | + * pics: 本地的图片路径 string 类型,可选, | ||
61 | + * @return: 类型array { | ||
62 | + "signature": string | ||
63 | + } | ||
64 | + */ | ||
65 | + public function updateSignature($id, $signature, $source, $pics = null) | ||
66 | + { | ||
67 | + $params['signature'] = $signature; | ||
68 | + $params['source'] = $source; | ||
69 | + if (!empty($pics)) { | ||
70 | + $params['pics'] = $this->imgToBase64($pics); | ||
71 | + } | ||
72 | + $body = json_encode($params); | ||
73 | + $url =$this->baseURL.'signature/'.$id; | ||
74 | + $ret = $this->PUT($url, $body); | ||
75 | + return $ret; | ||
76 | + } | ||
77 | + | ||
78 | + /* | ||
79 | + * 查询签名 | ||
80 | + * audit_status: 审核状态 string 类型,可选, | ||
81 | + 取值范围为: "passed"(通过), "rejected"(未通过), "reviewing"(审核中) | ||
82 | + * page:页码 int 类型, | ||
83 | + * page_size: 分页大小 int 类型,可选, 默认为20 | ||
84 | + *@return: 类型array { | ||
85 | + "items": [{ | ||
86 | + "id": string, | ||
87 | + "signature": string, | ||
88 | + "source": string, | ||
89 | + "audit_status": string, | ||
90 | + "reject_reason": string, | ||
91 | + "created_at": int64, | ||
92 | + "updated_at": int64 | ||
93 | + }...], | ||
94 | + "total": int, | ||
95 | + "page": int, | ||
96 | + "page_size": int, | ||
97 | + } | ||
98 | + */ | ||
99 | + public function checkSignature($audit_status = null, $page = 1, $page_size = 20) | ||
100 | + { | ||
101 | + | ||
102 | + $url = sprintf( | ||
103 | + "%s?audit_status=%s&page=%s&page_size=%s", | ||
104 | + $this->baseURL.'signature', | ||
105 | + $audit_status, | ||
106 | + $page, | ||
107 | + $page_size | ||
108 | + ); | ||
109 | + $ret = $this->get($url); | ||
110 | + return $ret; | ||
111 | + } | ||
112 | + | ||
113 | + | ||
114 | + /* | ||
115 | + * 删除签名 | ||
116 | + * id 签名id string 类型,必填, | ||
117 | + * @retrun : 请求成功 HTTP 状态码为 200 | ||
118 | + */ | ||
119 | + public function deleteSignature($id) | ||
120 | + { | ||
121 | + $url = $this->baseURL . 'signature/' . $id; | ||
122 | + list(, $err) = $this->delete($url); | ||
123 | + return $err; | ||
124 | + } | ||
125 | + | ||
126 | + | ||
127 | + | ||
128 | + | ||
129 | + /* | ||
130 | + * 创建模板 | ||
131 | + * name : 模板名称 string 类型 ,必填 | ||
132 | + * template: 模板内容 string 类型,必填 | ||
133 | + * type: 模板类型 string 类型,必填, | ||
134 | + 取值范围为: notification (通知类短信), verification (验证码短信), marketing (营销类短信) | ||
135 | + * description: 申请理由简述 string 类型,必填 | ||
136 | + * signature_id: 已经审核通过的签名 string 类型,必填 | ||
137 | + * @return: 类型 array { | ||
138 | + "template_id": string | ||
139 | + } | ||
140 | + */ | ||
141 | + public function createTemplate( | ||
142 | + $name, | ||
143 | + $template, | ||
144 | + $type, | ||
145 | + $description, | ||
146 | + $signture_id | ||
147 | + ) { | ||
148 | + $params['name'] = $name; | ||
149 | + $params['template'] = $template; | ||
150 | + $params['type'] = $type; | ||
151 | + $params['description'] = $description; | ||
152 | + $params['signature_id'] = $signture_id; | ||
153 | + | ||
154 | + $body = json_encode($params); | ||
155 | + $url =$this->baseURL.'template'; | ||
156 | + $ret = $this->post($url, $body); | ||
157 | + return $ret; | ||
158 | + } | ||
159 | + | ||
160 | + /* | ||
161 | + * 查询模板 | ||
162 | + * audit_status: 审核状态 string 类型 ,可选, | ||
163 | + 取值范围为: passed (通过), rejected (未通过), reviewing (审核中) | ||
164 | + * page: 页码 int 类型,可选,默认为 1 | ||
165 | + * page_size: 分页大小 int 类型,可选,默认为 20 | ||
166 | + * @return: 类型array{ | ||
167 | + "items": [{ | ||
168 | + "id": string, | ||
169 | + "name": string, | ||
170 | + "template": string, | ||
171 | + "audit_status": string, | ||
172 | + "reject_reason": string, | ||
173 | + "type": string, | ||
174 | + "signature_id": string, // 模版绑定的签名ID | ||
175 | + "signature_text": string, // 模版绑定的签名内容 | ||
176 | + "created_at": int64, | ||
177 | + "updated_at": int64 | ||
178 | + }...], | ||
179 | + "total": int, | ||
180 | + "page": int, | ||
181 | + "page_size": int | ||
182 | + } | ||
183 | + */ | ||
184 | + public function queryTemplate($audit_status = null, $page = 1, $page_size = 20) | ||
185 | + { | ||
186 | + | ||
187 | + $url = sprintf( | ||
188 | + "%s?audit_status=%s&page=%s&page_size=%s", | ||
189 | + $this->baseURL.'template', | ||
190 | + $audit_status, | ||
191 | + $page, | ||
192 | + $page_size | ||
193 | + ); | ||
194 | + $ret = $this->get($url); | ||
195 | + return $ret; | ||
196 | + } | ||
197 | + | ||
198 | + /* | ||
199 | + * 编辑模板 | ||
200 | + * id :模板id | ||
201 | + * name : 模板名称 string 类型 ,必填 | ||
202 | + * template: 模板内容 string 类型,必填 | ||
203 | + * description: 申请理由简述 string 类型,必填 | ||
204 | + * signature_id: 已经审核通过的签名 string 类型,必填 | ||
205 | + * @retrun : 请求成功 HTTP 状态码为 200 | ||
206 | + */ | ||
207 | + public function updateTemplate( | ||
208 | + $id, | ||
209 | + $name, | ||
210 | + $template, | ||
211 | + $description, | ||
212 | + $signature_id | ||
213 | + ) { | ||
214 | + $params['name'] = $name; | ||
215 | + $params['template'] = $template; | ||
216 | + $params['description'] = $description; | ||
217 | + $params['signature_id'] = $signature_id; | ||
218 | + $body = json_encode($params); | ||
219 | + $url =$this->baseURL.'template/'.$id; | ||
220 | + $ret = $this->PUT($url, $body); | ||
221 | + return $ret; | ||
222 | + } | ||
223 | + | ||
224 | + /* | ||
225 | + * 删除模板 | ||
226 | + * id :模板id string 类型,必填, | ||
227 | + * @retrun : 请求成功 HTTP 状态码为 200 | ||
228 | + */ | ||
229 | + public function deleteTemplate($id) | ||
230 | + { | ||
231 | + $url = $this->baseURL . 'template/' . $id; | ||
232 | + list(, $err) = $this->delete($url); | ||
233 | + return $err; | ||
234 | + } | ||
235 | + | ||
236 | + /* | ||
237 | + * 发送短信 | ||
238 | + * 编辑模板 | ||
239 | + * template_id :模板id string类型,必填 | ||
240 | + * mobiles : 手机号数组 []string 类型 ,必填 | ||
241 | + * parameters: 模板内容 map[string]string 类型,可选 | ||
242 | + * @return: 类型json { | ||
243 | + "job_id": string | ||
244 | + } | ||
245 | + */ | ||
246 | + public function sendMessage($template_id, $mobiles, $parameters = null) | ||
247 | + { | ||
248 | + $params['template_id'] = $template_id; | ||
249 | + $params['mobiles'] = $mobiles; | ||
250 | + if (!empty($parameters)) { | ||
251 | + $params['parameters'] = $parameters; | ||
252 | + } | ||
253 | + $body = json_encode($params); | ||
254 | + $url =$this->baseURL.'message'; | ||
255 | + $ret = $this->post($url, $body); | ||
256 | + return $ret; | ||
257 | + } | ||
258 | + | ||
259 | + public function imgToBase64($img_file) | ||
260 | + { | ||
261 | + $img_base64 = ''; | ||
262 | + if (file_exists($img_file)) { | ||
263 | + $app_img_file = $img_file; // 图片路径 | ||
264 | + $img_info = getimagesize($app_img_file); // 取得图片的大小,类型等 | ||
265 | + $fp = fopen($app_img_file, "r"); // 图片是否可读权限 | ||
266 | + if ($fp) { | ||
267 | + $filesize = filesize($app_img_file); | ||
268 | + if ($filesize > 5*1024*1024) { | ||
269 | + die("pic size < 5M !"); | ||
270 | + } | ||
271 | + $content = fread($fp, $filesize); | ||
272 | + $file_content = chunk_split(base64_encode($content)); // base64编码 | ||
273 | + switch ($img_info[2]) { //判读图片类型 | ||
274 | + case 1: | ||
275 | + $img_type = 'gif'; | ||
276 | + break; | ||
277 | + case 2: | ||
278 | + $img_type = 'jpg'; | ||
279 | + break; | ||
280 | + case 3: | ||
281 | + $img_type = 'png'; | ||
282 | + break; | ||
283 | + } | ||
284 | + //合成图片的base64编码 | ||
285 | + $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content; | ||
286 | + } | ||
287 | + fclose($fp); | ||
288 | + } | ||
289 | + | ||
290 | + return $img_base64; | ||
291 | + } | ||
292 | + | ||
293 | + private function get($url, $cType = null) | ||
294 | + { | ||
295 | + $rtcToken = $this->auth->authorizationV2($url, "GET", null, $cType); | ||
296 | + $rtcToken['Content-Type'] = $cType; | ||
297 | + $ret = Client::get($url, $rtcToken); | ||
298 | + if (!$ret->ok()) { | ||
299 | + return array(null, new Error($url, $ret)); | ||
300 | + } | ||
301 | + return array($ret->json(), null); | ||
302 | + } | ||
303 | + | ||
304 | + private function delete($url, $contentType = 'application/json') | ||
305 | + { | ||
306 | + $rtcToken = $this->auth->authorizationV2($url, "DELETE", null, $contentType); | ||
307 | + $rtcToken['Content-Type'] = $contentType; | ||
308 | + $ret = Client::delete($url, $rtcToken); | ||
309 | + if (!$ret->ok()) { | ||
310 | + return array(null, new Error($url, $ret)); | ||
311 | + } | ||
312 | + return array($ret->json(), null); | ||
313 | + } | ||
314 | + | ||
315 | + private function post($url, $body, $contentType = 'application/json') | ||
316 | + { | ||
317 | + $rtcToken = $this->auth->authorizationV2($url, "POST", $body, $contentType); | ||
318 | + $rtcToken['Content-Type'] = $contentType; | ||
319 | + $ret = Client::post($url, $body, $rtcToken); | ||
320 | + if (!$ret->ok()) { | ||
321 | + return array(null, new Error($url, $ret)); | ||
322 | + } | ||
323 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
324 | + return array($r, null); | ||
325 | + } | ||
326 | + private function PUT($url, $body, $contentType = 'application/json') | ||
327 | + { | ||
328 | + $rtcToken = $this->auth->authorizationV2($url, "PUT", $body, $contentType); | ||
329 | + $rtcToken['Content-Type'] = $contentType; | ||
330 | + $ret = Client::put($url, $body, $rtcToken); | ||
331 | + if (!$ret->ok()) { | ||
332 | + return array(null, new Error($url, $ret)); | ||
333 | + } | ||
334 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
335 | + return array($r, null); | ||
336 | + } | ||
337 | +} |
1 | +<?php | ||
2 | +namespace Qiniu\Storage; | ||
3 | + | ||
4 | +use Qiniu\Auth; | ||
5 | +use Qiniu\Config; | ||
6 | +use Qiniu\Zone; | ||
7 | +use Qiniu\Http\Client; | ||
8 | +use Qiniu\Http\Error; | ||
9 | + | ||
10 | +/** | ||
11 | + * 主要涉及了鉴黄接口的实现,具体的接口规格可以参考 | ||
12 | + * | ||
13 | + * @link https://developer.qiniu.com/dora/manual/3674/kodo-product-introduction | ||
14 | + */ | ||
15 | +final class ArgusManager | ||
16 | +{ | ||
17 | + private $auth; | ||
18 | + private $config; | ||
19 | + | ||
20 | + public function __construct(Auth $auth, Config $config = null) | ||
21 | + { | ||
22 | + $this->auth = $auth; | ||
23 | + if ($config == null) { | ||
24 | + $this->config = new Config(); | ||
25 | + } else { | ||
26 | + $this->config = $config; | ||
27 | + } | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * 视频鉴黄 | ||
32 | + * | ||
33 | + * @param $body body信息 | ||
34 | + * @param $vid videoID | ||
35 | + * | ||
36 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
37 | + * @link https://developer.qiniu.com/dora/manual/4258/video-pulp | ||
38 | + */ | ||
39 | + public function pulpVideo($body, $vid) | ||
40 | + { | ||
41 | + $path = '/v1/video/' . $vid; | ||
42 | + | ||
43 | + return $this->arPost($path, $body); | ||
44 | + } | ||
45 | + | ||
46 | + private function getArHost() | ||
47 | + { | ||
48 | + $scheme = "http://"; | ||
49 | + if ($this->config->useHTTPS == true) { | ||
50 | + $scheme = "https://"; | ||
51 | + } | ||
52 | + return $scheme . Config::ARGUS_HOST; | ||
53 | + } | ||
54 | + | ||
55 | + private function arPost($path, $body = null) | ||
56 | + { | ||
57 | + $url = $this->getArHost() . $path; | ||
58 | + return $this->post($url, $body); | ||
59 | + } | ||
60 | + | ||
61 | + private function post($url, $body) | ||
62 | + { | ||
63 | + $headers = $this->auth->authorizationV2($url, 'POST', $body, 'application/json'); | ||
64 | + $headers['Content-Type']='application/json'; | ||
65 | + $ret = Client::post($url, $body, $headers); | ||
66 | + if (!$ret->ok()) { | ||
67 | + print($ret->statusCode); | ||
68 | + return array(null, new Error($url, $ret)); | ||
69 | + } | ||
70 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
71 | + return array($r, null); | ||
72 | + } | ||
73 | +} |
1 | +<?php | ||
2 | +namespace Qiniu\Storage; | ||
3 | + | ||
4 | +use Qiniu\Auth; | ||
5 | +use Qiniu\Config; | ||
6 | +use Qiniu\Zone; | ||
7 | +use Qiniu\Http\Client; | ||
8 | +use Qiniu\Http\Error; | ||
9 | + | ||
10 | +/** | ||
11 | + * 主要涉及了空间资源管理及批量操作接口的实现,具体的接口规格可以参考 | ||
12 | + * | ||
13 | + * @link https://developer.qiniu.com/kodo/api/1274/rs | ||
14 | + */ | ||
15 | +final class BucketManager | ||
16 | +{ | ||
17 | + private $auth; | ||
18 | + private $config; | ||
19 | + | ||
20 | + public function __construct(Auth $auth, Config $config = null) | ||
21 | + { | ||
22 | + $this->auth = $auth; | ||
23 | + if ($config == null) { | ||
24 | + $this->config = new Config(); | ||
25 | + } else { | ||
26 | + $this->config = $config; | ||
27 | + } | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * 获取指定账号下所有的空间名。 | ||
32 | + * | ||
33 | + * @return string[] 包含所有空间名 | ||
34 | + */ | ||
35 | + public function buckets($shared = true) | ||
36 | + { | ||
37 | + $includeShared = "false"; | ||
38 | + if ($shared === true) { | ||
39 | + $includeShared = "true"; | ||
40 | + } | ||
41 | + return $this->rsGet('/buckets?shared=' . $includeShared); | ||
42 | + } | ||
43 | + | ||
44 | + /** | ||
45 | + * 列举空间,返回bucket列表 | ||
46 | + * region 指定区域,global 指定全局空间。 | ||
47 | + * 在指定了 region 参数时, | ||
48 | + * 如果指定 global 为 true,那么忽略 region 参数指定的区域,返回所有区域的全局空间。 | ||
49 | + * 如果没有指定 global 为 true,那么返回指定区域中非全局空间。 | ||
50 | + * 在没有指定 region 参数时(包括指定为空""), | ||
51 | + * 如果指定 global 为 true,那么返回所有区域的全局空间。 | ||
52 | + * 如果没有指定 global 为 true,那么返回指定区域中所有的空间,包括全局空间。 | ||
53 | + * 在指定了line为 true 时,只返回 Line 空间;否则,只返回非 Line 空间。 | ||
54 | + * share 参数用于指定共享空间。 | ||
55 | + */ | ||
56 | + | ||
57 | + public function listbuckets( | ||
58 | + $region = null, | ||
59 | + $line = 'false', | ||
60 | + $shared = 'false' | ||
61 | + ) { | ||
62 | + $path = '/v3/buckets?region=' . $region . '&line=' . $line . '&shared=' . $shared; | ||
63 | + $info = $this->ucPost($path); | ||
64 | + return $info; | ||
65 | + } | ||
66 | + | ||
67 | + /** | ||
68 | + * 创建空间 | ||
69 | + * | ||
70 | + * @param $name 创建的空间名 | ||
71 | + * @param $region 创建的区域,默认华东 | ||
72 | + * | ||
73 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
74 | + */ | ||
75 | + public function createBucket($name, $region = 'z0') | ||
76 | + { | ||
77 | + $path = '/mkbucketv2/'.$name.'/region/' . $region; | ||
78 | + return $this->rsPost($path, null); | ||
79 | + } | ||
80 | + | ||
81 | + /** | ||
82 | + * 删除空间 | ||
83 | + * | ||
84 | + * @param $name 删除的空间名 | ||
85 | + * | ||
86 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
87 | + */ | ||
88 | + public function deleteBucket($name) | ||
89 | + { | ||
90 | + $path = '/drop/'.$name; | ||
91 | + return $this->rsPost($path, null); | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * 获取指定空间绑定的所有的域名 | ||
96 | + * | ||
97 | + * @return string[] 包含所有空间域名 | ||
98 | + */ | ||
99 | + public function domains($bucket) | ||
100 | + { | ||
101 | + return $this->apiGet('/v6/domain/list?tbl=' . $bucket); | ||
102 | + } | ||
103 | + | ||
104 | + /** | ||
105 | + * 获取指定空间的相关信息 | ||
106 | + * | ||
107 | + * @return string[] 包含空间信息 | ||
108 | + */ | ||
109 | + public function bucketInfo($bucket) | ||
110 | + { | ||
111 | + $path = '/v2/bucketInfo?bucket=' . $bucket; | ||
112 | + $info = $this->ucPost($path); | ||
113 | + return $info; | ||
114 | + } | ||
115 | + | ||
116 | + /** | ||
117 | + * 获取指定zone的空间信息列表 | ||
118 | + * 在Region 未指定且Global 不为 true 时(包含未指定的情况,下同),返回用户的所有空间。 | ||
119 | + * 在指定了 region 参数且 global 不为 true 时,只列举非全局空间。 | ||
120 | + * shared 不指定shared参数或指定shared为rw或false时,返回包含具有读写权限空间, | ||
121 | + * 指定shared为rd或true时,返回包含具有读权限空间。 | ||
122 | + * fs:如果为 true,会返回每个空间当前的文件数和存储量(实时数据)。 | ||
123 | + * @return string[] 包含空间信息 | ||
124 | + */ | ||
125 | + public function bucketInfos($region = null, $shared = 'false', $fs = 'false') | ||
126 | + { | ||
127 | + $path = '/v2/bucketInfos?region=' . $region . '&shared=' . $shared . '&fs=' . $fs; | ||
128 | + $info = $this->ucPost($path); | ||
129 | + return $info; | ||
130 | + } | ||
131 | + | ||
132 | + /** | ||
133 | + * 获取空间绑定的域名列表 | ||
134 | + * @return string[] 包含空间绑定的所有域名 | ||
135 | + */ | ||
136 | + | ||
137 | + /** | ||
138 | + * 列取空间的文件列表 | ||
139 | + * | ||
140 | + * @param $bucket 空间名 | ||
141 | + * @param $prefix 列举前缀 | ||
142 | + * @param $marker 列举标识符 | ||
143 | + * @param $limit 单次列举个数限制 | ||
144 | + * @param $delimiter 指定目录分隔符 | ||
145 | + * | ||
146 | + * @return array 包含文件信息的数组,类似:[ | ||
147 | +* { | ||
148 | +* "hash" => "<Hash string>", | ||
149 | +* "key" => "<Key string>", | ||
150 | +* "fsize" => "<file size>", | ||
151 | +* "putTime" => "<file modify time>" | ||
152 | +* }, | ||
153 | +* ... | ||
154 | +* ] | ||
155 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/list.html | ||
156 | + */ | ||
157 | + public function listFiles( | ||
158 | + $bucket, | ||
159 | + $prefix = null, | ||
160 | + $marker = null, | ||
161 | + $limit = 1000, | ||
162 | + $delimiter = null | ||
163 | + ) { | ||
164 | + $query = array('bucket' => $bucket); | ||
165 | + \Qiniu\setWithoutEmpty($query, 'prefix', $prefix); | ||
166 | + \Qiniu\setWithoutEmpty($query, 'marker', $marker); | ||
167 | + \Qiniu\setWithoutEmpty($query, 'limit', $limit); | ||
168 | + \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter); | ||
169 | + $url = $this->getRsfHost() . '/list?' . http_build_query($query); | ||
170 | + return $this->get($url); | ||
171 | + } | ||
172 | + | ||
173 | + /** | ||
174 | + * 列取空间的文件列表 | ||
175 | + * | ||
176 | + * @param $bucket 空间名 | ||
177 | + * @param $prefix 列举前缀 | ||
178 | + * @param $marker 列举标识符 | ||
179 | + * @param $limit 单次列举个数限制 | ||
180 | + * @param $delimiter 指定目录分隔符 | ||
181 | + * @param $skipconfirm 是否跳过已删除条目的确认机制 | ||
182 | + * | ||
183 | + * @return array 包含文件信息的数组,类似:[ | ||
184 | +* { | ||
185 | +* "hash" => "<Hash string>", | ||
186 | +* "key" => "<Key string>", | ||
187 | +* "fsize" => "<file size>", | ||
188 | +* "putTime" => "<file modify time>" | ||
189 | +* }, | ||
190 | +* ... | ||
191 | +* ] | ||
192 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/list.html | ||
193 | + */ | ||
194 | + public function listFilesv2( | ||
195 | + $bucket, | ||
196 | + $prefix = null, | ||
197 | + $marker = null, | ||
198 | + $limit = 1000, | ||
199 | + $delimiter = null, | ||
200 | + $skipconfirm = true | ||
201 | + ) { | ||
202 | + $query = array('bucket' => $bucket); | ||
203 | + \Qiniu\setWithoutEmpty($query, 'prefix', $prefix); | ||
204 | + \Qiniu\setWithoutEmpty($query, 'marker', $marker); | ||
205 | + \Qiniu\setWithoutEmpty($query, 'limit', $limit); | ||
206 | + \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter); | ||
207 | + \Qiniu\setWithoutEmpty($query, 'skipconfirm', $skipconfirm); | ||
208 | + $path = '/v2/list?' . http_build_query($query); | ||
209 | + $url = $this->getRsfHost() . $path; | ||
210 | + $headers = $this->auth->authorization($url, null, 'application/x-www-form-urlencoded'); | ||
211 | + $ret = Client::post($url, null, $headers); | ||
212 | + if (!$ret->ok()) { | ||
213 | + return array(null, new Error($url, $ret)); | ||
214 | + } | ||
215 | + $r = explode("\n", $ret->body); | ||
216 | + $pop = array_pop($r); | ||
217 | + return array($r, null); | ||
218 | + } | ||
219 | + | ||
220 | + /** | ||
221 | + * 设置Referer防盗链 | ||
222 | + * | ||
223 | + * @param $bucket 空间名 | ||
224 | + * @param $mode 0: 表示关闭Referer(使用此选项将会忽略以下参数并将恢复默认值); | ||
225 | + * 1: 表示设置Referer白名单; 2:表示设置Referer黑名单 | ||
226 | + * @param $norefer 0: 表示不允许空 Refer 访问; 1: 表示允许空 Refer 访问 | ||
227 | + * @param $pattern 规则字符串, 当前允许格式分为三种: 一种为空主机头域名, | ||
228 | + * 比如 foo.com; 一种是泛域名,比如 *.bar.com; 一种是完全通配符, | ||
229 | + * 即一个 *; 多个规则之间用;隔开, 比如: foo.com;*.bar.com;sub.foo.com;*.sub.bar.com | ||
230 | + * @param $source_enabled 源站是否支持,默认为0只给CDN配置, 设置为1表示开启源站防盗链 | ||
231 | + * | ||
232 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
233 | + */ | ||
234 | + // public function referAntiLeech(){ | ||
235 | + | ||
236 | + // } | ||
237 | + | ||
238 | + /** | ||
239 | + * 增加bucket生命规则 | ||
240 | + * | ||
241 | + * @param $bucket 空间名 | ||
242 | + * @param $name 规则名称 bucket 内唯一,长度小于50,不能为空,只能为 | ||
243 | + * 字母、数字、下划线 | ||
244 | + * @param $prefix 同一个 bucket 里面前缀不能重复 | ||
245 | + * @param $delete_after_days 指定上传文件多少天后删除,指定为0表示不删除, | ||
246 | + * 大于0表示多少天后删除,需大于 to_line_after_days | ||
247 | + * @param $to_line_after_days 指定文件上传多少天后转低频存储。指定为0表示 | ||
248 | + * 不转低频存储,小于0表示上传的文件立即变低频存储 | ||
249 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
250 | + */ | ||
251 | + public function bucketLifecycleRule( | ||
252 | + $bucket, | ||
253 | + $name, | ||
254 | + $prefix, | ||
255 | + $delete_after_days, | ||
256 | + $to_line_after_days | ||
257 | + ) { | ||
258 | + $path = '/rules/add'; | ||
259 | + if ($bucket) { | ||
260 | + $params['bucket'] = $bucket; | ||
261 | + } | ||
262 | + if ($name) { | ||
263 | + $params['name'] = $name; | ||
264 | + } | ||
265 | + if ($prefix) { | ||
266 | + $params['prefix'] = $prefix; | ||
267 | + } | ||
268 | + if ($delete_after_days) { | ||
269 | + $params['delete_after_days'] = $delete_after_days; | ||
270 | + } | ||
271 | + if ($to_line_after_days) { | ||
272 | + $params['to_line_after_days'] = $to_line_after_days; | ||
273 | + } | ||
274 | + $data = http_build_query($params); | ||
275 | + $info = $this->ucPost($path, $data); | ||
276 | + return $info; | ||
277 | + } | ||
278 | + | ||
279 | + /** | ||
280 | + * 更新bucket生命规则 | ||
281 | + * | ||
282 | + * @param $bucket 空间名 | ||
283 | + * @param $name 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、 | ||
284 | + * 数字、下划线 | ||
285 | + * @param $prefix 同一个 bucket 里面前缀不能重复 | ||
286 | + * @param $delete_after_days 指定上传文件多少天后删除,指定为0表示不删除, | ||
287 | + * 大于0表示多少天后删除,需大于 to_line_after_days | ||
288 | + * @param $to_line_after_days 指定文件上传多少天后转低频存储。指定为0表示不 | ||
289 | + * 转低频存储,小于0表示上传的文件立即变低频存储 | ||
290 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
291 | + */ | ||
292 | + public function updateBucketLifecycleRule( | ||
293 | + $bucket, | ||
294 | + $name, | ||
295 | + $prefix, | ||
296 | + $delete_after_days, | ||
297 | + $to_line_after_days | ||
298 | + ) { | ||
299 | + $path = '/rules/update'; | ||
300 | + if ($bucket) { | ||
301 | + $params['bucket'] = $bucket; | ||
302 | + } | ||
303 | + if ($name) { | ||
304 | + $params['name'] = $name; | ||
305 | + } | ||
306 | + if ($prefix) { | ||
307 | + $params['prefix'] = $prefix; | ||
308 | + } | ||
309 | + if ($delete_after_days) { | ||
310 | + $params['delete_after_days'] = $delete_after_days; | ||
311 | + } | ||
312 | + if ($to_line_after_days) { | ||
313 | + $params['to_line_after_days'] = $to_line_after_days; | ||
314 | + } | ||
315 | + $data = http_build_query($params); | ||
316 | + $info = $this->ucPost($path, $data); | ||
317 | + return $info; | ||
318 | + } | ||
319 | + | ||
320 | + /** | ||
321 | + * 获取bucket生命规则 | ||
322 | + * | ||
323 | + * @param $bucket 空间名 | ||
324 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
325 | + */ | ||
326 | + public function getBucketLifecycleRules($bucket) | ||
327 | + { | ||
328 | + $path = '/rules/get?bucket=' . $bucket; | ||
329 | + $info = $this->ucGet($path); | ||
330 | + return $info; | ||
331 | + } | ||
332 | + | ||
333 | + /** | ||
334 | + * 删除bucket生命规则 | ||
335 | + * | ||
336 | + * @param $bucket 空间名 | ||
337 | + * @param $name 规则名称 bucket 内唯一,长度小于50,不能为空, | ||
338 | + * 只能为字母、数字、下划线() | ||
339 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
340 | + */ | ||
341 | + public function deleteBucketLifecycleRule($bucket, $name) | ||
342 | + { | ||
343 | + $path = '/rules/delete'; | ||
344 | + if ($bucket) { | ||
345 | + $params['bucket'] = $bucket; | ||
346 | + } | ||
347 | + if ($name) { | ||
348 | + $params['name'] = $name; | ||
349 | + } | ||
350 | + $data = http_build_query($params); | ||
351 | + $info = $this->ucPost($path, $data); | ||
352 | + return $info; | ||
353 | + } | ||
354 | + | ||
355 | + /** | ||
356 | + * 增加bucket事件通知规则 | ||
357 | + * | ||
358 | + * @param $bucket 空间名 | ||
359 | + * @param $name 规则名称 bucket 内唯一,长度小于50,不能为空, | ||
360 | + * 只能为字母、数字、下划线() | ||
361 | + * @param $prefix 同一个 bucket 里面前缀不能重复 | ||
362 | + * @param $suffix 可选,文件配置的后缀 | ||
363 | + * @param $event 事件类型,可以指定多个,包括 put,mkfile,delete,copy,move,append, | ||
364 | + * disable,enable,deleteMarkerCreate | ||
365 | + * @param $callbackURL 通知URL,可以指定多个,失败依次重试 | ||
366 | + * @param $access_key 可选,设置的话会对通知请求用对应的ak、sk进行签名 | ||
367 | + * @param $host 可选,通知请求的host | ||
368 | + * | ||
369 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
370 | + */ | ||
371 | + public function putBucketEvent( | ||
372 | + $bucket, | ||
373 | + $name, | ||
374 | + $prefix, | ||
375 | + $suffix, | ||
376 | + $event, | ||
377 | + $callbackURL, | ||
378 | + $access_key = null, | ||
379 | + $host = null | ||
380 | + ) { | ||
381 | + $path = '/events/add'; | ||
382 | + if ($bucket) { | ||
383 | + $params['bucket'] = $bucket; | ||
384 | + } | ||
385 | + if ($name) { | ||
386 | + $params['name'] = $name; | ||
387 | + } | ||
388 | + if ($prefix) { | ||
389 | + $params['prefix'] = $prefix; | ||
390 | + } | ||
391 | + if ($suffix) { | ||
392 | + $params['suffix'] = $suffix; | ||
393 | + } | ||
394 | + if ($callbackURL) { | ||
395 | + $params['callbackURL'] = $callbackURL; | ||
396 | + } | ||
397 | + if ($access_key) { | ||
398 | + $params['access_key'] = $access_key; | ||
399 | + } | ||
400 | + if ($host) { | ||
401 | + $params['host'] = $host; | ||
402 | + } | ||
403 | + $data = http_build_query($params); | ||
404 | + if ($event) { | ||
405 | + $eventpath = ""; | ||
406 | + foreach ($event as $key => $value) { | ||
407 | + $eventpath .= "&event=$value"; | ||
408 | + } | ||
409 | + $data .= $eventpath; | ||
410 | + } | ||
411 | + $info = $this->ucPost($path, $data); | ||
412 | + return $info; | ||
413 | + } | ||
414 | + | ||
415 | + /** | ||
416 | + * 更新bucket事件通知规则 | ||
417 | + * | ||
418 | + * @param $bucket 空间名 | ||
419 | + * @param $name 规则名称 bucket 内唯一,长度小于50,不能为空, | ||
420 | + * 只能为字母、数字、下划线() | ||
421 | + * @param $prefix 同一个 bucket 里面前缀不能重复 | ||
422 | + * @param $suffix 可选,文件配置的后缀 | ||
423 | + * @param $event 事件类型,可以指定多个,包括 put,mkfile,delete,copy,move,append,disable, | ||
424 | + * enable,deleteMarkerCreate | ||
425 | + * @param $callbackURL 通知URL,可以指定多个,失败依次重试 | ||
426 | + * @param $access_key 可选,设置的话会对通知请求用对应的ak、sk进行签名 | ||
427 | + * @param $host 可选,通知请求的host | ||
428 | + * | ||
429 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
430 | + */ | ||
431 | + public function updateBucketEvent( | ||
432 | + $bucket, | ||
433 | + $name, | ||
434 | + $prefix, | ||
435 | + $suffix, | ||
436 | + $event, | ||
437 | + $callbackURL, | ||
438 | + $access_key = null, | ||
439 | + $host = null | ||
440 | + ) { | ||
441 | + $path = '/events/update'; | ||
442 | + if ($bucket) { | ||
443 | + $params['bucket'] = $bucket; | ||
444 | + } | ||
445 | + if ($name) { | ||
446 | + $params['name'] = $name; | ||
447 | + } | ||
448 | + if ($prefix) { | ||
449 | + $params['prefix'] = $prefix; | ||
450 | + } | ||
451 | + if ($suffix) { | ||
452 | + $params['suffix'] = $suffix; | ||
453 | + } | ||
454 | + if ($event) { | ||
455 | + $params['event'] = $event; | ||
456 | + } | ||
457 | + if ($callbackURL) { | ||
458 | + $params['callbackURL'] = $callbackURL; | ||
459 | + } | ||
460 | + if ($access_key) { | ||
461 | + $params['access_key'] = $access_key; | ||
462 | + } | ||
463 | + if ($host) { | ||
464 | + $params['host'] = $host; | ||
465 | + } | ||
466 | + $data = http_build_query($params); | ||
467 | + $info = $this->ucPost($path, $data); | ||
468 | + return $info; | ||
469 | + } | ||
470 | + | ||
471 | + /** | ||
472 | + * 获取bucket事件通知规则 | ||
473 | + * | ||
474 | + * @param $bucket 空间名 | ||
475 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
476 | + */ | ||
477 | + public function getBucketEvents($bucket) | ||
478 | + { | ||
479 | + $path = '/events/get?bucket=' . $bucket; | ||
480 | + $info = $this->ucGet($path); | ||
481 | + return $info; | ||
482 | + } | ||
483 | + | ||
484 | + /** | ||
485 | + * 删除bucket事件通知规则 | ||
486 | + * | ||
487 | + * @param $bucket 空间名 | ||
488 | + * @param $name 规则名称 bucket 内唯一,长度小于50,不能为空, | ||
489 | + * 只能为字母、数字、下划线 | ||
490 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
491 | + */ | ||
492 | + public function deleteBucketEvent($bucket, $name) | ||
493 | + { | ||
494 | + $path = '/events/delete'; | ||
495 | + if ($bucket) { | ||
496 | + $params['bucket'] = $bucket; | ||
497 | + } | ||
498 | + if ($name) { | ||
499 | + $params['name'] = $name; | ||
500 | + } | ||
501 | + $data = http_build_query($params); | ||
502 | + $info = $this->ucPost($path, $data); | ||
503 | + return $info; | ||
504 | + } | ||
505 | + | ||
506 | + /** | ||
507 | + * 设置bucket的跨域信息,最多允许设置10条跨域规则。 | ||
508 | + * 对于同一个域名如果设置了多条规则,那么按顺序使用第一条匹配的规则去生成返回值。 | ||
509 | + * 对于简单跨域请求,只匹配 Origin; | ||
510 | + * allowed_orgin: 允许的域名。必填;支持通配符*;*表示全部匹配;只有第一个*生效; | ||
511 | + * 需要设置"Scheme";大小写敏感。例如 | ||
512 | + * 规则:http://*.abc.*.com 请求:"http://test.abc.test.com" 结果:不通过 | ||
513 | + * 规则:"http://abc.com" 请求:"https://abc.com"/"abc.com" 结果:不通过 | ||
514 | + * 规则:"abc.com" 请求:"http://abc.com" 结果:不通过 | ||
515 | + * allowed_method: 允许的方法。必填;不支持通配符;大小写不敏感; | ||
516 | + * allowed_header: 允许的header。选填;支持通配符*, | ||
517 | + * 但只能是单独的*,表示允许全部header,其他*不生效; | ||
518 | + * 空则不允许任何header;大小写不敏感; | ||
519 | + * exposed_header: 暴露的header。选填;不支持通配符; | ||
520 | + * X-Log, X-Reqid是默认会暴露的两个header; | ||
521 | + * 其他的header如果没有设置,则不会暴露;大小写不敏感; | ||
522 | + * max_age: 结果可以缓存的时间。选填;空则不缓存; | ||
523 | + * allowed_credentials:该配置不支持设置,默认为true。 | ||
524 | + * 备注:如果没有设置任何corsRules,那么默认允许所有的跨域请求 | ||
525 | + */ | ||
526 | + // public function putCorsRules(string $bucket, array $params) | ||
527 | + // { | ||
528 | + // $path = '/corsRules/set/' . $bucket; | ||
529 | + // $data = json_encode($params); | ||
530 | + // $info = $this->ucPost($path, $data); | ||
531 | + // return $info; | ||
532 | + // } | ||
533 | + | ||
534 | + /** | ||
535 | + * 获取bucket的跨域信息 | ||
536 | + * $bucket 空间名 | ||
537 | + */ | ||
538 | + public function getCorsRules($bucket) | ||
539 | + { | ||
540 | + $path = '/corsRules/get/' . $bucket; | ||
541 | + $info = $this->ucGet($path); | ||
542 | + return $info; | ||
543 | + } | ||
544 | + | ||
545 | + /** | ||
546 | + * 设置回源规则 | ||
547 | + * 使用该API设置源站优先级高于/image设置的源站,即IO优先读取source接口设置的源站配置, | ||
548 | + * 如果存在会忽略/image设置的源站 | ||
549 | + * Bucket 空间名 | ||
550 | + * Host(可选)回源Host | ||
551 | + * RetryCodes(可选),镜像回源时源站返回Code可以重试,最多指定3个,当前只支持4xx错误码重试 | ||
552 | + * SourceQiniuAK,SourceQiniuSK(可选)如果存在将在回源时对URL进行签名,客户源站可以验证 | ||
553 | + * 以保证请求来自Qiniu服务器 | ||
554 | + * Expires(可选) 签名过期时间,如果不设置默认为1小时 | ||
555 | + * Addr 回源地址,不可重复。 | ||
556 | + * Weight 权重,范围限制1-100,不填默认为1,回源时会根据所有源的权重值进行源站选择, | ||
557 | + * 主备源会分开计算. | ||
558 | + * Backup 是否备用回源,回源优先尝试主源 | ||
559 | + */ | ||
560 | + // public function putBucktSourceConfig(array $params) | ||
561 | + // { | ||
562 | + // $path = '/mirrorConfig/set'; | ||
563 | + // $data = json_encode($params); | ||
564 | + // $info = $this->ucPostV2($path, $data); | ||
565 | + // return $info; | ||
566 | + // } | ||
567 | + | ||
568 | + /** | ||
569 | + * 获取空间回源配置 | ||
570 | + */ | ||
571 | + public function getBucktSourceConfig(array $params) | ||
572 | + { | ||
573 | + $path = '/mirrorConfig/get'; | ||
574 | + $data = json_encode($params); | ||
575 | + $info = $this->ucPostV2($path, $data); | ||
576 | + return $info; | ||
577 | + } | ||
578 | + | ||
579 | + /** | ||
580 | + * 开关原图保护 | ||
581 | + * mode 为1表示开启原图保护,0表示关闭 | ||
582 | + */ | ||
583 | + public function putBucketAccessStyleMode($bucket, $mode) | ||
584 | + { | ||
585 | + $path = '/accessMode/' . $bucket . '/mode/' . $mode; | ||
586 | + $info = $this->ucPost($path, null); | ||
587 | + return $info; | ||
588 | + } | ||
589 | + | ||
590 | + /** | ||
591 | + * 设置私有属性 | ||
592 | + * private为0表示公开,为1表示私有 | ||
593 | + */ | ||
594 | + public function putBucketAccessMode($bucket, $private) | ||
595 | + { | ||
596 | + $path = '/bucket/' . $bucket . '/private/' . $private; | ||
597 | + $info = $this->ucPost($path, null); | ||
598 | + return $info; | ||
599 | + } | ||
600 | + | ||
601 | + /** | ||
602 | + * 设置referer防盗链 | ||
603 | + * bucket=<BucketName>: bucket 名 | ||
604 | + * mode=<AntiLeechMode>: | ||
605 | + * 0: 表示关闭Referer(使用此选项将会忽略以下参数并将恢复默认值); | ||
606 | + * 1: 表示设置Referer白名单; 2: 表示设置Referer黑名单 | ||
607 | + * norefer=<NoRefer>: 0: 表示不允许空 Refer 访问; | ||
608 | + * 1: 表示允许空 Refer 访问 | ||
609 | + * pattern=<Pattern>: 规则字符串, 当前允许格式分为三种: | ||
610 | + * 一种为空主机头域名, 比如 foo.com; | ||
611 | + * 一种是泛域名, 比如 *.bar.com; 一种是完全通配符, 即一个 *; | ||
612 | + * 多个规则之间用;隔开, 比如: foo.com;*.bar.com;sub.foo.com;*.sub.bar.com | ||
613 | + * 空主机头域名可以是多级域名,比如 foo.bar.com。 | ||
614 | + * 多个域名之间不允许夹带空白字符。 | ||
615 | + * source_enabled=:1 | ||
616 | + */ | ||
617 | + public function putReferAntiLeech($bucket, $mode, $norefer, $pattern, $enabled = 1) | ||
618 | + { | ||
619 | + $path = "/referAntiLeech?bucket=$bucket&mode=$mode&norefer=$norefer&pattern=$pattern&source_enabled=$enabled"; | ||
620 | + $info = $this->ucPost($path, null); | ||
621 | + return $info; | ||
622 | + } | ||
623 | + | ||
624 | + /** | ||
625 | + * 设置Bucket的maxAge | ||
626 | + * maxAge为0或者负数表示为默认值(31536000) | ||
627 | + */ | ||
628 | + public function putBucketMaxAge($bucket, $maxAge) | ||
629 | + { | ||
630 | + $path = '/maxAge?bucket=' . $bucket . '&maxAge=' . $maxAge; | ||
631 | + $info = $this->ucPost($path, null); | ||
632 | + return $info; | ||
633 | + } | ||
634 | + | ||
635 | + /** | ||
636 | + * 设置配额 | ||
637 | + * <bucket>: 空间名称,不支持授权空间 | ||
638 | + * <size>: 空间存储量配额,参数传入0或不传表示不更改当前配置,传入-1表示取消限额, | ||
639 | + * 新创建的空间默认没有限额。 | ||
640 | + * <count>: 空间文件数配额,参数含义同<size> | ||
641 | + */ | ||
642 | + public function putBucketQuota($bucket, $size, $count) | ||
643 | + { | ||
644 | + $path = '/setbucketquota/' . $bucket . '/size/' . $size . '/count/' . $count; | ||
645 | + $info = $this->apiPost($path, null); | ||
646 | + return $info; | ||
647 | + } | ||
648 | + | ||
649 | + /** | ||
650 | + * 获取配额 | ||
651 | + * bucket 空间名称 | ||
652 | + */ | ||
653 | + public function getBucketQuota($bucket) | ||
654 | + { | ||
655 | + $path = '/getbucketquota/' . $bucket; | ||
656 | + $info = $this->apiPost($path, null); | ||
657 | + return $info; | ||
658 | + } | ||
659 | + | ||
660 | + /** | ||
661 | + * 获取资源的元信息,但不返回文件内容 | ||
662 | + * | ||
663 | + * @param $bucket 待获取信息资源所在的空间 | ||
664 | + * @param $key 待获取资源的文件名 | ||
665 | + * | ||
666 | + * @return array 包含文件信息的数组,类似: | ||
667 | +* [ | ||
668 | +* "hash" => "<Hash string>", | ||
669 | +* "key" => "<Key string>", | ||
670 | +* "fsize" => <file size>, | ||
671 | +* "putTime" => "<file modify time>" | ||
672 | +* "fileType" => <file type> | ||
673 | +* ] | ||
674 | + * | ||
675 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/stat.html | ||
676 | + */ | ||
677 | + public function stat($bucket, $key) | ||
678 | + { | ||
679 | + $path = '/stat/' . \Qiniu\entry($bucket, $key); | ||
680 | + return $this->rsGet($path); | ||
681 | + } | ||
682 | + | ||
683 | + /** | ||
684 | + * 删除指定资源 | ||
685 | + * | ||
686 | + * @param $bucket 待删除资源所在的空间 | ||
687 | + * @param $key 待删除资源的文件名 | ||
688 | + * | ||
689 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
690 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/delete.html | ||
691 | + */ | ||
692 | + public function delete($bucket, $key) | ||
693 | + { | ||
694 | + $path = '/delete/' . \Qiniu\entry($bucket, $key); | ||
695 | + list(, $error) = $this->rsPost($path); | ||
696 | + return $error; | ||
697 | + } | ||
698 | + | ||
699 | + | ||
700 | + /** | ||
701 | + * 给资源进行重命名,本质为move操作。 | ||
702 | + * | ||
703 | + * @param $bucket 待操作资源所在空间 | ||
704 | + * @param $oldname 待操作资源文件名 | ||
705 | + * @param $newname 目标资源文件名 | ||
706 | + * | ||
707 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
708 | + */ | ||
709 | + public function rename($bucket, $oldname, $newname) | ||
710 | + { | ||
711 | + return $this->move($bucket, $oldname, $bucket, $newname); | ||
712 | + } | ||
713 | + | ||
714 | + /** | ||
715 | + * 对资源进行复制。 | ||
716 | + * | ||
717 | + * @param $from_bucket 待操作资源所在空间 | ||
718 | + * @param $from_key 待操作资源文件名 | ||
719 | + * @param $to_bucket 目标资源空间名 | ||
720 | + * @param $to_key 目标资源文件名 | ||
721 | + * | ||
722 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
723 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/copy.html | ||
724 | + */ | ||
725 | + public function copy($from_bucket, $from_key, $to_bucket, $to_key, $force = false) | ||
726 | + { | ||
727 | + $from = \Qiniu\entry($from_bucket, $from_key); | ||
728 | + $to = \Qiniu\entry($to_bucket, $to_key); | ||
729 | + $path = '/copy/' . $from . '/' . $to; | ||
730 | + if ($force === true) { | ||
731 | + $path .= '/force/true'; | ||
732 | + } | ||
733 | + list(, $error) = $this->rsPost($path); | ||
734 | + return $error; | ||
735 | + } | ||
736 | + | ||
737 | + /** | ||
738 | + * 将资源从一个空间到另一个空间 | ||
739 | + * | ||
740 | + * @param $from_bucket 待操作资源所在空间 | ||
741 | + * @param $from_key 待操作资源文件名 | ||
742 | + * @param $to_bucket 目标资源空间名 | ||
743 | + * @param $to_key 目标资源文件名 | ||
744 | + * | ||
745 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
746 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/move.html | ||
747 | + */ | ||
748 | + public function move($from_bucket, $from_key, $to_bucket, $to_key, $force = false) | ||
749 | + { | ||
750 | + $from = \Qiniu\entry($from_bucket, $from_key); | ||
751 | + $to = \Qiniu\entry($to_bucket, $to_key); | ||
752 | + $path = '/move/' . $from . '/' . $to; | ||
753 | + if ($force) { | ||
754 | + $path .= '/force/true'; | ||
755 | + } | ||
756 | + list(, $error) = $this->rsPost($path); | ||
757 | + return $error; | ||
758 | + } | ||
759 | + | ||
760 | + /** | ||
761 | + * 主动修改指定资源的文件元信息 | ||
762 | + * | ||
763 | + * @param $bucket 待操作资源所在空间 | ||
764 | + * @param $key 待操作资源文件名 | ||
765 | + * @param $mime 待操作文件目标mimeType | ||
766 | + * | ||
767 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
768 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/chgm.html | ||
769 | + */ | ||
770 | + public function changeMime($bucket, $key, $mime) | ||
771 | + { | ||
772 | + $resource = \Qiniu\entry($bucket, $key); | ||
773 | + $encode_mime = \Qiniu\base64_urlSafeEncode($mime); | ||
774 | + $path = '/chgm/' . $resource . '/mime/' . $encode_mime; | ||
775 | + list(, $error) = $this->rsPost($path); | ||
776 | + return $error; | ||
777 | + } | ||
778 | + | ||
779 | + | ||
780 | + /** | ||
781 | + * 修改指定资源的存储类型 | ||
782 | + * | ||
783 | + * @param $bucket 待操作资源所在空间 | ||
784 | + * @param $key 待操作资源文件名 | ||
785 | + * @param $fileType 待操作文件目标文件类型 | ||
786 | + * | ||
787 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
788 | + * @link https://developer.qiniu.com/kodo/api/3710/modify-the-file-type | ||
789 | + */ | ||
790 | + public function changeType($bucket, $key, $fileType) | ||
791 | + { | ||
792 | + $resource = \Qiniu\entry($bucket, $key); | ||
793 | + $path = '/chtype/' . $resource . '/type/' . $fileType; | ||
794 | + list(, $error) = $this->rsPost($path); | ||
795 | + return $error; | ||
796 | + } | ||
797 | + | ||
798 | + /** | ||
799 | + * 修改文件的存储状态,即禁用状态和启用状态间的的互相转换 | ||
800 | + * | ||
801 | + * @param $bucket 待操作资源所在空间 | ||
802 | + * @param $key 待操作资源文件名 | ||
803 | + * @param $status 待操作文件目标文件类型 | ||
804 | + * | ||
805 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
806 | + * @link https://developer.qiniu.com/kodo/api/4173/modify-the-file-status | ||
807 | + */ | ||
808 | + public function changeStatus($bucket, $key, $status) | ||
809 | + { | ||
810 | + $resource = \Qiniu\entry($bucket, $key); | ||
811 | + $path = '/chstatus/' . $resource . '/status/' . $status; | ||
812 | + list(, $error) = $this->rsPost($path); | ||
813 | + return $error; | ||
814 | + } | ||
815 | + | ||
816 | + /** | ||
817 | + * 从指定URL抓取资源,并将该资源存储到指定空间中 | ||
818 | + * | ||
819 | + * @param $url 指定的URL | ||
820 | + * @param $bucket 目标资源空间 | ||
821 | + * @param $key 目标资源文件名 | ||
822 | + * | ||
823 | + * @return array 包含已拉取的文件信息。 | ||
824 | + * 成功时: [ | ||
825 | + * [ | ||
826 | + * "hash" => "<Hash string>", | ||
827 | + * "key" => "<Key string>" | ||
828 | + * ], | ||
829 | + * null | ||
830 | + * ] | ||
831 | + * | ||
832 | + * 失败时: [ | ||
833 | + * null, | ||
834 | + * Qiniu/Http/Error | ||
835 | + * ] | ||
836 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/fetch.html | ||
837 | + */ | ||
838 | + public function fetch($url, $bucket, $key = null) | ||
839 | + { | ||
840 | + | ||
841 | + $resource = \Qiniu\base64_urlSafeEncode($url); | ||
842 | + $to = \Qiniu\entry($bucket, $key); | ||
843 | + $path = '/fetch/' . $resource . '/to/' . $to; | ||
844 | + | ||
845 | + $ak = $this->auth->getAccessKey(); | ||
846 | + $ioHost = $this->config->getIovipHost($ak, $bucket); | ||
847 | + | ||
848 | + $url = $ioHost . $path; | ||
849 | + return $this->post($url, null); | ||
850 | + } | ||
851 | + | ||
852 | + /** | ||
853 | + * 从镜像源站抓取资源到空间中,如果空间中已经存在,则覆盖该资源 | ||
854 | + * | ||
855 | + * @param $bucket 待获取资源所在的空间 | ||
856 | + * @param $key 代获取资源文件名 | ||
857 | + * | ||
858 | + * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error | ||
859 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/prefetch.html | ||
860 | + */ | ||
861 | + public function prefetch($bucket, $key) | ||
862 | + { | ||
863 | + $resource = \Qiniu\entry($bucket, $key); | ||
864 | + $path = '/prefetch/' . $resource; | ||
865 | + | ||
866 | + $ak = $this->auth->getAccessKey(); | ||
867 | + $ioHost = $this->config->getIovipHost($ak, $bucket); | ||
868 | + | ||
869 | + $url = $ioHost . $path; | ||
870 | + list(, $error) = $this->post($url, null); | ||
871 | + return $error; | ||
872 | + } | ||
873 | + | ||
874 | + /** | ||
875 | + * 在单次请求中进行多个资源管理操作 | ||
876 | + * | ||
877 | + * @param $operations 资源管理操作数组 | ||
878 | + * | ||
879 | + * @return array 每个资源的处理情况,结果类似: | ||
880 | + * [ | ||
881 | + * { "code" => <HttpCode int>, "data" => <Data> }, | ||
882 | + * { "code" => <HttpCode int> }, | ||
883 | + * { "code" => <HttpCode int> }, | ||
884 | + * { "code" => <HttpCode int> }, | ||
885 | + * { "code" => <HttpCode int>, "data" => { "error": "<ErrorMessage string>" } }, | ||
886 | + * ... | ||
887 | + * ] | ||
888 | + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/batch.html | ||
889 | + */ | ||
890 | + public function batch($operations) | ||
891 | + { | ||
892 | + $params = 'op=' . implode('&op=', $operations); | ||
893 | + return $this->rsPost('/batch', $params); | ||
894 | + } | ||
895 | + | ||
896 | + /** | ||
897 | + * 设置文件的生命周期 | ||
898 | + * | ||
899 | + * @param $bucket 设置文件生命周期文件所在的空间 | ||
900 | + * @param $key 设置文件生命周期文件的文件名 | ||
901 | + * @param $days 设置该文件多少天后删除,当$days设置为0时表示取消该文件的生命周期 | ||
902 | + * | ||
903 | + * @return Mixed | ||
904 | + * @link https://developer.qiniu.com/kodo/api/update-file-lifecycle | ||
905 | + */ | ||
906 | + public function deleteAfterDays($bucket, $key, $days) | ||
907 | + { | ||
908 | + $entry = \Qiniu\entry($bucket, $key); | ||
909 | + $path = "/deleteAfterDays/$entry/$days"; | ||
910 | + list(, $error) = $this->rsPost($path); | ||
911 | + return $error; | ||
912 | + } | ||
913 | + | ||
914 | + private function getRsfHost() | ||
915 | + { | ||
916 | + $scheme = "http://"; | ||
917 | + if ($this->config->useHTTPS == true) { | ||
918 | + $scheme = "https://"; | ||
919 | + } | ||
920 | + return $scheme . Config::RSF_HOST; | ||
921 | + } | ||
922 | + | ||
923 | + private function getRsHost() | ||
924 | + { | ||
925 | + $scheme = "http://"; | ||
926 | + if ($this->config->useHTTPS == true) { | ||
927 | + $scheme = "https://"; | ||
928 | + } | ||
929 | + return $scheme . Config::RS_HOST; | ||
930 | + } | ||
931 | + | ||
932 | + private function getApiHost() | ||
933 | + { | ||
934 | + $scheme = "http://"; | ||
935 | + if ($this->config->useHTTPS == true) { | ||
936 | + $scheme = "https://"; | ||
937 | + } | ||
938 | + return $scheme . Config::API_HOST; | ||
939 | + } | ||
940 | + | ||
941 | + private function getUcHost() | ||
942 | + { | ||
943 | + $scheme = "http://"; | ||
944 | + if ($this->config->useHTTPS == true) { | ||
945 | + $scheme = "https://"; | ||
946 | + } | ||
947 | + return $scheme . Config::UC_HOST; | ||
948 | + } | ||
949 | + | ||
950 | + private function rsPost($path, $body = null) | ||
951 | + { | ||
952 | + $url = $this->getRsHost() . $path; | ||
953 | + return $this->post($url, $body); | ||
954 | + } | ||
955 | + | ||
956 | + private function apiPost($path, $body = null) | ||
957 | + { | ||
958 | + $url = $this->getApiHost() . $path; | ||
959 | + return $this->post($url, $body); | ||
960 | + } | ||
961 | + | ||
962 | + private function ucPost($path, $body = null) | ||
963 | + { | ||
964 | + $url = $this->getUcHost() . $path; | ||
965 | + return $this->post($url, $body); | ||
966 | + } | ||
967 | + | ||
968 | + private function ucGet($path) | ||
969 | + { | ||
970 | + $url = $this->getUcHost() . $path; | ||
971 | + return $this->get($url); | ||
972 | + } | ||
973 | + | ||
974 | + private function apiGet($path) | ||
975 | + { | ||
976 | + $url = $this->getApiHost() . $path; | ||
977 | + return $this->get($url); | ||
978 | + } | ||
979 | + | ||
980 | + private function rsGet($path) | ||
981 | + { | ||
982 | + $url = $this->getRsHost() . $path; | ||
983 | + return $this->get($url); | ||
984 | + } | ||
985 | + | ||
986 | + private function get($url) | ||
987 | + { | ||
988 | + $headers = $this->auth->authorization($url); | ||
989 | + $ret = Client::get($url, $headers); | ||
990 | + if (!$ret->ok()) { | ||
991 | + return array(null, new Error($url, $ret)); | ||
992 | + } | ||
993 | + return array($ret->json(), null); | ||
994 | + } | ||
995 | + | ||
996 | + private function post($url, $body) | ||
997 | + { | ||
998 | + $headers = $this->auth->authorization($url, $body, 'application/x-www-form-urlencoded'); | ||
999 | + $ret = Client::post($url, $body, $headers); | ||
1000 | + if (!$ret->ok()) { | ||
1001 | + return array(null, new Error($url, $ret)); | ||
1002 | + } | ||
1003 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
1004 | + return array($r, null); | ||
1005 | + } | ||
1006 | + | ||
1007 | + private function ucPostV2($path, $body) | ||
1008 | + { | ||
1009 | + $url = $this->getUcHost() . $path; | ||
1010 | + return $this->postV2($url, $body); | ||
1011 | + } | ||
1012 | + | ||
1013 | + private function postV2($url, $body) | ||
1014 | + { | ||
1015 | + $headers = $this->auth->authorizationV2($url, 'POST', $body, 'application/json'); | ||
1016 | + $headers["Content-Type"] = 'application/json'; | ||
1017 | + $ret = Client::post($url, $body, $headers); | ||
1018 | + if (!$ret->ok()) { | ||
1019 | + return array(null, new Error($url, $ret)); | ||
1020 | + } | ||
1021 | + $r = ($ret->body === null) ? array() : $ret->json(); | ||
1022 | + return array($r, null); | ||
1023 | + } | ||
1024 | + | ||
1025 | + public static function buildBatchCopy($source_bucket, $key_pairs, $target_bucket, $force) | ||
1026 | + { | ||
1027 | + return self::twoKeyBatch('/copy', $source_bucket, $key_pairs, $target_bucket, $force); | ||
1028 | + } | ||
1029 | + | ||
1030 | + | ||
1031 | + public static function buildBatchRename($bucket, $key_pairs, $force) | ||
1032 | + { | ||
1033 | + return self::buildBatchMove($bucket, $key_pairs, $bucket, $force); | ||
1034 | + } | ||
1035 | + | ||
1036 | + | ||
1037 | + public static function buildBatchMove($source_bucket, $key_pairs, $target_bucket, $force) | ||
1038 | + { | ||
1039 | + return self::twoKeyBatch('/move', $source_bucket, $key_pairs, $target_bucket, $force); | ||
1040 | + } | ||
1041 | + | ||
1042 | + | ||
1043 | + public static function buildBatchDelete($bucket, $keys) | ||
1044 | + { | ||
1045 | + return self::oneKeyBatch('/delete', $bucket, $keys); | ||
1046 | + } | ||
1047 | + | ||
1048 | + | ||
1049 | + public static function buildBatchStat($bucket, $keys) | ||
1050 | + { | ||
1051 | + return self::oneKeyBatch('/stat', $bucket, $keys); | ||
1052 | + } | ||
1053 | + | ||
1054 | + public static function buildBatchDeleteAfterDays($bucket, $key_day_pairs) | ||
1055 | + { | ||
1056 | + $data = array(); | ||
1057 | + foreach ($key_day_pairs as $key => $day) { | ||
1058 | + array_push($data, '/deleteAfterDays/' . \Qiniu\entry($bucket, $key) . '/' . $day); | ||
1059 | + } | ||
1060 | + return $data; | ||
1061 | + } | ||
1062 | + | ||
1063 | + public static function buildBatchChangeMime($bucket, $key_mime_pairs) | ||
1064 | + { | ||
1065 | + $data = array(); | ||
1066 | + foreach ($key_mime_pairs as $key => $mime) { | ||
1067 | + array_push($data, '/chgm/' . \Qiniu\entry($bucket, $key) . '/mime/' . base64_encode($mime)); | ||
1068 | + } | ||
1069 | + return $data; | ||
1070 | + } | ||
1071 | + | ||
1072 | + public static function buildBatchChangeType($bucket, $key_type_pairs) | ||
1073 | + { | ||
1074 | + $data = array(); | ||
1075 | + foreach ($key_type_pairs as $key => $type) { | ||
1076 | + array_push($data, '/chtype/' . \Qiniu\entry($bucket, $key) . '/type/' . $type); | ||
1077 | + } | ||
1078 | + return $data; | ||
1079 | + } | ||
1080 | + | ||
1081 | + private static function oneKeyBatch($operation, $bucket, $keys) | ||
1082 | + { | ||
1083 | + $data = array(); | ||
1084 | + foreach ($keys as $key) { | ||
1085 | + array_push($data, $operation . '/' . \Qiniu\entry($bucket, $key)); | ||
1086 | + } | ||
1087 | + return $data; | ||
1088 | + } | ||
1089 | + | ||
1090 | + private static function twoKeyBatch($operation, $source_bucket, $key_pairs, $target_bucket, $force) | ||
1091 | + { | ||
1092 | + if ($target_bucket === null) { | ||
1093 | + $target_bucket = $source_bucket; | ||
1094 | + } | ||
1095 | + $data = array(); | ||
1096 | + $forceOp = "false"; | ||
1097 | + if ($force) { | ||
1098 | + $forceOp = "true"; | ||
1099 | + } | ||
1100 | + foreach ($key_pairs as $from_key => $to_key) { | ||
1101 | + $from = \Qiniu\entry($source_bucket, $from_key); | ||
1102 | + $to = \Qiniu\entry($target_bucket, $to_key); | ||
1103 | + array_push($data, $operation . '/' . $from . '/' . $to . "/force/" . $forceOp); | ||
1104 | + } | ||
1105 | + return $data; | ||
1106 | + } | ||
1107 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu\Storage; | ||
4 | + | ||
5 | +use Qiniu\Config; | ||
6 | +use Qiniu\Http\Client; | ||
7 | +use Qiniu\Http\Error; | ||
8 | + | ||
9 | +final class FormUploader | ||
10 | +{ | ||
11 | + | ||
12 | + /** | ||
13 | + * 上传二进制流到七牛, 内部使用 | ||
14 | + * | ||
15 | + * @param string $upToken 上传凭证 | ||
16 | + * @param string $key 上传文件名 | ||
17 | + * @param resource $data 上传二进制流 | ||
18 | + * @param Config $config 上传配置 | ||
19 | + * @param array $params 自定义变量,规格参考 http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar | ||
20 | + * @param string $mime 上传数据的mimeType | ||
21 | + * | ||
22 | + * @return array 包含已上传文件的信息,类似: | ||
23 | + * [ | ||
24 | + * "hash" => "<Hash string>", | ||
25 | + * "key" => "<Key string>" | ||
26 | + * ] | ||
27 | + */ | ||
28 | + public static function put($upToken, $key, $data, $config, $params, $mime, $fname) | ||
29 | + { | ||
30 | + $fields = array('token' => $upToken); | ||
31 | + if ($key === null) { | ||
32 | + } else { | ||
33 | + $fields['key'] = $key; | ||
34 | + } | ||
35 | + | ||
36 | + //enable crc32 check by default | ||
37 | + $fields['crc32'] = \Qiniu\crc32_data($data); | ||
38 | + | ||
39 | + if ($params) { | ||
40 | + foreach ($params as $k => $v) { | ||
41 | + $fields[$k] = $v; | ||
42 | + } | ||
43 | + } | ||
44 | + | ||
45 | + list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); | ||
46 | + if ($err != null) { | ||
47 | + return array(null, $err); | ||
48 | + } | ||
49 | + | ||
50 | + $upHost = $config->getUpHost($accessKey, $bucket); | ||
51 | + | ||
52 | + $response = Client::multipartPost($upHost, $fields, 'file', $fname, $data, $mime); | ||
53 | + if (!$response->ok()) { | ||
54 | + return array(null, new Error($upHost, $response)); | ||
55 | + } | ||
56 | + return array($response->json(), null); | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * 上传文件到七牛,内部使用 | ||
61 | + * | ||
62 | + * @param string $upToken 上传凭证 | ||
63 | + * @param string $key 上传文件名 | ||
64 | + * @param string $filePath 上传文件的路径 | ||
65 | + * @param Config $config 上传配置 | ||
66 | + * @param array $params 自定义变量,规格参考 http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar | ||
67 | + * @param string $mime 上传数据的mimeType | ||
68 | + * | ||
69 | + * @return array 包含已上传文件的信息,类似: | ||
70 | + * [ | ||
71 | + * "hash" => "<Hash string>", | ||
72 | + * "key" => "<Key string>" | ||
73 | + * ] | ||
74 | + */ | ||
75 | + public static function putFile($upToken, $key, $filePath, $config, $params, $mime) | ||
76 | + { | ||
77 | + $fields = array('token' => $upToken, 'file' => self::createFile($filePath, $mime)); | ||
78 | + if ($key !== null) { | ||
79 | + $fields['key'] = $key; | ||
80 | + } | ||
81 | + | ||
82 | + $fields['crc32'] = \Qiniu\crc32_file($filePath); | ||
83 | + | ||
84 | + if ($params) { | ||
85 | + foreach ($params as $k => $v) { | ||
86 | + $fields[$k] = $v; | ||
87 | + } | ||
88 | + } | ||
89 | + $fields['key'] = $key; | ||
90 | + $headers = array('Content-Type' => 'multipart/form-data'); | ||
91 | + | ||
92 | + list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); | ||
93 | + if ($err != null) { | ||
94 | + return array(null, $err); | ||
95 | + } | ||
96 | + | ||
97 | + $upHost = $config->getUpHost($accessKey, $bucket); | ||
98 | + | ||
99 | + $response = Client::post($upHost, $fields, $headers); | ||
100 | + if (!$response->ok()) { | ||
101 | + return array(null, new Error($upHost, $response)); | ||
102 | + } | ||
103 | + return array($response->json(), null); | ||
104 | + } | ||
105 | + | ||
106 | + private static function createFile($filename, $mime) | ||
107 | + { | ||
108 | + // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax | ||
109 | + // See: https://wiki.php.net/rfc/curl-file-upload | ||
110 | + if (function_exists('curl_file_create')) { | ||
111 | + return curl_file_create($filename, $mime); | ||
112 | + } | ||
113 | + | ||
114 | + // Use the old style if using an older version of PHP | ||
115 | + $value = "@{$filename}"; | ||
116 | + if (!empty($mime)) { | ||
117 | + $value .= ';type=' . $mime; | ||
118 | + } | ||
119 | + | ||
120 | + return $value; | ||
121 | + } | ||
122 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu\Storage; | ||
4 | + | ||
5 | +use Qiniu\Config; | ||
6 | +use Qiniu\Http\Client; | ||
7 | +use Qiniu\Http\Error; | ||
8 | + | ||
9 | +/** | ||
10 | + * 断点续上传类, 该类主要实现了断点续上传中的分块上传, | ||
11 | + * 以及相应地创建块和创建文件过程. | ||
12 | + * | ||
13 | + * @link http://developer.qiniu.com/docs/v6/api/reference/up/mkblk.html | ||
14 | + * @link http://developer.qiniu.com/docs/v6/api/reference/up/mkfile.html | ||
15 | + */ | ||
16 | +final class ResumeUploader | ||
17 | +{ | ||
18 | + private $upToken; | ||
19 | + private $key; | ||
20 | + private $inputStream; | ||
21 | + private $size; | ||
22 | + private $params; | ||
23 | + private $mime; | ||
24 | + private $contexts; | ||
25 | + private $host; | ||
26 | + private $currentUrl; | ||
27 | + private $config; | ||
28 | + | ||
29 | + /** | ||
30 | + * 上传二进制流到七牛 | ||
31 | + * | ||
32 | + * @param string $upToken 上传凭证 | ||
33 | + * @param string $key 上传文件名 | ||
34 | + * @param resource $inputStream 上传二进制流 | ||
35 | + * @param int $size 上传流的大小 | ||
36 | + * @param array $params 自定义变量 | ||
37 | + * @param string $mime 上传数据的mimeType | ||
38 | + * | ||
39 | + * @link http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar | ||
40 | + */ | ||
41 | + public function __construct( | ||
42 | + $upToken, | ||
43 | + $key, | ||
44 | + $inputStream, | ||
45 | + $size, | ||
46 | + $params = null, | ||
47 | + $mime = '', | ||
48 | + $config = null | ||
49 | + ) { | ||
50 | + | ||
51 | + $this->upToken = $upToken; | ||
52 | + $this->key = $key; | ||
53 | + $this->inputStream = $inputStream; | ||
54 | + $this->size = $size; | ||
55 | + $this->params = $params; | ||
56 | + $this->mime = $mime ? $mime : 'application/octet-stream'; | ||
57 | + $this->contexts = array(); | ||
58 | + $this->config = $config ? $config : new Config(); | ||
59 | + | ||
60 | + list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); | ||
61 | + if ($err != null) { | ||
62 | + return array(null, $err); | ||
63 | + } | ||
64 | + | ||
65 | + $upHost = $this->config->getUpHost($accessKey, $bucket); | ||
66 | + if ($err != null) { | ||
67 | + throw new \Exception($err->message(), 1); | ||
68 | + } | ||
69 | + $this->host = $upHost; | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * 上传操作 | ||
74 | + */ | ||
75 | + public function upload($fname) | ||
76 | + { | ||
77 | + $uploaded = 0; | ||
78 | + while ($uploaded < $this->size) { | ||
79 | + $blockSize = $this->blockSize($uploaded); | ||
80 | + $data = fread($this->inputStream, $blockSize); | ||
81 | + if ($data === false) { | ||
82 | + throw new \Exception("file read failed", 1); | ||
83 | + } | ||
84 | + $crc = \Qiniu\crc32_data($data); | ||
85 | + $response = $this->makeBlock($data, $blockSize); | ||
86 | + $ret = null; | ||
87 | + if ($response->ok() && $response->json() != null) { | ||
88 | + $ret = $response->json(); | ||
89 | + } | ||
90 | + if ($response->statusCode < 0) { | ||
91 | + list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($this->upToken); | ||
92 | + if ($err != null) { | ||
93 | + return array(null, $err); | ||
94 | + } | ||
95 | + | ||
96 | + $upHostBackup = $this->config->getUpBackupHost($accessKey, $bucket); | ||
97 | + $this->host = $upHostBackup; | ||
98 | + } | ||
99 | + if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) { | ||
100 | + $response = $this->makeBlock($data, $blockSize); | ||
101 | + $ret = $response->json(); | ||
102 | + } | ||
103 | + | ||
104 | + if (!$response->ok() || !isset($ret['crc32']) || $crc != $ret['crc32']) { | ||
105 | + return array(null, new Error($this->currentUrl, $response)); | ||
106 | + } | ||
107 | + array_push($this->contexts, $ret['ctx']); | ||
108 | + $uploaded += $blockSize; | ||
109 | + } | ||
110 | + return $this->makeFile($fname); | ||
111 | + } | ||
112 | + | ||
113 | + public function uploadChunk($index, $file, $size) | ||
114 | + { | ||
115 | + $blockSize = $this->size; | ||
116 | + $data = fread($this->inputStream, $size); | ||
117 | + if ($data === false) { | ||
118 | + throw new \Exception("file read failed", 1); | ||
119 | + } | ||
120 | + $crc = \Qiniu\crc32_data($data); | ||
121 | + $response = $this->makeBlock($data, $blockSize); | ||
122 | + $ret = null; | ||
123 | + if ($response->ok() && $response->json() != null) { | ||
124 | + $ret = $response->json(); | ||
125 | + } | ||
126 | + if ($response->statusCode < 0) { | ||
127 | + list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($this->upToken); | ||
128 | + if ($err != null) { | ||
129 | + return array(null, $err); | ||
130 | + } | ||
131 | + | ||
132 | + $upHostBackup = $this->config->getUpBackupHost($accessKey, $bucket); | ||
133 | + $this->host = $upHostBackup; | ||
134 | + } | ||
135 | + if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) { | ||
136 | + $response = $this->makeBlock($data, $blockSize); | ||
137 | + $ret = $response->json(); | ||
138 | + } | ||
139 | + | ||
140 | + if (!$response->ok() || !isset($ret['crc32']) || $crc != $ret['crc32']) { | ||
141 | + return array(null, new Error($this->currentUrl, $response)); | ||
142 | + } | ||
143 | + array_push($this->contexts, $ret['ctx']); | ||
144 | + return $ret; | ||
145 | + } | ||
146 | + | ||
147 | + public function setContexts($contexts) | ||
148 | + { | ||
149 | + $this->contexts = is_array($contexts) ? $contexts : explode(',', $contexts); | ||
150 | + return $this; | ||
151 | + } | ||
152 | + | ||
153 | + /** | ||
154 | + * 创建块 | ||
155 | + */ | ||
156 | + private function makeBlock($block, $blockSize) | ||
157 | + { | ||
158 | + $url = $this->host . '/mkblk/' . $blockSize; | ||
159 | + return $this->post($url, $block); | ||
160 | + } | ||
161 | + | ||
162 | + private function fileUrl($fname) | ||
163 | + { | ||
164 | + $url = $this->host . '/mkfile/' . $this->size; | ||
165 | + $url .= '/mimeType/' . \Qiniu\base64_urlSafeEncode($this->mime); | ||
166 | + if ($this->key != null) { | ||
167 | + $url .= '/key/' . \Qiniu\base64_urlSafeEncode($this->key); | ||
168 | + } | ||
169 | + $url .= '/fname/' . \Qiniu\base64_urlSafeEncode($fname); | ||
170 | + if (!empty($this->params)) { | ||
171 | + foreach ($this->params as $key => $value) { | ||
172 | + $val = \Qiniu\base64_urlSafeEncode($value); | ||
173 | + $url .= "/$key/$val"; | ||
174 | + } | ||
175 | + } | ||
176 | + return $url; | ||
177 | + } | ||
178 | + | ||
179 | + /** | ||
180 | + * 创建文件 | ||
181 | + */ | ||
182 | + public function makeFile($fname) | ||
183 | + { | ||
184 | + $url = $this->fileUrl($fname); | ||
185 | + $body = implode(',', $this->contexts); | ||
186 | + $response = $this->post($url, $body); | ||
187 | + if ($response->needRetry()) { | ||
188 | + $response = $this->post($url, $body); | ||
189 | + } | ||
190 | + if (!$response->ok()) { | ||
191 | + return array(null, new Error($this->currentUrl, $response)); | ||
192 | + } | ||
193 | + return array($response->json(), null); | ||
194 | + } | ||
195 | + | ||
196 | + private function post($url, $data) | ||
197 | + { | ||
198 | + $this->currentUrl = $url; | ||
199 | + $headers = array('Authorization' => 'UpToken ' . $this->upToken); | ||
200 | + return Client::post($url, $data, $headers); | ||
201 | + } | ||
202 | + | ||
203 | + private function blockSize($uploaded) | ||
204 | + { | ||
205 | + if ($this->size < $uploaded + Config::BLOCK_SIZE) { | ||
206 | + return $this->size - $uploaded; | ||
207 | + } | ||
208 | + return Config::BLOCK_SIZE; | ||
209 | + } | ||
210 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu\Storage; | ||
4 | + | ||
5 | +use Qiniu\Config; | ||
6 | +use Qiniu\Http\HttpClient; | ||
7 | +use Qiniu\Storage\ResumeUploader; | ||
8 | +use Qiniu\Storage\FormUploader; | ||
9 | + | ||
10 | +/** | ||
11 | + * 主要涉及了资源上传接口的实现 | ||
12 | + * | ||
13 | + * @link http://developer.qiniu.com/docs/v6/api/reference/up/ | ||
14 | + */ | ||
15 | +final class UploadManager | ||
16 | +{ | ||
17 | + private $config; | ||
18 | + | ||
19 | + public function __construct(Config $config = null) | ||
20 | + { | ||
21 | + if ($config === null) { | ||
22 | + $config = new Config(); | ||
23 | + } | ||
24 | + $this->config = $config; | ||
25 | + } | ||
26 | + | ||
27 | + /** | ||
28 | + * 上传二进制流到七牛 | ||
29 | + * | ||
30 | + * @param string $upToken 上传凭证 | ||
31 | + * @param string $key 上传文件名 | ||
32 | + * @param resource $data 上传二进制流 | ||
33 | + * @param array $params 自定义变量,规格参考 http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar | ||
34 | + * @param string $mime 上传数据的mimeType | ||
35 | + * @param bool $checkCrc 是否校验crc32 | ||
36 | + * | ||
37 | + * @return array 包含已上传文件的信息,类似: | ||
38 | + * [ | ||
39 | + * "hash" => "<Hash string>", | ||
40 | + * "key" => "<Key string>" | ||
41 | + * ] | ||
42 | + */ | ||
43 | + public function put($upToken, $key, $data, $params = null, $mime = 'application/octet-stream', $fname = "default_filename") | ||
44 | + { | ||
45 | + $params = self::trimParams($params); | ||
46 | + return FormUploader::put($upToken, $key, $data, $this->config, $params, $mime, $fname); | ||
47 | + } | ||
48 | + | ||
49 | + | ||
50 | + /** | ||
51 | + * 上传文件到七牛 | ||
52 | + * | ||
53 | + * @param string $upToken 上传凭证 | ||
54 | + * @param string $key 上传文件名 | ||
55 | + * @param string $filePath 上传文件的路径 | ||
56 | + * @param array $params 自定义变量,规格参考 http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar | ||
57 | + * @param string $mime 上传数据的mimeType | ||
58 | + * @param bool $checkCrc 是否校验crc32 | ||
59 | + * | ||
60 | + * @return array 包含已上传文件的信息,类似: | ||
61 | + * [ | ||
62 | + * "hash" => "<Hash string>", | ||
63 | + * "key" => "<Key string>" | ||
64 | + * ] | ||
65 | + */ | ||
66 | + public function putFile($upToken, $key, $filePath, $params = null, $mime = 'application/octet-stream', $checkCrc = false) | ||
67 | + { | ||
68 | + $file = fopen($filePath, 'rb'); | ||
69 | + if ($file === false) { | ||
70 | + throw new \Exception("file can not open", 1); | ||
71 | + } | ||
72 | + $params = self::trimParams($params); | ||
73 | + $stat = fstat($file); | ||
74 | + $size = $stat['size']; | ||
75 | + //不满足分片上传条件 | ||
76 | + if ($size <= Config::BLOCK_SIZE) { | ||
77 | + $data = fread($file, $size); | ||
78 | + fclose($file); | ||
79 | + if ($data === false) { | ||
80 | + throw new \Exception("file can not read", 1); | ||
81 | + } | ||
82 | + return FormUploader::put($upToken, $key, $data, $this->config, $params, $mime, basename($filePath)); | ||
83 | + } else { | ||
84 | + $up = new ResumeUploader($upToken, $key, $file, $size, $params, $mime, $this->config); | ||
85 | + $ret = $up->upload(basename($filePath)); | ||
86 | + fclose($file); | ||
87 | + return $ret; | ||
88 | + } | ||
89 | + } | ||
90 | + | ||
91 | + public static function trimParams($params) | ||
92 | + { | ||
93 | + if ($params === null) { | ||
94 | + return null; | ||
95 | + } | ||
96 | + $ret = array(); | ||
97 | + foreach ($params as $k => $v) { | ||
98 | + $pos1 = strpos($k, 'x:'); | ||
99 | + $pos2 = strpos($k, 'x-qn-meta-'); | ||
100 | + if (($pos1 === 0 || $pos2 === 0) && !empty($v)) { | ||
101 | + $ret[$k] = $v; | ||
102 | + } | ||
103 | + } | ||
104 | + return $ret; | ||
105 | + } | ||
106 | +} |
addons/qiniu/library/Qiniu/Zone.php
0 → 100644
1 | +<?php | ||
2 | +namespace Qiniu; | ||
3 | + | ||
4 | +use Qiniu\Region; | ||
5 | + | ||
6 | +class Zone extends Region | ||
7 | +{ | ||
8 | + public static function zonez0() | ||
9 | + { | ||
10 | + return parent::regionHuadong(); | ||
11 | + } | ||
12 | + | ||
13 | + public static function zonez1() | ||
14 | + { | ||
15 | + return parent::regionHuabei(); | ||
16 | + } | ||
17 | + | ||
18 | + public static function zonez2() | ||
19 | + { | ||
20 | + return parent::regionHuanan(); | ||
21 | + } | ||
22 | + | ||
23 | + public static function zoneAs0() | ||
24 | + { | ||
25 | + return parent::regionSingapore(); | ||
26 | + } | ||
27 | + | ||
28 | + public static function zoneNa0() | ||
29 | + { | ||
30 | + return parent::regionNorthAmerica(); | ||
31 | + } | ||
32 | + | ||
33 | + public static function qvmZonez0() | ||
34 | + { | ||
35 | + return parent::qvmRegionHuadong(); | ||
36 | + } | ||
37 | + | ||
38 | + public static function qvmZonez1() | ||
39 | + { | ||
40 | + return parent::qvmRegionHuabei(); | ||
41 | + } | ||
42 | + | ||
43 | + public static function queryZone($ak, $bucket) | ||
44 | + { | ||
45 | + return parent::queryRegion($ak, $bucket); | ||
46 | + } | ||
47 | +} |
addons/qiniu/library/Qiniu/functions.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace Qiniu; | ||
4 | + | ||
5 | +use Qiniu\Config; | ||
6 | + | ||
7 | +if (!defined('QINIU_FUNCTIONS_VERSION')) { | ||
8 | + define('QINIU_FUNCTIONS_VERSION', Config::SDK_VER); | ||
9 | + | ||
10 | + /** | ||
11 | + * 计算文件的crc32检验码: | ||
12 | + * | ||
13 | + * @param $file string 待计算校验码的文件路径 | ||
14 | + * | ||
15 | + * @return string 文件内容的crc32校验码 | ||
16 | + */ | ||
17 | + function crc32_file($file) | ||
18 | + { | ||
19 | + $hash = hash_file('crc32b', $file); | ||
20 | + $array = unpack('N', pack('H*', $hash)); | ||
21 | + return sprintf('%u', $array[1]); | ||
22 | + } | ||
23 | + | ||
24 | + /** | ||
25 | + * 计算输入流的crc32检验码 | ||
26 | + * | ||
27 | + * @param $data 待计算校验码的字符串 | ||
28 | + * | ||
29 | + * @return string 输入字符串的crc32校验码 | ||
30 | + */ | ||
31 | + function crc32_data($data) | ||
32 | + { | ||
33 | + $hash = hash('crc32b', $data); | ||
34 | + $array = unpack('N', pack('H*', $hash)); | ||
35 | + return sprintf('%u', $array[1]); | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * 对提供的数据进行urlsafe的base64编码。 | ||
40 | + * | ||
41 | + * @param string $data 待编码的数据,一般为字符串 | ||
42 | + * | ||
43 | + * @return string 编码后的字符串 | ||
44 | + * @link http://developer.qiniu.com/docs/v6/api/overview/appendix.html#urlsafe-base64 | ||
45 | + */ | ||
46 | + function base64_urlSafeEncode($data) | ||
47 | + { | ||
48 | + $find = array('+', '/'); | ||
49 | + $replace = array('-', '_'); | ||
50 | + return str_replace($find, $replace, base64_encode($data)); | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * 对提供的urlsafe的base64编码的数据进行解码 | ||
55 | + * | ||
56 | + * @param string $str 待解码的数据,一般为字符串 | ||
57 | + * | ||
58 | + * @return string 解码后的字符串 | ||
59 | + */ | ||
60 | + function base64_urlSafeDecode($str) | ||
61 | + { | ||
62 | + $find = array('-', '_'); | ||
63 | + $replace = array('+', '/'); | ||
64 | + return base64_decode(str_replace($find, $replace, $str)); | ||
65 | + } | ||
66 | + | ||
67 | + /** | ||
68 | + * Wrapper for JSON decode that implements error detection with helpful | ||
69 | + * error messages. | ||
70 | + * | ||
71 | + * @param string $json JSON data to parse | ||
72 | + * @param bool $assoc When true, returned objects will be converted | ||
73 | + * into associative arrays. | ||
74 | + * @param int $depth User specified recursion depth. | ||
75 | + * | ||
76 | + * @return mixed | ||
77 | + * @throws \InvalidArgumentException if the JSON cannot be parsed. | ||
78 | + * @link http://www.php.net/manual/en/function.json-decode.php | ||
79 | + */ | ||
80 | + function json_decode($json, $assoc = false, $depth = 512) | ||
81 | + { | ||
82 | + static $jsonErrors = array( | ||
83 | + JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded', | ||
84 | + JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch', | ||
85 | + JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found', | ||
86 | + JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON', | ||
87 | + JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded' | ||
88 | + ); | ||
89 | + | ||
90 | + if (empty($json)) { | ||
91 | + return null; | ||
92 | + } | ||
93 | + $data = \json_decode($json, $assoc, $depth); | ||
94 | + | ||
95 | + if (JSON_ERROR_NONE !== json_last_error()) { | ||
96 | + $last = json_last_error(); | ||
97 | + throw new \InvalidArgumentException( | ||
98 | + 'Unable to parse JSON data: ' | ||
99 | + . (isset($jsonErrors[$last]) | ||
100 | + ? $jsonErrors[$last] | ||
101 | + : 'Unknown error') | ||
102 | + ); | ||
103 | + } | ||
104 | + | ||
105 | + return $data; | ||
106 | + } | ||
107 | + | ||
108 | + /** | ||
109 | + * 计算七牛API中的数据格式 | ||
110 | + * | ||
111 | + * @param $bucket 待操作的空间名 | ||
112 | + * @param $key 待操作的文件名 | ||
113 | + * | ||
114 | + * @return string 符合七牛API规格的数据格式 | ||
115 | + * @link http://developer.qiniu.com/docs/v6/api/reference/data-formats.html | ||
116 | + */ | ||
117 | + function entry($bucket, $key) | ||
118 | + { | ||
119 | + $en = $bucket; | ||
120 | + if (!empty($key)) { | ||
121 | + $en = $bucket . ':' . $key; | ||
122 | + } | ||
123 | + return base64_urlSafeEncode($en); | ||
124 | + } | ||
125 | + | ||
126 | + /** | ||
127 | + * array 辅助方法,无值时不set | ||
128 | + * | ||
129 | + * @param $array 待操作array | ||
130 | + * @param $key key | ||
131 | + * @param $value value 为null时 不设置 | ||
132 | + * | ||
133 | + * @return array 原来的array,便于连续操作 | ||
134 | + */ | ||
135 | + function setWithoutEmpty(&$array, $key, $value) | ||
136 | + { | ||
137 | + if (!empty($value)) { | ||
138 | + $array[$key] = $value; | ||
139 | + } | ||
140 | + return $array; | ||
141 | + } | ||
142 | + | ||
143 | + /** | ||
144 | + * 缩略图链接拼接 | ||
145 | + * | ||
146 | + * @param string $url 图片链接 | ||
147 | + * @param int $mode 缩略模式 | ||
148 | + * @param int $width 宽度 | ||
149 | + * @param int $height 长度 | ||
150 | + * @param string $format 输出类型 | ||
151 | + * @param int $quality 图片质量 | ||
152 | + * @param int $interlace 是否支持渐进显示 | ||
153 | + * @param int $ignoreError 忽略结果 | ||
154 | + * @return string | ||
155 | + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/imageview2.html | ||
156 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
157 | + */ | ||
158 | + function thumbnail( | ||
159 | + $url, | ||
160 | + $mode, | ||
161 | + $width, | ||
162 | + $height, | ||
163 | + $format = null, | ||
164 | + $quality = null, | ||
165 | + $interlace = null, | ||
166 | + $ignoreError = 1 | ||
167 | + ) { | ||
168 | + | ||
169 | + static $imageUrlBuilder = null; | ||
170 | + if (is_null($imageUrlBuilder)) { | ||
171 | + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; | ||
172 | + } | ||
173 | + | ||
174 | + return call_user_func_array(array($imageUrlBuilder, 'thumbnail'), func_get_args()); | ||
175 | + } | ||
176 | + | ||
177 | + /** | ||
178 | + * 图片水印 | ||
179 | + * | ||
180 | + * @param string $url 图片链接 | ||
181 | + * @param string $image 水印图片链接 | ||
182 | + * @param numeric $dissolve 透明度 | ||
183 | + * @param string $gravity 水印位置 | ||
184 | + * @param numeric $dx 横轴边距 | ||
185 | + * @param numeric $dy 纵轴边距 | ||
186 | + * @param numeric $watermarkScale 自适应原图的短边比例 | ||
187 | + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html | ||
188 | + * @return string | ||
189 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
190 | + */ | ||
191 | + function waterImg( | ||
192 | + $url, | ||
193 | + $image, | ||
194 | + $dissolve = 100, | ||
195 | + $gravity = 'SouthEast', | ||
196 | + $dx = null, | ||
197 | + $dy = null, | ||
198 | + $watermarkScale = null | ||
199 | + ) { | ||
200 | + | ||
201 | + static $imageUrlBuilder = null; | ||
202 | + if (is_null($imageUrlBuilder)) { | ||
203 | + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; | ||
204 | + } | ||
205 | + | ||
206 | + return call_user_func_array(array($imageUrlBuilder, 'waterImg'), func_get_args()); | ||
207 | + } | ||
208 | + | ||
209 | + /** | ||
210 | + * 文字水印 | ||
211 | + * | ||
212 | + * @param string $url 图片链接 | ||
213 | + * @param string $text 文字 | ||
214 | + * @param string $font 文字字体 | ||
215 | + * @param string $fontSize 文字字号 | ||
216 | + * @param string $fontColor 文字颜色 | ||
217 | + * @param numeric $dissolve 透明度 | ||
218 | + * @param string $gravity 水印位置 | ||
219 | + * @param numeric $dx 横轴边距 | ||
220 | + * @param numeric $dy 纵轴边距 | ||
221 | + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark | ||
222 | + * @return string | ||
223 | + * @author Sherlock Ren <sherlock_ren@icloud.com> | ||
224 | + */ | ||
225 | + function waterText( | ||
226 | + $url, | ||
227 | + $text, | ||
228 | + $font = '黑体', | ||
229 | + $fontSize = 0, | ||
230 | + $fontColor = null, | ||
231 | + $dissolve = 100, | ||
232 | + $gravity = 'SouthEast', | ||
233 | + $dx = null, | ||
234 | + $dy = null | ||
235 | + ) { | ||
236 | + | ||
237 | + static $imageUrlBuilder = null; | ||
238 | + if (is_null($imageUrlBuilder)) { | ||
239 | + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; | ||
240 | + } | ||
241 | + | ||
242 | + return call_user_func_array(array($imageUrlBuilder, 'waterText'), func_get_args()); | ||
243 | + } | ||
244 | + | ||
245 | + /** | ||
246 | + * 从uptoken解析accessKey和bucket | ||
247 | + * | ||
248 | + * @param $upToken | ||
249 | + * @return array(ak,bucket,err=null) | ||
250 | + */ | ||
251 | + function explodeUpToken($upToken) | ||
252 | + { | ||
253 | + $items = explode(':', $upToken); | ||
254 | + if (count($items) != 3) { | ||
255 | + return array(null, null, "invalid uptoken"); | ||
256 | + } | ||
257 | + $accessKey = $items[0]; | ||
258 | + $putPolicy = json_decode(base64_urlSafeDecode($items[2])); | ||
259 | + $scope = $putPolicy->scope; | ||
260 | + $scopeItems = explode(':', $scope); | ||
261 | + $bucket = $scopeItems[0]; | ||
262 | + return array($accessKey, $bucket, null); | ||
263 | + } | ||
264 | +} |
@@ -11,7 +11,10 @@ date_default_timezone_set('PRC'); | @@ -11,7 +11,10 @@ date_default_timezone_set('PRC'); | ||
11 | 11 | ||
12 | use app\api\controller\getui\JgPush; | 12 | use app\api\controller\getui\JgPush; |
13 | use app\common\controller\Api; | 13 | use app\common\controller\Api; |
14 | +use app\common\exception\UploadException; | ||
15 | +use app\common\library\Upload; | ||
14 | use fast\Tree; | 16 | use fast\Tree; |
17 | +use think\Config; | ||
15 | use think\Db; | 18 | use think\Db; |
16 | use think\Request; | 19 | use think\Request; |
17 | use Qiniu\Auth as QAuth; | 20 | use Qiniu\Auth as QAuth; |
@@ -93,5 +96,70 @@ class Task extends Api | @@ -93,5 +96,70 @@ class Task extends Api | ||
93 | } | 96 | } |
94 | } | 97 | } |
95 | } | 98 | } |
99 | + /** | ||
100 | + * 上传文件 | ||
101 | + */ | ||
102 | + public function upload() | ||
103 | + { | ||
104 | + Config::set('default_return_type', 'json'); | ||
105 | + | ||
106 | + //必须还原upload配置,否则分片及cdnurl函数计算错误 | ||
107 | + Config::load(APP_PATH . 'extra/upload.php', 'upload'); | ||
108 | + | ||
109 | + $chunkid = $this->request->post("chunkid"); | ||
110 | + if ($chunkid) { | ||
111 | + if (!Config::get('upload.chunking')) { | ||
112 | + $this->error(__('Chunk file disabled')); | ||
113 | + } | ||
114 | + $action = $this->request->post("action"); | ||
115 | + $chunkindex = $this->request->post("chunkindex/d"); | ||
116 | + $chunkcount = $this->request->post("chunkcount/d"); | ||
117 | + $filename = $this->request->post("filename"); | ||
118 | + $method = $this->request->method(true); | ||
119 | + if ($action == 'merge') { | ||
120 | + $attachment = null; | ||
121 | + //合并分片文件 | ||
122 | + try { | ||
123 | + $upload = new Upload(); | ||
124 | + $attachment = $upload->merge($chunkid, $chunkcount, $filename); | ||
125 | + } catch (UploadException $e) { | ||
126 | + $this->error($e->getMessage()); | ||
127 | + } | ||
128 | + $this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]); | ||
129 | + } elseif ($method == 'clean') { | ||
130 | + //删除冗余的分片文件 | ||
131 | + try { | ||
132 | + $upload = new Upload(); | ||
133 | + $upload->clean($chunkid); | ||
134 | + } catch (UploadException $e) { | ||
135 | + $this->error($e->getMessage()); | ||
136 | + } | ||
137 | + $this->success(); | ||
138 | + } else { | ||
139 | + //上传分片文件 | ||
140 | + //默认普通上传文件 | ||
141 | + $file = $this->request->file('file'); | ||
142 | + try { | ||
143 | + $upload = new Upload($file); | ||
144 | + $upload->chunk($chunkid, $chunkindex, $chunkcount); | ||
145 | + } catch (UploadException $e) { | ||
146 | + $this->error($e->getMessage()); | ||
147 | + } | ||
148 | + $this->success(); | ||
149 | + } | ||
150 | + } else { | ||
151 | + $attachment = null; | ||
152 | + //默认普通上传文件 | ||
153 | + $file = $this->request->file('file'); | ||
154 | + try { | ||
155 | + $upload = new Upload($file); | ||
156 | + $attachment = $upload->upload(); | ||
157 | + } catch (UploadException $e) { | ||
158 | + $this->error($e->getMessage()); | ||
159 | + } | ||
160 | + | ||
161 | + $this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]); | ||
162 | + } | ||
163 | + } | ||
96 | 164 | ||
97 | } | 165 | } |
@@ -209,13 +209,11 @@ class Login extends Base | @@ -209,13 +209,11 @@ class Login extends Base | ||
209 | */ | 209 | */ |
210 | public function getuserdata(){ | 210 | public function getuserdata(){ |
211 | $username=$this->request->param("username"); | 211 | $username=$this->request->param("username"); |
212 | - $avatar=$this->request->param("avatar"); | ||
213 | $user_id=$this->auth->id; | 212 | $user_id=$this->auth->id; |
214 | Db::name("user") | 213 | Db::name("user") |
215 | ->where("id", $user_id) | 214 | ->where("id", $user_id) |
216 | ->update([ | 215 | ->update([ |
217 | "username" => $username, | 216 | "username" => $username, |
218 | - "avatar" => $avatar, | ||
219 | "nickname" => $username, | 217 | "nickname" => $username, |
220 | ]); | 218 | ]); |
221 | $this->success("请求成功"); | 219 | $this->success("请求成功"); |
-
请 注册 或 登录 后发表评论