1 | <?php |
||
2 | |||
3 | namespace Freyo\Flysystem\QcloudCOSv4; |
||
4 | |||
5 | use Carbon\Carbon; |
||
6 | use DateTimeInterface; |
||
7 | use Freyo\Flysystem\QcloudCOSv4\Exceptions\RuntimeException; |
||
8 | use League\Flysystem\Adapter\AbstractAdapter; |
||
9 | use League\Flysystem\AdapterInterface; |
||
10 | use League\Flysystem\Config; |
||
11 | use League\Flysystem\Util; |
||
12 | use QCloud\Cos\Api; |
||
13 | |||
14 | /** |
||
15 | * Class Adapter. |
||
16 | */ |
||
17 | class Adapter extends AbstractAdapter |
||
18 | { |
||
19 | /** |
||
20 | * @var Api |
||
21 | */ |
||
22 | protected $cosApi; |
||
23 | |||
24 | /** |
||
25 | * @var string |
||
26 | */ |
||
27 | protected $bucket; |
||
28 | |||
29 | /** |
||
30 | * @var bool |
||
31 | */ |
||
32 | protected $debug; |
||
33 | |||
34 | /** |
||
35 | * Adapter constructor. |
||
36 | * |
||
37 | * @param Api $cosApi |
||
38 | * @param array $config |
||
39 | */ |
||
40 | public function __construct(Api $cosApi, array $config) |
||
41 | { |
||
42 | $this->cosApi = $cosApi; |
||
43 | |||
44 | $this->bucket = $config['bucket']; |
||
45 | $this->debug = $config['debug']; |
||
46 | |||
47 | $this->setPathPrefix($config['protocol'].'://'.$config['domain'].'/'); |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * @return string |
||
52 | */ |
||
53 | 26 | public function getBucket() |
|
54 | { |
||
55 | 26 | return $this->bucket; |
|
56 | } |
||
57 | |||
58 | /** |
||
59 | * @param string $path |
||
60 | * |
||
61 | * @return string |
||
62 | */ |
||
63 | 3 | public function getUrl($path) |
|
64 | { |
||
65 | 3 | return $this->applyPathPrefix($path); |
|
66 | } |
||
67 | |||
68 | /** |
||
69 | * @param string $path |
||
70 | * @param \DateTimeInterface $expiration |
||
71 | * @param array $options |
||
72 | * |
||
73 | * @return string|bool |
||
74 | */ |
||
75 | 1 | public function getTemporaryUrl($path, DateTimeInterface $expiration, array $options = []) |
|
0 ignored issues
–
show
|
|||
76 | { |
||
77 | 1 | $response = $this->cosApi->getDownloadUrl( |
|
78 | 1 | $this->getBucket(), $path, Carbon::now()->diffInSeconds($expiration) |
|
79 | 1 | ); |
|
80 | |||
81 | 1 | $response = $this->normalizeResponse($response); |
|
82 | |||
83 | 1 | if (false !== $response) { |
|
84 | 1 | $url = parse_url($response['access_url']); |
|
85 | |||
86 | 1 | return $this->getUrl($url['path']).'?'.$url['query']; |
|
87 | } |
||
88 | |||
89 | return $response; |
||
0 ignored issues
–
show
|
|||
90 | } |
||
91 | |||
92 | /** |
||
93 | * @param string $path |
||
94 | * @param string $contents |
||
95 | * @param Config $config |
||
96 | * |
||
97 | * @throws RuntimeException |
||
98 | * |
||
99 | * @return array|bool |
||
100 | */ |
||
101 | 6 | public function write($path, $contents, Config $config) |
|
102 | { |
||
103 | 6 | $temporaryPath = $this->createTemporaryFile($contents); |
|
104 | |||
105 | 6 | $response = $this->cosApi->upload($this->getBucket(), $temporaryPath, $path, |
|
106 | 6 | null, null, $config->get('insertOnly', 1)); |
|
107 | |||
108 | 6 | $response = $this->normalizeResponse($response); |
|
109 | |||
110 | 5 | if (false !== $response) { |
|
111 | 5 | $this->setContentType($path, $contents); |
|
112 | 5 | } |
|
113 | |||
114 | 5 | return $response; |
|
115 | } |
||
116 | |||
117 | /** |
||
118 | * @param string $path |
||
119 | * @param resource $resource |
||
120 | * @param Config $config |
||
121 | * |
||
122 | * @throws RuntimeException |
||
123 | * |
||
124 | * @return array|bool |
||
125 | */ |
||
126 | 2 | public function writeStream($path, $resource, Config $config) |
|
127 | { |
||
128 | 2 | $uri = stream_get_meta_data($resource)['uri']; |
|
129 | |||
130 | 2 | $response = $this->cosApi->upload($this->getBucket(), $uri, $path, |
|
131 | 2 | null, null, $config->get('insertOnly', 1)); |
|
132 | |||
133 | 2 | $response = $this->normalizeResponse($response); |
|
134 | |||
135 | 1 | if (false !== $response) { |
|
136 | 1 | $this->setContentType($path, stream_get_contents($resource)); |
|
137 | 1 | } |
|
138 | |||
139 | 1 | return $response; |
|
140 | } |
||
141 | |||
142 | /** |
||
143 | * @param string $path |
||
144 | * @param string $contents |
||
145 | * @param Config $config |
||
146 | * |
||
147 | * @throws RuntimeException |
||
148 | * |
||
149 | * @return array|bool |
||
150 | */ |
||
151 | 2 | public function update($path, $contents, Config $config) |
|
152 | { |
||
153 | 2 | $temporaryPath = $this->createTemporaryFile($contents); |
|
154 | |||
155 | 2 | $response = $this->cosApi->upload($this->getBucket(), $temporaryPath, $path, |
|
156 | 2 | null, null, $config->get('insertOnly', 0)); |
|
157 | |||
158 | 2 | $response = $this->normalizeResponse($response); |
|
159 | |||
160 | 1 | if (false !== $response) { |
|
161 | 1 | $this->setContentType($path, $contents); |
|
162 | 1 | } |
|
163 | |||
164 | 1 | return $response; |
|
165 | } |
||
166 | |||
167 | /** |
||
168 | * @param string $path |
||
169 | * @param resource $resource |
||
170 | * @param Config $config |
||
171 | * |
||
172 | * @throws RuntimeException |
||
173 | * |
||
174 | * @return array|bool |
||
175 | */ |
||
176 | 2 | public function updateStream($path, $resource, Config $config) |
|
177 | { |
||
178 | 2 | $uri = stream_get_meta_data($resource)['uri']; |
|
179 | |||
180 | 2 | $response = $this->cosApi->upload($this->getBucket(), $uri, $path, |
|
181 | 2 | null, null, $config->get('insertOnly', 0)); |
|
182 | |||
183 | 2 | $response = $this->normalizeResponse($response); |
|
184 | |||
185 | 2 | if (false !== $response) { |
|
186 | 1 | $this->setContentType($path, stream_get_contents($resource)); |
|
187 | 1 | } |
|
188 | |||
189 | 1 | return $response; |
|
190 | } |
||
191 | |||
192 | /** |
||
193 | * @param string $path |
||
194 | * @param string $newpath |
||
195 | * |
||
196 | * @return bool |
||
197 | */ |
||
198 | 2 | public function rename($path, $newpath) |
|
199 | { |
||
200 | 2 | return (bool) $this->normalizeResponse( |
|
201 | 2 | $this->cosApi->moveFile($this->getBucket(), $path, $newpath, true) |
|
202 | 2 | ); |
|
203 | } |
||
204 | |||
205 | /** |
||
206 | * @param string $path |
||
207 | * @param string $newpath |
||
208 | * |
||
209 | * @return bool |
||
210 | */ |
||
211 | 2 | public function copy($path, $newpath) |
|
212 | { |
||
213 | 2 | return (bool) $this->normalizeResponse( |
|
214 | 2 | $this->cosApi->copyFile($this->getBucket(), $path, $newpath, true) |
|
215 | 2 | ); |
|
216 | } |
||
217 | |||
218 | /** |
||
219 | * @param string $path |
||
220 | * |
||
221 | * @return bool |
||
222 | */ |
||
223 | 2 | public function delete($path) |
|
224 | { |
||
225 | 2 | return (bool) $this->normalizeResponse( |
|
226 | 2 | $this->cosApi->delFile($this->getBucket(), $path) |
|
227 | 2 | ); |
|
228 | } |
||
229 | |||
230 | /** |
||
231 | * @param string $dirname |
||
232 | * |
||
233 | * @return bool |
||
234 | */ |
||
235 | 2 | public function deleteDir($dirname) |
|
236 | { |
||
237 | 2 | return (bool) $this->normalizeResponse( |
|
238 | 2 | $this->cosApi->delFolder($this->getBucket(), $dirname) |
|
239 | 2 | ); |
|
240 | } |
||
241 | |||
242 | /** |
||
243 | * @param string $dirname |
||
244 | * @param Config $config |
||
245 | * |
||
246 | * @return array|bool |
||
247 | */ |
||
248 | 2 | public function createDir($dirname, Config $config) |
|
249 | { |
||
250 | 2 | return $this->normalizeResponse( |
|
0 ignored issues
–
show
|
|||
251 | 2 | $this->cosApi->createFolder($this->getBucket(), $dirname) |
|
252 | 2 | ); |
|
253 | } |
||
254 | |||
255 | /** |
||
256 | * @param string $path |
||
257 | * @param string $visibility |
||
258 | * |
||
259 | * @return bool |
||
260 | */ |
||
261 | 2 | public function setVisibility($path, $visibility) |
|
262 | { |
||
263 | 2 | $visibility = ($visibility === AdapterInterface::VISIBILITY_PUBLIC) |
|
264 | 2 | ? 'eWPrivateRPublic' : 'eWRPrivate'; |
|
265 | |||
266 | 2 | return (bool) $this->normalizeResponse( |
|
0 ignored issues
–
show
The expression
return (bool)$this->norm...th, null, $visibility)) returns the type boolean which is incompatible with the return type mandated by League\Flysystem\AdapterInterface::setVisibility() of false|array .
In the issue above, the returned value is violating the contract defined by the mentioned interface. Let's take a look at an example: interface HasName {
/** @return string */
public function getName();
}
class Name {
public $name;
}
class User implements HasName {
/** @return string|Name */
public function getName() {
return new Name('foo'); // This is a violation of the ``HasName`` interface
// which only allows a string value to be returned.
}
}
![]() |
|||
267 | 2 | $this->cosApi->update($this->getBucket(), $path, null, $visibility) |
|
268 | 2 | ); |
|
269 | } |
||
270 | |||
271 | /** |
||
272 | * @param string $path |
||
273 | * |
||
274 | * @return bool |
||
275 | */ |
||
276 | 1 | public function has($path) |
|
277 | { |
||
278 | try { |
||
279 | 1 | return (bool) $this->getMetadata($path); |
|
280 | 1 | } catch (RuntimeException $exception) { |
|
281 | 1 | return false; |
|
282 | } |
||
283 | } |
||
284 | |||
285 | /** |
||
286 | * @param string $path |
||
287 | * |
||
288 | * @return array|bool |
||
289 | */ |
||
290 | 1 | public function read($path) |
|
291 | { |
||
292 | 1 | $contents = file_get_contents($this->applyPathPrefix($path)); |
|
293 | |||
294 | 1 | return $contents !== false ? compact('contents') : false; |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * @param string $path |
||
299 | * |
||
300 | * @return array|bool |
||
301 | */ |
||
302 | 1 | public function readStream($path) |
|
303 | { |
||
304 | 1 | $stream = fopen($this->applyPathPrefix($path), 'r'); |
|
305 | |||
306 | 1 | return $stream !== false ? compact('stream') : false; |
|
307 | } |
||
308 | |||
309 | /** |
||
310 | * @param string $directory |
||
311 | * @param bool $recursive |
||
312 | * |
||
313 | * @return array|bool |
||
314 | */ |
||
315 | 1 | public function listContents($directory = '', $recursive = false) |
|
316 | { |
||
317 | 1 | return $this->normalizeResponse( |
|
0 ignored issues
–
show
|
|||
318 | 1 | $this->cosApi->listFolder($this->getBucket(), $directory) |
|
319 | 1 | ); |
|
320 | } |
||
321 | |||
322 | /** |
||
323 | * @param string $path |
||
324 | * |
||
325 | * @return array|bool |
||
326 | */ |
||
327 | 6 | public function getMetadata($path) |
|
328 | { |
||
329 | 6 | return $this->normalizeResponse( |
|
0 ignored issues
–
show
|
|||
330 | 6 | $this->cosApi->stat($this->getBucket(), $path) |
|
331 | 6 | ); |
|
332 | } |
||
333 | |||
334 | /** |
||
335 | * @param string $path |
||
336 | * |
||
337 | * @return array|bool |
||
338 | */ |
||
339 | 1 | public function getSize($path) |
|
340 | { |
||
341 | 1 | $stat = $this->getMetadata($path); |
|
342 | |||
343 | 1 | return isset($stat['filesize']) ? ['size' => $stat['filesize']] : false; |
|
344 | } |
||
345 | |||
346 | /** |
||
347 | * @param string $path |
||
348 | * |
||
349 | * @return array|bool |
||
350 | */ |
||
351 | 1 | public function getMimetype($path) |
|
352 | { |
||
353 | 1 | $stat = $this->getMetadata($path); |
|
354 | |||
355 | 1 | return isset($stat['custom_headers']['Content-Type']) |
|
356 | 1 | ? ['mimetype' => $stat['custom_headers']['Content-Type']] : false; |
|
357 | } |
||
358 | |||
359 | /** |
||
360 | * @param string $path |
||
361 | * |
||
362 | * @return array|bool |
||
363 | */ |
||
364 | 1 | public function getTimestamp($path) |
|
365 | { |
||
366 | 1 | $stat = $this->getMetadata($path); |
|
367 | |||
368 | 1 | return isset($stat['ctime']) ? ['timestamp' => $stat['ctime']] : false; |
|
369 | } |
||
370 | |||
371 | /** |
||
372 | * @param string $path |
||
373 | * |
||
374 | * @return array|bool |
||
375 | */ |
||
376 | 1 | public function getVisibility($path) |
|
377 | { |
||
378 | 1 | $stat = $this->getMetadata($path); |
|
379 | |||
380 | 1 | if (isset($stat['authority']) && $stat['authority'] === 'eWPrivateRPublic') { |
|
381 | return ['visibility' => AdapterInterface::VISIBILITY_PUBLIC]; |
||
382 | } |
||
383 | |||
384 | 1 | if (isset($stat['authority']) && $stat['authority'] === 'eWRPrivate') { |
|
385 | 1 | return ['visibility' => AdapterInterface::VISIBILITY_PRIVATE]; |
|
386 | } |
||
387 | |||
388 | return false; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * Creates a temporary file. |
||
393 | * |
||
394 | * @param string $content |
||
395 | * |
||
396 | * @throws RuntimeException |
||
397 | * |
||
398 | * @return string |
||
399 | */ |
||
400 | 8 | protected function createTemporaryFile($content) |
|
401 | { |
||
402 | 8 | $temporaryPath = $this->getTemporaryPath(); |
|
403 | |||
404 | 8 | if (false === $temporaryPath) { |
|
0 ignored issues
–
show
|
|||
405 | throw new RuntimeException("Unable to create temporary file in '{$temporaryPath}'."); |
||
406 | } |
||
407 | |||
408 | 8 | file_put_contents($temporaryPath, $content); |
|
409 | |||
410 | // The file is automatically removed when closed, or when the script ends. |
||
411 | 8 | register_shutdown_function(function () use ($temporaryPath) { |
|
412 | unlink($temporaryPath); |
||
413 | 8 | }); |
|
414 | |||
415 | 8 | return $temporaryPath; |
|
416 | } |
||
417 | |||
418 | /** |
||
419 | * Gets a temporary file path. |
||
420 | * |
||
421 | * @return bool|string |
||
422 | */ |
||
423 | 8 | protected function getTemporaryPath() |
|
424 | { |
||
425 | 8 | return tempnam(sys_get_temp_dir(), uniqid('tencentyun', true)); |
|
426 | } |
||
427 | |||
428 | /** |
||
429 | * @param string $path |
||
430 | * @param string $content |
||
431 | * |
||
432 | * @return bool |
||
433 | */ |
||
434 | 8 | protected function setContentType($path, $content) |
|
435 | { |
||
436 | $custom_headers = [ |
||
437 | 8 | 'Content-Type' => Util::guessMimeType($path, $content), |
|
438 | 8 | ]; |
|
439 | |||
440 | 8 | return $this->normalizeResponse( |
|
441 | 8 | $this->cosApi->update($this->getBucket(), $path, null, null, $custom_headers) |
|
442 | 8 | ); |
|
443 | } |
||
444 | |||
445 | /** |
||
446 | * @param $response |
||
447 | * |
||
448 | * @throws RuntimeException |
||
449 | * |
||
450 | * @return mixed |
||
451 | */ |
||
452 | 26 | protected function normalizeResponse($response) |
|
453 | { |
||
454 | 26 | if ($response['code'] == 0) { |
|
455 | 18 | return isset($response['data']) ? $response['data'] : true; |
|
456 | } |
||
457 | |||
458 | 9 | if ($this->debug) { |
|
459 | 9 | throw new RuntimeException($response['message'], $response['code']); |
|
460 | } |
||
461 | |||
462 | return false; |
||
463 | } |
||
464 | } |
||
465 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.