1
|
|
|
<?php |
2
|
|
|
namespace Qiniu; |
3
|
|
|
|
4
|
|
|
use Qiniu\Http\Header; |
5
|
|
|
use Qiniu\Zone; |
6
|
|
|
|
7
|
|
|
final class Auth |
8
|
|
|
{ |
9
|
|
|
private $accessKey; |
10
|
|
|
private $secretKey; |
11
|
|
|
|
12
|
|
|
public function __construct($accessKey, $secretKey) |
13
|
|
|
{ |
14
|
|
|
$this->accessKey = $accessKey; |
15
|
|
|
$this->secretKey = $secretKey; |
16
|
|
|
} |
17
|
6 |
|
|
18
|
|
|
public function getAccessKey() |
19
|
6 |
|
{ |
20
|
|
|
return $this->accessKey; |
21
|
|
|
} |
22
|
93 |
|
|
23
|
|
|
public function sign($data) |
24
|
93 |
|
{ |
25
|
93 |
|
$hmac = hash_hmac('sha1', $data, $this->secretKey, true); |
26
|
|
|
return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac); |
27
|
|
|
} |
28
|
24 |
|
|
29
|
|
|
public function signWithData($data) |
30
|
24 |
|
{ |
31
|
24 |
|
$encodedData = \Qiniu\base64_urlSafeEncode($data); |
32
|
|
|
return $this->sign($encodedData) . ':' . $encodedData; |
33
|
|
|
} |
34
|
54 |
|
|
35
|
|
|
public function signRequest($urlString, $body, $contentType = null) |
36
|
54 |
|
{ |
37
|
54 |
|
$url = parse_url($urlString); |
38
|
54 |
|
$data = ''; |
39
|
51 |
|
if (array_key_exists('path', $url)) { |
40
|
51 |
|
$data = $url['path']; |
41
|
54 |
|
} |
42
|
9 |
|
if (array_key_exists('query', $url)) { |
43
|
9 |
|
$data .= '?' . $url['query']; |
44
|
54 |
|
} |
45
|
|
|
$data .= "\n"; |
46
|
54 |
|
|
47
|
24 |
|
if ($body !== null && $contentType === 'application/x-www-form-urlencoded') { |
48
|
24 |
|
$data .= $body; |
49
|
54 |
|
} |
50
|
|
|
return $this->sign($data); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @param string $urlString |
55
|
|
|
* @param string $method |
56
|
|
|
* @param string $body |
57
|
|
|
* @param null|Header $headers |
58
|
12 |
|
*/ |
59
|
|
|
public function signQiniuAuthorization($urlString, $method = "GET", $body = "", $headers = null) |
60
|
12 |
|
{ |
61
|
|
|
$url = parse_url($urlString); |
62
|
12 |
|
if (!$url) { |
|
|
|
|
63
|
12 |
|
return array(null, new \Exception("parse_url error")); |
64
|
9 |
|
} |
65
|
9 |
|
|
66
|
3 |
|
// append method, path and query |
67
|
|
|
if ($method === "") { |
68
|
12 |
|
$data = "GET "; |
69
|
|
|
} else { |
70
|
12 |
|
$data = $method . " "; |
71
|
12 |
|
} |
72
|
|
|
if (isset($url["path"])) { |
73
|
|
|
$data .= $url["path"]; |
74
|
21 |
|
} |
75
|
|
|
if (isset($url["query"])) { |
76
|
21 |
|
$data .= "?" . $url["query"]; |
77
|
21 |
|
} |
78
|
21 |
|
|
79
|
15 |
|
// append Host |
80
|
15 |
|
$data .= "\n"; |
81
|
|
|
$data .= "Host: "; |
82
|
21 |
|
if (isset($url["host"])) { |
83
|
21 |
|
$data .= $url["host"]; |
84
|
21 |
|
} |
85
|
|
|
if (isset($url["port"]) && $url["port"] > 0) { |
86
|
21 |
|
$data .= ":" . $url["port"]; |
87
|
21 |
|
} |
88
|
|
|
|
89
|
|
|
// try append content type |
90
|
|
|
if ($headers != null && isset($headers["Content-Type"])) { |
91
|
|
|
// append content type |
92
|
|
|
$data .= "\n"; |
93
|
|
|
$data .= "Content-Type: " . $headers["Content-Type"]; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
// try append xQiniuHeaders |
97
|
|
|
if ($headers != null) { |
98
|
|
|
$headerLines = array(); |
99
|
|
|
$keyPrefix = "X-Qiniu-"; |
100
|
|
|
foreach ($headers as $k => $v) { |
101
|
|
|
if (strlen($k) > strlen($keyPrefix) && strpos($k, $keyPrefix) === 0) { |
102
|
|
|
array_push( |
103
|
|
|
$headerLines, |
104
|
|
|
$k . ": " . $v |
105
|
|
|
); |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
if (count($headerLines) > 0) { |
109
|
|
|
$data .= "\n"; |
110
|
|
|
sort($headerLines); |
111
|
|
|
$data .= implode("\n", $headerLines); |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
// append body |
116
|
|
|
$data .= "\n\n"; |
117
|
|
|
if (count($body) > 0 |
|
|
|
|
118
|
|
|
&& isset($headers["Content-Type"]) |
119
|
|
|
&& $headers["Content-Type"] != "application/octet-stream" |
120
|
|
|
) { |
121
|
|
|
$data .= $body; |
122
|
21 |
|
} |
123
|
|
|
|
124
|
21 |
|
return array($this->sign(utf8_encode($data)), null); |
125
|
18 |
|
} |
126
|
|
|
|
127
|
3 |
|
public function verifyCallback($contentType, $originAuthorization, $url, $body) |
128
|
3 |
|
{ |
129
|
3 |
|
$authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); |
130
|
3 |
|
return $originAuthorization === $authorization; |
131
|
3 |
|
} |
132
|
3 |
|
|
133
|
|
|
public function privateDownloadUrl($baseUrl, $expires = 3600) |
134
|
|
|
{ |
135
|
51 |
|
$deadline = time() + $expires; |
136
|
|
|
|
137
|
51 |
|
$pos = strpos($baseUrl, '?'); |
138
|
51 |
|
if ($pos !== false) { |
139
|
|
|
$baseUrl .= '&e='; |
140
|
|
|
} else { |
141
|
|
|
$baseUrl .= '?e='; |
142
|
|
|
} |
143
|
|
|
$baseUrl .= $deadline; |
144
|
|
|
|
145
|
|
|
$token = $this->sign($baseUrl); |
146
|
|
|
return "$baseUrl&token=$token"; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true) |
150
|
|
|
{ |
151
|
|
|
$deadline = time() + $expires; |
152
|
|
|
$scope = $bucket; |
153
|
|
|
if ($key !== null) { |
154
|
|
|
$scope .= ':' . $key; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
$args = self::copyPolicy($args, $policy, $strictPolicy); |
158
|
|
|
$args['scope'] = $scope; |
159
|
|
|
$args['deadline'] = $deadline; |
160
|
|
|
|
161
|
|
|
$b = json_encode($args); |
162
|
|
|
return $this->signWithData($b); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
*上传策略,参数规格详见 |
167
|
|
|
*http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html |
168
|
|
|
*/ |
169
|
|
|
private static $policyFields = array( |
170
|
|
|
'callbackUrl', |
171
|
|
|
'callbackBody', |
172
|
|
|
'callbackHost', |
173
|
|
|
'callbackBodyType', |
174
|
|
|
'callbackFetchKey', |
175
|
|
|
|
176
|
|
|
'returnUrl', |
177
|
|
|
'returnBody', |
178
|
|
|
|
179
|
|
|
'endUser', |
180
|
|
|
'saveKey', |
181
|
|
|
'forceSaveKey', |
182
|
|
|
'insertOnly', |
183
|
|
|
|
184
|
|
|
'detectMime', |
185
|
|
|
'mimeLimit', |
186
|
|
|
'fsizeMin', |
187
|
|
|
'fsizeLimit', |
188
|
|
|
|
189
|
|
|
'persistentOps', |
190
|
|
|
'persistentNotifyUrl', |
191
|
|
|
'persistentPipeline', |
192
|
|
|
|
193
|
|
|
'deleteAfterDays', |
194
|
|
|
'fileType', |
195
|
|
|
'isPrefixalScope', |
196
|
|
|
); |
197
|
|
|
|
198
|
|
|
private static function copyPolicy(&$policy, $originPolicy, $strictPolicy) |
199
|
|
|
{ |
200
|
|
|
if ($originPolicy === null) { |
201
|
|
|
return array(); |
202
|
|
|
} |
203
|
|
|
foreach ($originPolicy as $key => $value) { |
204
|
|
|
if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) { |
205
|
|
|
$policy[$key] = $value; |
206
|
|
|
} |
207
|
|
|
} |
208
|
|
|
return $policy; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
public function authorization($url, $body = null, $contentType = null) |
212
|
|
|
{ |
213
|
|
|
$authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); |
214
|
|
|
return array('Authorization' => $authorization); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
public function authorizationV2($url, $method, $body = null, $contentType = null) |
218
|
|
|
{ |
219
|
|
|
$headers = null; |
220
|
|
|
$result = array(); |
221
|
|
|
if ($contentType != null) { |
222
|
|
|
$headers = new Header(array( |
223
|
|
|
'Content-Type' => array($contentType), |
224
|
|
|
)); |
225
|
|
|
$result['Content-Type'] = $contentType; |
226
|
|
|
} |
227
|
|
|
list($sign) = $this->signQiniuAuthorization($url, $method, $body, $headers); |
228
|
|
|
$result['Authorization'] = 'Qiniu ' . $sign; |
229
|
|
|
return $result; |
230
|
|
|
} |
231
|
|
|
} |
232
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.