Passed
Push — master ( 53ff19...ea1022 )
by Luo
54s queued 11s
created

OssAdapter::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 5
Bugs 3 Features 0
Metric Value
cc 1
eloc 10
c 5
b 3
f 0
nc 1
nop 8
dl 0
loc 12
ccs 0
cts 12
cp 0
crap 2
rs 9.9332

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/*
4
 * This file is part of the iidestiny/flysystem-oss.
5
 *
6
 * (c) iidestiny <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Iidestiny\Flysystem\Oss;
13
14
use Carbon\Carbon;
15
use Iidestiny\Flysystem\Oss\Traits\SignatureTrait;
16
use League\Flysystem\AdapterInterface;
17
use League\Flysystem\Adapter\AbstractAdapter;
18
use League\Flysystem\Adapter\Polyfill\NotSupportingVisibilityTrait;
19
use League\Flysystem\Config;
20
use OSS\Core\OssException;
21
use OSS\OssClient;
22
23
/**
24
 * Class OssAdapter.
25
 *
26
 * @author iidestiny <[email protected]>
27
 */
28
class OssAdapter extends AbstractAdapter
29
{
30
    use NotSupportingVisibilityTrait;
31
    use SignatureTrait;
32
33
    /**
34
     * @var
35
     */
36
    protected $accessKeyId;
37
38
    /**
39
     * @var
40
     */
41
    protected $accessKeySecret;
42
43
    /**
44
     * @var
45
     */
46
    protected $endpoint;
47
48
    /**
49
     * @var
50
     */
51
    protected $bucket;
52
53
    /**
54
     * @var
55
     */
56
    protected $isCName;
57
58
    /**
59
     * @var array
60
     */
61
    protected $buckets;
62
    /**
63
     * @var OssClient
64
     */
65
    protected $client;
66
67
    /**
68
     * @var array|mixed[]
69
     */
70
    protected $params;
71
72
    /**
73
     * @var bool
74
     */
75
    protected $useSSL = false;
76
77
    /**
78
     * OssAdapter constructor.
79
     *
80
     * @param       $accessKeyId
81
     * @param       $accessKeySecret
82
     * @param       $endpoint
83
     * @param       $bucket
84
     * @param bool  $isCName
85
     * @param       $prefix
86
     * @param array $buckets
87
     * @param mixed ...$params
88
     *
89
     * @throws OssException
90
     */
91
    public function __construct($accessKeyId, $accessKeySecret, $endpoint, $bucket, $isCName = false, $prefix = '', $buckets = [], ...$params)
92
    {
93
        $this->accessKeyId = $accessKeyId;
94
        $this->accessKeySecret = $accessKeySecret;
95
        $this->endpoint = $endpoint;
96
        $this->bucket = $bucket;
97
        $this->isCName = $isCName;
98
        $this->setPathPrefix($prefix);
99
        $this->buckets = $buckets;
100
        $this->params = $params;
101
        $this->initClient();
102
        $this->checkEndpoint();
103
    }
104
105
    /**
106
     * 调用不同的桶配置
107
     */
108
    public function bucket($bucket)
109
    {
110
        if (!isset($this->buckets[$bucket])) {
111
            throw new \Exception("bucket is not exist.");
112
        }
113
        $bucketConfig = $this->buckets[$bucket];
114
115
        $this->accessKeyId = $bucketConfig['access_key'];
116
        $this->accessKeySecret = $bucketConfig['secret_key'];
117
        $this->endpoint = $bucketConfig['endpoint'];
118
        $this->bucket = $bucketConfig['bucket'];
119
        $this->isCName = $bucketConfig['isCName'];
120
121
        $this->initClient();
122
        $this->checkEndpoint();
123
124
        return $this;
125
    }
126
127
    /**
128
     * init oss client.
129
     *
130
     * @throws OssException
131
     */
132
    protected function initClient()
133
    {
134
        if (empty($this->client)) {
135
            $this->client = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint, $this->isCName, ...$this->params);
0 ignored issues
show
Bug introduced by
$this->params is expanded, but the parameter $securityToken of OSS\OssClient::__construct() does not expect variable arguments. ( Ignorable by Annotation )

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

135
            $this->client = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint, $this->isCName, /** @scrutinizer ignore-type */ ...$this->params);
Loading history...
136
        }
137
    }
138
139
    /**
140
     * oss 直传配置.
141
     *
142
     * @param string $prefix
143
     * @param null   $callBackUrl
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $callBackUrl is correct as it would always require null to be passed?
Loading history...
144
     * @param int    $expire
145
     * @param int    $contentLengthRangeValue 最大文件大小
146
     *
147
     * @return false|string
148
     *
149
     * @throws \Exception
150
     */
151
    public function signatureConfig($prefix = '', $callBackUrl = null, $expire = 30, $contentLengthRangeValue = 1048576000)
152
    {
153
        if (!empty($prefix)) {
154
            $prefix = ltrim($prefix, '/');
155
        }
156
157
        $callbackParam = [
158
            'callbackUrl' => $callBackUrl,
159
            'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
160
            'callbackBodyType' => 'application/x-www-form-urlencoded',
161
        ];
162
        $callbackString = json_encode($callbackParam);
163
        $base64_callback_body = base64_encode($callbackString);
164
165
        $now = time();
166
        $end = $now + $expire;
167
        $expiration = $this->gmt_iso8601($end);
168
169
        // 最大文件大小.用户可以自己设置
170
        $condition = [
171
            0 => 'content-length-range',
172
            1 => 0,
173
            2 => $contentLengthRangeValue,
174
        ];
175
        $conditions[] = $condition;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$conditions was never initialized. Although not strictly required by PHP, it is generally a good practice to add $conditions = array(); before regardless.
Loading history...
176
177
        $start = [
178
            0 => 'starts-with',
179
            1 => '$key',
180
            2 => $prefix,
181
        ];
182
        $conditions[] = $start;
183
184
        $arr = [
185
            'expiration' => $expiration,
186
            'conditions' => $conditions,
187
        ];
188
        $policy = json_encode($arr);
189
        $base64_policy = base64_encode($policy);
190
        $string_to_sign = $base64_policy;
191
        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true));
192
193
        $response = [];
194
        $response['accessid'] = $this->accessKeyId;
195
        $response['host'] = $this->normalizeHost();
196
        $response['policy'] = $base64_policy;
197
        $response['signature'] = $signature;
198
        $response['expire'] = $end;
199
        $response['callback'] = $base64_callback_body;
200
        $response['dir'] = $prefix;  // 这个参数是设置用户上传文件时指定的前缀。
201
202
        return json_encode($response);
203
    }
204
205
    /**
206
     * sign url.
207
     *
208
     * @param       $path
209
     * @param       $timeout
210
     * @param array $options
211
     *
212
     * @return bool|string
213
     */
214
    public function signUrl($path, $timeout, array $options = [])
215
    {
216
        $path = $this->applyPathPrefix($path);
217
218
        try {
219
            $path = $this->client->signUrl($this->bucket, $path, $timeout, OssClient::OSS_HTTP_GET, $options);
220
        } catch (OssException $exception) {
221
            return false;
222
        }
223
224
        return $path;
225
    }
226
227
    /**
228
     * temporaryUrl.
229
     *
230
     * @param       $path
231
     * @param       $expiration
232
     * @param array $options
233
     */
234
    public function getTemporaryUrl($path, $expiration, array $options = [])
235
    {
236
        return $this->signUrl($path, Carbon::now()->diffInSeconds($expiration), $options);
237
    }
238
239
    /**
240
     * write a file.
241
     *
242
     * @param string $path
243
     * @param string $contents
244
     * @param Config $config
245
     *
246
     * @return array|bool|false
247
     */
248
    public function write($path, $contents, Config $config)
249
    {
250
        $path = $this->applyPathPrefix($path);
251
252
        $options = [];
253
254
        if ($config->has('options')) {
255
            $options = $config->get('options');
256
        }
257
258
        $this->client->putObject($this->bucket, $path, $contents, $options);
259
260
        return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by League\Flysystem\AdapterInterface::write() of array|false.

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...
261
    }
262
263
    /**
264
     * Write a new file using a stream.
265
     *
266
     * @param string   $path
267
     * @param resource $resource
268
     * @param Config   $config
269
     *
270
     * @return array|bool|false
271
     */
272
    public function writeStream($path, $resource, Config $config)
273
    {
274
        $contents = stream_get_contents($resource);
275
276
        return $this->write($path, $contents, $config);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->write($path, $contents, $config) returns the type true which is incompatible with the return type mandated by League\Flysystem\AdapterInterface::writeStream() of array|false.

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...
277
    }
278
279
    /**
280
     * Update a file.
281
     *
282
     * @param string $path
283
     * @param string $contents
284
     * @param Config $config
285
     *
286
     * @return array|bool|false
287
     */
288
    public function update($path, $contents, Config $config)
289
    {
290
        return $this->write($path, $contents, $config);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->write($path, $contents, $config) returns the type true which is incompatible with the return type mandated by League\Flysystem\AdapterInterface::update() of array|false.

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...
291
    }
292
293
    /**
294
     * Update a file using a stream.
295
     *
296
     * @param string   $path
297
     * @param resource $resource
298
     * @param Config   $config
299
     *
300
     * @return array|bool|false
301
     */
302
    public function updateStream($path, $resource, Config $config)
303
    {
304
        return $this->writeStream($path, $resource, $config);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->writeStrea...th, $resource, $config) returns the type true which is incompatible with the return type mandated by League\Flysystem\AdapterInterface::updateStream() of array|false.

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...
305
    }
306
307
    /**
308
     * rename a file.
309
     *
310
     * @param string $path
311
     * @param string $newpath
312
     *
313
     * @return bool
314
     *
315
     * @throws OssException
316
     */
317
    public function rename($path, $newpath)
318
    {
319
        if (!$this->copy($path, $newpath)) {
320
            return false;
321
        }
322
323
        return $this->delete($path);
324
    }
325
326
    /**
327
     * copy a file.
328
     *
329
     * @param string $path
330
     * @param string $newpath
331
     *
332
     * @return bool
333
     */
334
    public function copy($path, $newpath)
335
    {
336
        $path = $this->applyPathPrefix($path);
337
        $newpath = $this->applyPathPrefix($newpath);
338
339
        try {
340
            $this->client->copyObject($this->bucket, $path, $this->bucket, $newpath);
341
        } catch (OssException $exception) {
342
            return false;
343
        }
344
345
        return true;
346
    }
347
348
    /**
349
     * delete a file.
350
     *
351
     * @param string $path
352
     *
353
     * @return bool
354
     *
355
     * @throws OssException
356
     */
357
    public function delete($path)
358
    {
359
        $path = $this->applyPathPrefix($path);
360
361
        try {
362
            $this->client->deleteObject($this->bucket, $path);
363
        } catch (OssException $ossException) {
364
            return false;
365
        }
366
367
        return !$this->has($path);
368
    }
369
370
    /**
371
     * Delete a directory.
372
     *
373
     * @param string $dirname
374
     *
375
     * @return bool
376
     */
377
    public function deleteDir($dirname)
378
    {
379
        $fileList = $this->listContents($dirname, true);
380
        foreach ($fileList as $file) {
381
            $this->delete($file['path']);
382
        }
383
384
        return !$this->has($dirname);
385
    }
386
387
    /**
388
     * create a directory.
389
     *
390
     * @param string $dirname
391
     * @param Config $config
392
     *
393
     * @return bool
394
     */
395
    public function createDir($dirname, Config $config)
396
    {
397
        $defaultFile = trim($dirname, '/').'/oss.txt';
398
399
        return $this->write($defaultFile, '当虚拟目录下有其他文件时,可删除此文件~', $config);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->write($def... returns the type true which is incompatible with the return type mandated by League\Flysystem\AdapterInterface::createDir() of array|false.

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...
400
    }
401
402
    /**
403
     * visibility.
404
     *
405
     * @param string $path
406
     * @param string $visibility
407
     *
408
     * @return array|bool|false
409
     */
410
    public function setVisibility($path, $visibility)
411
    {
412
        $object = $this->applyPathPrefix($path);
413
        $acl = (AdapterInterface::VISIBILITY_PUBLIC === $visibility) ? OssClient::OSS_ACL_TYPE_PUBLIC_READ : OssClient::OSS_ACL_TYPE_PRIVATE;
414
415
        try {
416
            $this->client->putObjectAcl($this->bucket, $object, $acl);
417
        } catch (OssException $exception) {
418
            return false;
419
        }
420
421
        return compact('visibility');
422
    }
423
424
    /**
425
     * Check whether a file exists.
426
     *
427
     * @param string $path
428
     *
429
     * @return array|bool|null
430
     */
431
    public function has($path)
432
    {
433
        $path = $this->applyPathPrefix($path);
434
435
        return $this->client->doesObjectExist($this->bucket, $path);
436
    }
437
438
    /**
439
     * Get resource url.
440
     *
441
     * @param string $path
442
     *
443
     * @return string
444
     */
445
    public function getUrl($path)
446
    {
447
        $path = $this->applyPathPrefix($path);
448
449
        return $this->normalizeHost().ltrim($path, '/');
450
    }
451
452
    /**
453
     * read a file.
454
     *
455
     * @param string $path
456
     *
457
     * @return array|bool|false
458
     */
459
    public function read($path)
460
    {
461
        try {
462
            $contents = $this->getObject($path);
463
        } catch (OssException $exception) {
464
            return false;
465
        }
466
467
        return compact('contents', 'path');
468
    }
469
470
    /**
471
     * read a file stream.
472
     *
473
     * @param string $path
474
     *
475
     * @return array|bool|false
476
     */
477
    public function readStream($path)
478
    {
479
        try {
480
            $stream = $this->getObject($path);
481
        } catch (OssException $exception) {
482
            return false;
483
        }
484
485
        return compact('stream', 'path');
486
    }
487
488
    /**
489
     * Lists all files in the directory.
490
     *
491
     * @param string $directory
492
     * @param bool   $recursive
493
     *
494
     * @return array
495
     *
496
     * @throws OssException
497
     */
498
    public function listContents($directory = '', $recursive = false)
499
    {
500
        $list = [];
501
502
        $result = $this->listDirObjects($directory, true);
503
504
        if (!empty($result['objects'])) {
505
            foreach ($result['objects'] as $files) {
506
                if (!$fileInfo = $this->normalizeFileInfo($files)) {
507
                    continue;
508
                }
509
510
                $list[] = $fileInfo;
511
            }
512
        }
513
514
        return $list;
515
    }
516
517
    /**
518
     * get meta data.
519
     *
520
     * @param string $path
521
     *
522
     * @return array|bool|false
523
     */
524
    public function getMetadata($path)
525
    {
526
        $path = $this->applyPathPrefix($path);
527
528
        try {
529
            $metadata = $this->client->getObjectMeta($this->bucket, $path);
530
        } catch (OssException $exception) {
531
            return false;
532
        }
533
534
        return $metadata;
535
    }
536
537
    /**
538
     * get the size of file.
539
     *
540
     * @param string $path
541
     *
542
     * @return array|false
543
     */
544
    public function getSize($path)
545
    {
546
        return $this->normalizeFileInfo(['Key' => $path]);
547
    }
548
549
    /**
550
     * get mime type.
551
     *
552
     * @param string $path
553
     *
554
     * @return array|false
555
     */
556
    public function getMimetype($path)
557
    {
558
        return $this->normalizeFileInfo(['Key' => $path]);
559
    }
560
561
    /**
562
     * get timestamp.
563
     *
564
     * @param string $path
565
     *
566
     * @return array|false
567
     */
568
    public function getTimestamp($path)
569
    {
570
        return $this->normalizeFileInfo(['Key' => $path]);
571
    }
572
573
    /**
574
     * normalize Host.
575
     *
576
     * @return string
577
     */
578
    protected function normalizeHost()
579
    {
580
        if ($this->isCName) {
581
            $domain = $this->endpoint;
582
        } else {
583
            $domain = $this->bucket.'.'.$this->endpoint;
584
        }
585
586
        if ($this->useSSL) {
587
            $domain = "https://{$domain}";
588
        } else {
589
            $domain = "http://{$domain}";
590
        }
591
592
        return rtrim($domain, '/').'/';
593
    }
594
595
    /**
596
     * Check the endpoint to see if SSL can be used.
597
     */
598
    protected function checkEndpoint()
599
    {
600
        if (0 === strpos($this->endpoint, 'http://')) {
601
            $this->endpoint = substr($this->endpoint, strlen('http://'));
602
            $this->useSSL = false;
603
        } elseif (0 === strpos($this->endpoint, 'https://')) {
604
            $this->endpoint = substr($this->endpoint, strlen('https://'));
605
            $this->useSSL = true;
606
        }
607
    }
608
609
    /**
610
     * Read an object from the OssClient.
611
     *
612
     * @param $path
613
     *
614
     * @return string
615
     */
616
    protected function getObject($path)
617
    {
618
        $path = $this->applyPathPrefix($path);
619
620
        return $this->client->getObject($this->bucket, $path);
621
    }
622
623
    /**
624
     * File list core method.
625
     *
626
     * @param string $dirname
627
     * @param bool   $recursive
628
     *
629
     * @return array
630
     *
631
     * @throws OssException
632
     */
633
    public function listDirObjects($dirname = '', $recursive = false)
634
    {
635
        $delimiter = '/';
636
        $nextMarker = '';
637
        $maxkeys = 1000;
638
639
        $result = [];
640
641
        while (true) {
642
            $options = [
643
                'delimiter' => $delimiter,
644
                'prefix' => $dirname,
645
                'max-keys' => $maxkeys,
646
                'marker' => $nextMarker,
647
            ];
648
649
            try {
650
                $listObjectInfo = $this->client->listObjects($this->bucket, $options);
651
            } catch (OssException $exception) {
652
                throw $exception;
653
            }
654
655
            $nextMarker = $listObjectInfo->getNextMarker();
656
            $objectList = $listObjectInfo->getObjectList();
657
            $prefixList = $listObjectInfo->getPrefixList();
658
659
            if (!empty($objectList)) {
660
                foreach ($objectList as $objectInfo) {
661
                    $object['Prefix'] = $dirname;
662
                    $object['Key'] = $objectInfo->getKey();
663
                    $object['LastModified'] = $objectInfo->getLastModified();
664
                    $object['eTag'] = $objectInfo->getETag();
665
                    $object['Type'] = $objectInfo->getType();
666
                    $object['Size'] = $objectInfo->getSize();
667
                    $object['StorageClass'] = $objectInfo->getStorageClass();
668
                    $result['objects'][] = $object;
669
                }
670
            } else {
671
                $result['objects'] = [];
672
            }
673
674
            if (!empty($prefixList)) {
675
                foreach ($prefixList as $prefixInfo) {
676
                    $result['prefix'][] = $prefixInfo->getPrefix();
677
                }
678
            } else {
679
                $result['prefix'] = [];
680
            }
681
682
            // Recursive directory
683
            if ($recursive) {
684
                foreach ($result['prefix'] as $prefix) {
685
                    $next = $this->listDirObjects($prefix, $recursive);
686
                    $result['objects'] = array_merge($result['objects'], $next['objects']);
687
                }
688
            }
689
690
            if ('' === $nextMarker) {
691
                break;
692
            }
693
        }
694
695
        return $result;
696
    }
697
698
    /**
699
     * normalize file info.
700
     *
701
     * @param array $stats
702
     *
703
     * @return array
704
     */
705
    protected function normalizeFileInfo(array $stats)
706
    {
707
        $filePath = ltrim($stats['Key'], '/');
708
709
        $meta = $this->getMetadata($filePath) ?? [];
710
711
        if (empty($meta)) {
712
            return [];
713
        }
714
715
        return [
716
            'type' => 'file',
717
            'mimetype' => $meta['content-type'],
718
            'path' => $filePath,
719
            'timestamp' => $meta['info']['filetime'],
720
            'size' => $meta['content-length'],
721
        ];
722
    }
723
}
724