Passed
Push — master ( 62974d...a504b0 )
by Luo
04:22 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
    /**
64
     * @var OssClient
65
     */
66
    protected $client;
67
68
    /**
69
     * @var array|mixed[]
70
     */
71
    protected $params;
72
73
    /**
74
     * @var bool
75
     */
76
    protected $useSSL = false;
77
78
    /**
79
     * OssAdapter constructor.
80
     *
81
     * @param       $accessKeyId
82
     * @param       $accessKeySecret
83
     * @param       $endpoint
84
     * @param       $bucket
85
     * @param bool  $isCName
86
     * @param       $prefix
87
     * @param array $buckets
88
     * @param mixed ...$params
89
     *
90
     * @throws OssException
91
     */
92
    public function __construct($accessKeyId, $accessKeySecret, $endpoint, $bucket, $isCName = false, $prefix = '', $buckets = [], ...$params)
93
    {
94
        $this->accessKeyId     = $accessKeyId;
95
        $this->accessKeySecret = $accessKeySecret;
96
        $this->endpoint        = $endpoint;
97
        $this->bucket          = $bucket;
98
        $this->isCName         = $isCName;
99
        $this->setPathPrefix($prefix);
100
        $this->buckets = $buckets;
101
        $this->params = $params;
102
        $this->initClient();
103
        $this->checkEndpoint();
104
    }
105
106
    /**
107
     * 调用不同的桶配置.
108
     */
109
    public function bucket($bucket)
110
    {
111
        if (!isset($this->buckets[$bucket])) {
112
            throw new \Exception('bucket is not exist.');
113
        }
114
        $bucketConfig = $this->buckets[$bucket];
115
116
        $this->accessKeyId = $bucketConfig['access_key'];
117
        $this->accessKeySecret = $bucketConfig['secret_key'];
118
        $this->endpoint = $bucketConfig['endpoint'];
119
        $this->bucket = $bucketConfig['bucket'];
120
        $this->isCName = $bucketConfig['isCName'];
121
122
        $this->initClient();
123
        $this->checkEndpoint();
124
125
        return $this;
126
    }
127
128
    /**
129
     * init oss client.
130
     *
131
     * @throws OssException
132
     */
133
    protected function initClient()
134
    {
135
        if (empty($this->client)) {
136
            $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

136
            $this->client = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint, $this->isCName, /** @scrutinizer ignore-type */ ...$this->params);
Loading history...
137
        }
138
    }
139
140
    /**
141
     * get ali sdk kernel class
142
     *
143
     * @return OssClient
144
     */
145
    public function getClient()
146
    {
147
        return $this->client;
148
    }
149
150
    /**
151
     * oss 直传配置.
152
     *
153
     * @param string $prefix
154
     * @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...
155
     * @param int    $expire
156
     * @param int    $contentLengthRangeValue 最大文件大小
157
     *
158
     * @return false|string
159
     *
160
     * @throws \Exception
161
     */
162
    public function signatureConfig($prefix = '', $callBackUrl = null, $expire = 30, $contentLengthRangeValue = 1048576000)
163
    {
164
        if (!empty($prefix)) {
165
            $prefix = ltrim($prefix, '/');
166
        }
167
168
        $callbackParam        = [
169
            'callbackUrl'      => $callBackUrl,
170
            'callbackBody'     => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
171
            'callbackBodyType' => 'application/x-www-form-urlencoded',
172
        ];
173
        $callbackString       = json_encode($callbackParam);
174
        $base64_callback_body = base64_encode($callbackString);
175
176
        $now        = time();
177
        $end        = $now + $expire;
178
        $expiration = $this->gmt_iso8601($end);
179
180
        // 最大文件大小.用户可以自己设置
181
        $condition    = [
182
            0 => 'content-length-range',
183
            1 => 0,
184
            2 => $contentLengthRangeValue,
185
        ];
186
        $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...
187
188
        $start        = [
189
            0 => 'starts-with',
190
            1 => '$key',
191
            2 => $prefix,
192
        ];
193
        $conditions[] = $start;
194
195
        $arr            = [
196
            'expiration' => $expiration,
197
            'conditions' => $conditions,
198
        ];
199
        $policy         = json_encode($arr);
200
        $base64_policy  = base64_encode($policy);
201
        $string_to_sign = $base64_policy;
202
        $signature      = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true));
203
204
        $response              = [];
205
        $response['accessid']  = $this->accessKeyId;
206
        $response['host']      = $this->normalizeHost();
207
        $response['policy']    = $base64_policy;
208
        $response['signature'] = $signature;
209
        $response['expire']    = $end;
210
        $response['callback']  = $base64_callback_body;
211
        $response['dir']       = $prefix;  // 这个参数是设置用户上传文件时指定的前缀。
212
213
        return json_encode($response);
214
    }
215
216
    /**
217
     * sign url.
218
     *
219
     * @param       $path
220
     * @param       $timeout
221
     * @param array $options
222
     *
223
     * @return bool|string
224
     */
225
    public function signUrl($path, $timeout, array $options = [])
226
    {
227
        $path = $this->applyPathPrefix($path);
228
229
        try {
230
            $path = $this->client->signUrl($this->bucket, $path, $timeout, OssClient::OSS_HTTP_GET, $options);
231
        } catch (OssException $exception) {
232
            return false;
233
        }
234
235
        return $path;
236
    }
237
238
    /**
239
     * temporary file url
240
     *
241
     * @param       $path
242
     * @param       $expiration
243
     * @param array $options
244
     *
245
     * @return bool|string
246
     */
247
    public function getTemporaryUrl($path, $expiration, array $options = [])
248
    {
249
        return $this->signUrl($path, Carbon::now()->diffInSeconds($expiration), $options);
250
    }
251
252
    /**
253
     * write a file.
254
     *
255
     * @param string $path
256
     * @param string $contents
257
     * @param Config $config
258
     *
259
     * @return array|bool|false
260
     */
261
    public function write($path, $contents, Config $config)
262
    {
263
        $path = $this->applyPathPrefix($path);
264
265
        $options = [];
266
267
        if ($config->has('options')) {
268
            $options = $config->get('options');
269
        }
270
271
        $this->client->putObject($this->bucket, $path, $contents, $options);
272
273
        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...
274
    }
275
276
    /**
277
     * Write a new file using a stream.
278
     *
279
     * @param string   $path
280
     * @param resource $resource
281
     * @param Config   $config
282
     *
283
     * @return array|bool|false
284
     */
285
    public function writeStream($path, $resource, Config $config)
286
    {
287
        $contents = stream_get_contents($resource);
288
289
        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...
290
    }
291
292
    /**
293
     * Update a file.
294
     *
295
     * @param string $path
296
     * @param string $contents
297
     * @param Config $config
298
     *
299
     * @return array|bool|false
300
     */
301
    public function update($path, $contents, Config $config)
302
    {
303
        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...
304
    }
305
306
    /**
307
     * Update a file using a stream.
308
     *
309
     * @param string   $path
310
     * @param resource $resource
311
     * @param Config   $config
312
     *
313
     * @return array|bool|false
314
     */
315
    public function updateStream($path, $resource, Config $config)
316
    {
317
        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...
318
    }
319
320
    /**
321
     * rename a file.
322
     *
323
     * @param string $path
324
     * @param string $newpath
325
     *
326
     * @return bool
327
     *
328
     * @throws OssException
329
     */
330
    public function rename($path, $newpath)
331
    {
332
        if (!$this->copy($path, $newpath)) {
333
            return false;
334
        }
335
336
        return $this->delete($path);
337
    }
338
339
    /**
340
     * copy a file.
341
     *
342
     * @param string $path
343
     * @param string $newpath
344
     *
345
     * @return bool
346
     */
347
    public function copy($path, $newpath)
348
    {
349
        $path    = $this->applyPathPrefix($path);
350
        $newpath = $this->applyPathPrefix($newpath);
351
352
        try {
353
            $this->client->copyObject($this->bucket, $path, $this->bucket, $newpath);
354
        } catch (OssException $exception) {
355
            return false;
356
        }
357
358
        return true;
359
    }
360
361
    /**
362
     * delete a file.
363
     *
364
     * @param string $path
365
     *
366
     * @return bool
367
     *
368
     * @throws OssException
369
     */
370
    public function delete($path)
371
    {
372
        $path = $this->applyPathPrefix($path);
373
374
        try {
375
            $this->client->deleteObject($this->bucket, $path);
376
        } catch (OssException $ossException) {
377
            return false;
378
        }
379
380
        return !$this->has($path);
381
    }
382
383
    /**
384
     * Delete a directory.
385
     *
386
     * @param string $dirname
387
     *
388
     * @return bool
389
     */
390
    public function deleteDir($dirname)
391
    {
392
        $fileList = $this->listContents($dirname, true);
393
        foreach ($fileList as $file) {
394
            $this->delete($file['path']);
395
        }
396
397
        return !$this->has($dirname);
398
    }
399
400
    /**
401
     * create a directory.
402
     *
403
     * @param string $dirname
404
     * @param Config $config
405
     *
406
     * @return bool
407
     */
408
    public function createDir($dirname, Config $config)
409
    {
410
        $defaultFile = trim($dirname, '/').'/oss.txt';
411
412
        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...
413
    }
414
415
    /**
416
     * visibility.
417
     *
418
     * @param string $path
419
     * @param string $visibility
420
     *
421
     * @return array|bool|false
422
     */
423
    public function setVisibility($path, $visibility)
424
    {
425
        $object = $this->applyPathPrefix($path);
426
        $acl    = (AdapterInterface::VISIBILITY_PUBLIC === $visibility) ? OssClient::OSS_ACL_TYPE_PUBLIC_READ : OssClient::OSS_ACL_TYPE_PRIVATE;
427
428
        try {
429
            $this->client->putObjectAcl($this->bucket, $object, $acl);
430
        } catch (OssException $exception) {
431
            return false;
432
        }
433
434
        return compact('visibility');
435
    }
436
437
    /**
438
     * Check whether a file exists.
439
     *
440
     * @param string $path
441
     *
442
     * @return array|bool|null
443
     */
444
    public function has($path)
445
    {
446
        $path = $this->applyPathPrefix($path);
447
448
        return $this->client->doesObjectExist($this->bucket, $path);
449
    }
450
451
    /**
452
     * Get resource url.
453
     *
454
     * @param string $path
455
     *
456
     * @return string
457
     */
458
    public function getUrl($path)
459
    {
460
        $path = $this->applyPathPrefix($path);
461
462
        return $this->normalizeHost() . ltrim($path, '/');
463
    }
464
465
    /**
466
     * read a file.
467
     *
468
     * @param string $path
469
     *
470
     * @return array|bool|false
471
     */
472
    public function read($path)
473
    {
474
        try {
475
            $contents = $this->getObject($path);
476
        } catch (OssException $exception) {
477
            return false;
478
        }
479
480
        return compact('contents', 'path');
481
    }
482
483
    /**
484
     * read a file stream.
485
     *
486
     * @param string $path
487
     *
488
     * @return array|bool|false
489
     */
490
    public function readStream($path)
491
    {
492
        try {
493
            $stream = $this->getObject($path);
494
        } catch (OssException $exception) {
495
            return false;
496
        }
497
498
        return compact('stream', 'path');
499
    }
500
501
    /**
502
     * Lists all files in the directory.
503
     *
504
     * @param string $directory
505
     * @param bool   $recursive
506
     *
507
     * @return array
508
     *
509
     * @throws OssException
510
     */
511
    public function listContents($directory = '', $recursive = false)
512
    {
513
        $list = [];
514
515
        $result = $this->listDirObjects($directory, true);
516
517
        if (!empty($result['objects'])) {
518
            foreach ($result['objects'] as $files) {
519
                if (!$fileInfo = $this->normalizeFileInfo($files)) {
520
                    continue;
521
                }
522
523
                $list[] = $fileInfo;
524
            }
525
        }
526
527
        return $list;
528
    }
529
530
    /**
531
     * get meta data.
532
     *
533
     * @param string $path
534
     *
535
     * @return array|bool|false
536
     */
537
    public function getMetadata($path)
538
    {
539
        $path = $this->applyPathPrefix($path);
540
541
        try {
542
            $metadata = $this->client->getObjectMeta($this->bucket, $path);
543
        } catch (OssException $exception) {
544
            return false;
545
        }
546
547
        return $metadata;
548
    }
549
550
    /**
551
     * get the size of file.
552
     *
553
     * @param string $path
554
     *
555
     * @return array|false
556
     */
557
    public function getSize($path)
558
    {
559
        return $this->normalizeFileInfo(['Key' => $path]);
560
    }
561
562
    /**
563
     * get mime type.
564
     *
565
     * @param string $path
566
     *
567
     * @return array|false
568
     */
569
    public function getMimetype($path)
570
    {
571
        return $this->normalizeFileInfo(['Key' => $path]);
572
    }
573
574
    /**
575
     * get timestamp.
576
     *
577
     * @param string $path
578
     *
579
     * @return array|false
580
     */
581
    public function getTimestamp($path)
582
    {
583
        return $this->normalizeFileInfo(['Key' => $path]);
584
    }
585
586
    /**
587
     * normalize Host.
588
     *
589
     * @return string
590
     */
591
    protected function normalizeHost()
592
    {
593
        if ($this->isCName) {
594
            $domain = $this->endpoint;
595
        } else {
596
            $domain = $this->bucket . '.' . $this->endpoint;
597
        }
598
599
        if ($this->useSSL) {
600
            $domain = "https://{$domain}";
601
        } else {
602
            $domain = "http://{$domain}";
603
        }
604
605
        return rtrim($domain, '/') . '/';
606
    }
607
608
    /**
609
     * Check the endpoint to see if SSL can be used.
610
     */
611
    protected function checkEndpoint()
612
    {
613
        if (0 === strpos($this->endpoint, 'http://')) {
614
            $this->endpoint = substr($this->endpoint, strlen('http://'));
615
            $this->useSSL   = false;
616
        } elseif (0 === strpos($this->endpoint, 'https://')) {
617
            $this->endpoint = substr($this->endpoint, strlen('https://'));
618
            $this->useSSL   = true;
619
        }
620
    }
621
622
    /**
623
     * Read an object from the OssClient.
624
     *
625
     * @param $path
626
     *
627
     * @return string
628
     */
629
    protected function getObject($path)
630
    {
631
        $path = $this->applyPathPrefix($path);
632
633
        return $this->client->getObject($this->bucket, $path);
634
    }
635
636
    /**
637
     * File list core method.
638
     *
639
     * @param string $dirname
640
     * @param bool   $recursive
641
     *
642
     * @return array
643
     *
644
     * @throws OssException
645
     */
646
    public function listDirObjects($dirname = '', $recursive = false)
647
    {
648
        $delimiter  = '/';
649
        $nextMarker = '';
650
        $maxkeys    = 1000;
651
652
        $result = [];
653
654
        while (true) {
655
            $options = [
656
                'delimiter' => $delimiter,
657
                'prefix'    => $dirname,
658
                'max-keys'  => $maxkeys,
659
                'marker'    => $nextMarker,
660
            ];
661
662
            try {
663
                $listObjectInfo = $this->client->listObjects($this->bucket, $options);
664
            } catch (OssException $exception) {
665
                throw $exception;
666
            }
667
668
            $nextMarker = $listObjectInfo->getNextMarker();
669
            $objectList = $listObjectInfo->getObjectList();
670
            $prefixList = $listObjectInfo->getPrefixList();
671
672
            if (!empty($objectList)) {
673
                foreach ($objectList as $objectInfo) {
674
                    $object['Prefix']       = $dirname;
675
                    $object['Key']          = $objectInfo->getKey();
676
                    $object['LastModified'] = $objectInfo->getLastModified();
677
                    $object['eTag']         = $objectInfo->getETag();
678
                    $object['Type']         = $objectInfo->getType();
679
                    $object['Size']         = $objectInfo->getSize();
680
                    $object['StorageClass'] = $objectInfo->getStorageClass();
681
                    $result['objects'][]    = $object;
682
                }
683
            } else {
684
                $result['objects'] = [];
685
            }
686
687
            if (!empty($prefixList)) {
688
                foreach ($prefixList as $prefixInfo) {
689
                    $result['prefix'][] = $prefixInfo->getPrefix();
690
                }
691
            } else {
692
                $result['prefix'] = [];
693
            }
694
695
            // Recursive directory
696
            if ($recursive) {
697
                foreach ($result['prefix'] as $prefix) {
698
                    $next              = $this->listDirObjects($prefix, $recursive);
699
                    $result['objects'] = array_merge($result['objects'], $next['objects']);
700
                }
701
            }
702
703
            if ('' === $nextMarker) {
704
                break;
705
            }
706
        }
707
708
        return $result;
709
    }
710
711
    /**
712
     * normalize file info.
713
     *
714
     * @param array $stats
715
     *
716
     * @return array
717
     */
718
    protected function normalizeFileInfo(array $stats)
719
    {
720
        $filePath = ltrim($stats['Key'], '/');
721
722
        $meta = $this->getMetadata($filePath) ?? [];
723
724
        if (empty($meta)) {
725
            return [];
726
        }
727
728
        return [
729
            'type'      => 'file',
730
            'mimetype'  => $meta['content-type'],
731
            'path'      => $filePath,
732
            'timestamp' => $meta['info']['filetime'],
733
            'size'      => $meta['content-length'],
734
        ];
735
    }
736
}
737