-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathupyun.class.php
More file actions
273 lines (255 loc) · 8.32 KB
/
Copy pathupyun.class.php
File metadata and controls
273 lines (255 loc) · 8.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
<?php
class UpYun{
public function version(){return '1.0.1';}
private $bucketname;
private $username;
private $password;
private $api_domain = 'v0.api.upyun.com';
private $tmp_infos;
public $timeout = 300;
public $debug = false;
private $content_md5 = null;
private $file_secret = null;
/**
* 初始化 UpYun 存储接口
* @param $bucketname 空间名称
* @param $username 操作员名称
* @param $password 密码
* return UpYun object
*/
public function __construct($bucketname, $username, $password) {
$this->bucketname = $bucketname;
$this->username = $username;
$this->password = md5($password);
}
/**
* 切换 API 接口的域名
* @param $domain {默然 v0.api.upyun.com 自动识别, v1.api.upyun.com 电信, v2.api.upyun.com 联通, v3.api.upyun.com 移动}
* return null;
*/
public function setApiDomain($domain){
$this->api_domain = $domain;
}
/**
* 设置连接超时时间
* @param $time 秒
* return null;
*/
public function setTimeout($time){
$this->timeout = $time;
}
/**
* 设置待上传文件的 Content-MD5 值(如又拍云服务端收到的文件MD5值与用户设置的不一致,将回报 406 Not Acceptable 错误)
* @param $str (文件 MD5 校验码)
* return null;
*/
public function setContentMD5($str){
$this->content_md5 = $str;
}
/**
* 连接签名方法
* @param $method 请求方式 {GET, POST, PUT, DELETE}
* return 签名字符串
*/
private function sign($method, $uri, $date, $length){
$sign = "{$method}&{$uri}&{$date}&{$length}&{$this->password}";
return 'UpYun '.$this->username.':'.md5($sign);
}
/**
* 连接处理逻辑
* @param $method 请求方式 {GET, POST, PUT, DELETE}
* @param $uri 请求地址
* @param $datas 如果是 POST 上传文件,传递文件内容 或 文件IO数据流
* @param $output_file 如果是 GET 下载文件,可传递文件IO数据流
* return 请求返回字符串,失败返回 null (打开 debug 状态下遇到错误将中止程序执行)
*/
private function HttpAction($method, $uri, $datas, $output_file = null){
unset($this->tmp_infos);
$uri = "/{$this->bucketname}{$uri}";
$process = curl_init("http://{$this->api_domain}{$uri}");
$headers = array('Expect:');
if($datas == 'folder:true'){
$headers[] = $datas;
$datas = null;
}
$length = @strlen($datas);
if($method == 'PUT' || $method == 'POST'){
if($this->auto_mkdir == true){
$headers[] = 'mkdir: true';
}
$method = 'POST';
curl_setopt($process, CURLOPT_POST, 1);
if($datas){
$headers[] = 'Content-Type: ';
if($this->content_md5 != null)$headers[] = 'Content-MD5: '.$this->content_md5;
$this->content_md5 = null;
if($this->file_secret != null)$headers[] = 'Content-Secret: '.$this->file_secret;
$this->file_secret = null;
if(is_resource($datas)){
fseek($datas, 0, SEEK_END);
$length = ftell($datas);
fseek($datas, 0);
$headers[] = 'Content-Length: '.$length;
curl_setopt($process, CURLOPT_INFILE, $datas);
curl_setopt($process, CURLOPT_INFILESIZE, $length);
}
else curl_setopt($process, CURLOPT_POSTFIELDS, $datas);
}else curl_setopt($process, CURLOPT_POSTFIELDS, "");
}
curl_setopt($process, CURLOPT_CUSTOMREQUEST, $method);
$date = gmdate('D, d M Y H:i:s \G\M\T');
$headers[] = "Date: {$date}";
$headers[] = 'Authorization: '.$this->sign($method, $uri, $date, $length);
curl_setopt($process, CURLOPT_HTTPHEADER, $headers);
curl_setopt($process, CURLOPT_HEADER, 1); /// 获取 header
curl_setopt($process, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($process, CURLOPT_FOLLOWLOCATION, 1);
if($method == 'HEAD')curl_setopt($process, CURLOPT_NOBODY, true);
if(is_resource($output_file)){
curl_setopt($process, CURLOPT_HEADER, 0);
curl_setopt($process, CURLOPT_FILE, $output_file);
}
$r = curl_exec($process);
$rc = curl_getinfo($process, CURLINFO_HTTP_CODE);
$r_offset = curl_getinfo($process, CURLINFO_HEADER_SIZE);
if($rc != 200 && $method != 'HEAD'){
if($this->debug)
throw new Exception($r, $rc);
return null;
}
curl_close($process);
$r_headers = explode("\n", substr($r, 0 , $r_offset)."]");
foreach($r_headers as $hl){
$hl = trim($hl);
if(substr($hl, 0, 7) == 'x-upyun'){
if(!isset($this->tmp_infos))$this->tmp_infos = array();
list($k, $v) = explode(':', $hl);
if(in_array(substr($k,8,5), array('width','heigh','frame')))
$this->tmp_infos[trim($k)] = intval($v);
else
$this->tmp_infos[trim($k)] = trim($v);
}
}
if($rc != 200 && $method == 'HEAD')return null;
return substr($r, $r_offset, strlen($r));
}
/**
* 获取总体空间的占用信息
* return 空间占用量,失败返回 null
*/
public function getBucketUsage(){
return $this->getFolderUsage('/');
}
/**
* 获取某个子目录的占用信息
* @param $path 目标路径
* return 空间占用量,失败返回 null
*/
public function getFolderUsage($path){
$r = $this->HttpAction('GET', "{$path}?usage", null);
if($r == '')return null;
return floatval($r);
}
/**
* 设置待上传文件的 访问密钥(注意:仅支持图片空!,设置密钥后,无法根据原文件URL直接访问,需带 URL 后面加上 (缩略图间隔标志符+密钥) 进行访问)
* 如缩略图间隔标志符为 ! ,密钥为 bac,上传文件路径为 /folder/test.jpg ,那么该图片的对外访问地址为: http://空间域名/folder/test.jpg!bac
* @param $str (文件 MD5 校验码)
* return null;
*/
public function setFileSecret($str){
$this->file_secret = $str;
}
/**
* 上传文件
* @param $file 文件路径(包含文件名)
* @param $datas 文件内容 或 文件IO数据流
* @param $auto_mkdir=false 是否自动创建父级目录
* return true or false
*/
public function writeFile($file, $datas, $auto_mkdir=false){
$this->auto_mkdir = $auto_mkdir;
$r = $this->HttpAction('PUT', $file, $datas);
return !is_null($r);
}
/**
* 获取上传文件后的信息(仅图片空间有返回数据)
* @param $key 信息字段名(x-upyun-width、x-upyun-height、x-upyun-frames、x-upyun-file-type)
* return value or NULL
*/
public function getWritedFileInfo($key){
if(!isset($this->tmp_infos))return NULL;
return $this->tmp_infos[$key];
}
/**
* 读取文件
* @param $file 文件路径(包含文件名)
* @param $output_file 可传递文件IO数据流(默认为 null,结果返回文件内容,如设置文件数据流,将返回 true or false)
* return 文件内容 或 null
*/
public function readFile($file, $output_file = null){
return $this->HttpAction('GET', $file, null, $output_file);
}
/**
* 获取文件信息
* @param $file 文件路径(包含文件名)
* return array('type'=> file | folder, 'size'=> file size, 'date'=> unix time) 或 null
*/
public function getFileInfo($file){
$r = $this->HttpAction('HEAD', $file, null);
if(is_null($r))return null;
return array('type'=> $this->tmp_infos['x-upyun-file-type'], 'size'=> @intval($this->tmp_infos['x-upyun-file-size']), 'date'=> @intval($this->tmp_infos['x-upyun-file-date']));
}
/**
* 读取目录列表
* @param $path 目录路径
* return array 数组 或 null
*/
public function readDir($path){
$r = $this->HttpAction('GET', $path, null);
if(is_null($r))return null;
$rs = explode("\n", $r);
$returns = array();
foreach($rs as $r){
$r = trim($r);
$l = new stdclass;
@list($l->name, $l->type, $l->size, $l->time) = explode("\t", $r);
if(!empty($l->time)){
$l->type = ($l->type == 'N' ? 'file':'folder');
$l->size = intval($l->size);
$l->time = intval($l->time);
$returns[] = $l;
}
}
return $returns;
}
/**
* 删除文件
* @param $file 文件路径(包含文件名)
* return true or false
*/
public function deleteFile($file){
$r = $this->HttpAction('DELETE', $file, null);
return !is_null($r);
}
/**
* 创建目录
* @param $path 目录路径
* @param $auto_mkdir=false 是否自动创建父级目录
* return true or false
*/
public function mkDir($path, $auto_mkdir=false){
$this->auto_mkdir = $auto_mkdir;
$r = $this->HttpAction('PUT', $path, 'folder:true');
return !is_null($r);
}
/**
* 删除目录
* @param $path 目录路径
* return true or false
*/
public function rmDir($dir){
$r = $this->HttpAction('DELETE', $dir, null);
return !is_null($r);
}
}