Adapter::read()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
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
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

75
    public function getTemporaryUrl($path, DateTimeInterface $expiration, /** @scrutinizer ignore-unused */ array $options = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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
Bug Best Practice introduced by
The expression return $response also could return the type array<string,string> which is incompatible with the documented return type string|boolean.
Loading history...
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
Bug Best Practice introduced by
The expression return $this->normalizeR...getBucket(), $dirname)) also could return the type boolean which is incompatible with the return type mandated by League\Flysystem\AdapterInterface::createDir() of false|array.
Loading history...
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
Bug Best Practice introduced by
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.
    }
}
Loading history...
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
Bug Best Practice introduced by
The expression return $this->normalizeR...tBucket(), $directory)) also could return the type boolean which is incompatible with the return type mandated by League\Flysystem\ReadInterface::listContents() of array.
Loading history...
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
Bug Best Practice introduced by
The expression return $this->normalizeR...s->getBucket(), $path)) also could return the type boolean which is incompatible with the return type mandated by League\Flysystem\ReadInterface::getMetadata() of false|array.
Loading history...
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
introduced by
The condition false === $temporaryPath is always false.
Loading history...
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