Cos::recursiveDelete()   A
last analyzed

Complexity

Conditions 6
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 13
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 23
rs 9.2222
1
<?php
2
3
// +----------------------------------------------------------------------
4
// | date: 2015-09-09
5
// +----------------------------------------------------------------------
6
// | OssAdapter.php: oss上传
7
// +----------------------------------------------------------------------
8
// | Author: Tinymeng <[email protected]>
9
// +----------------------------------------------------------------------
10
11
12
namespace tinymeng\uploads\Gateways;
13
14
use Exception;
15
use Qcloud\Cos\Client;
16
use tinymeng\uploads\exception\TinymengException;
17
use tinymeng\uploads\Connector\Gateway;
18
use tinymeng\uploads\Helper\PathLibrary;
19
use tinymeng\uploads\Helper\FileFunction;
20
21
class Cos extends  Gateway
22
{
23
24
    const FILE_TYPE_FILE    = 'file';//类型是文件
25
    const FILE_TYPE_DIR     = 'dir';//类型是文件夹
26
27
28
    /**
29
     * oss client 上传对象
30
     *
31
     * @var OssClient
0 ignored issues
show
Bug introduced by
The type tinymeng\uploads\Gateways\OssClient was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
     */
33
    protected $upload;
34
35
    /**
36
     * bucket
37
     *
38
     * @var string
39
     */
40
    protected $bucket;
41
42
    /**
43
     * 构造方法
44
     *
45
     * @param array $config   配置信息
46
     * @author Tinymeng <[email protected]>
47
     */
48
    public function __construct($config)
49
    {
50
        $baseConfig = [
51
            'secretId'	=> '',
52
            'secretKey' => '',
53
            'bucket'    => '',
54
            'region' 	=> 'ap-beijing',
55
        ];
56
        
57
        // 兼容 accessKeyId/accessKeySecret 配置(映射到 secretId/secretKey)
58
        if (isset($config['accessKeyId']) && empty($config['secretId'])) {
59
            $config['secretId'] = $config['accessKeyId'];
60
        }
61
        if (isset($config['accessKeySecret']) && empty($config['secretKey'])) {
62
            $config['secretKey'] = $config['accessKeySecret'];
63
        }
64
        $this->config   = array_replace_recursive($baseConfig, $config);
65
        $this->bucket   = $this->config['bucket'];
66
    }
67
68
    /**
69
     * 格式化路径
70
     *
71
     * @param $path
72
     * @return string
73
     */
74
    protected static function normalizerPath($path, $is_dir = false)
75
    {
76
        $path = ltrim(PathLibrary::normalizerPath($path, $is_dir), '/');
77
78
        return $path == '/' ? '' : $path;
79
    }
80
81
    /**
82
     * 获得COS client上传对象
83
     *
84
     * @return Client
85
     * @author Tinymeng <[email protected]>
86
     */
87
    protected function getClient()
88
    {
89
        if (!$this->client) {
90
            // 检查必需的配置
91
            if (empty($this->config['secretId']) || empty($this->config['secretKey'])) {
92
                throw new TinymengException('COS配置错误:secretId 和 secretKey 不能为空');
93
            }
94
            if (empty($this->config['region'])) {
95
                throw new TinymengException('COS配置错误:region 不能为空');
96
            }
97
            
98
            $schema = isset($this->config['transport']) && $this->config['transport'] === 'https' ? 'https' : 'http';
99
            
100
            $config = array(
101
                'region' => $this->config['region'],
102
                'schema' => $schema, //协议头部,默认为https
103
                'credentials'=> array(
104
                    'secretId'  => $this->config['secretId'],
105
                    'secretKey' => $this->config['secretKey']
106
                )
107
            );
108
            
109
            // 可选配置
110
            if (isset($this->config['timeout'])) {
111
                $config['timeout'] = (int)$this->config['timeout'];
112
            }
113
            if (isset($this->config['connectTimeout'])) {
114
                $config['connectTimeout'] = (int)$this->config['connectTimeout'];
115
            }
116
            
117
            $this->client = new Client($config);
118
        }
119
        return $this->client;
120
    }
121
122
    /**
123
     * 获得 Oss 实例
124
     * @return OssClient
125
     */
126
    public function getInstance()
127
    {
128
        return $this->getClient();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getClient() returns the type Qcloud\Cos\Client which is incompatible with the documented return type tinymeng\uploads\Gateways\OssClient.
Loading history...
129
    }
130
131
    /**
132
     * 判断文件是否存在
133
     * @param string $path
134
     * @return bool
135
     * @throws TinymengException
136
     * @author Tinymeng <[email protected]>
137
     */
138
    public function has($path)
139
    {
140
        try {
141
            $path = static::normalizerPath($path);
142
            $params = array(
143
                'Bucket' => $this->bucket,
144
                'Key' => $path
145
            );
146
            $this->getClient()->headObject($params);
147
            return true;
148
        }catch (Exception $e){
149
            // 如果文件不存在,会抛出异常,返回 false
150
            if (strpos($e->getMessage(), '404') !== false || strpos($e->getMessage(), 'NoSuchKey') !== false) {
151
                return false;
152
            }
153
            throw new TinymengException($e->getMessage());
154
        }
155
    }
156
157
    /**
158
     * 读取文件
159
     * @param $path
160
     * @return array
161
     * @throws TinymengException
162
     * @internal param $file_name
163
     * @author Tinymeng <[email protected]>
164
     */
165
    public function read($path)
166
    {
167
        try {
168
            $path = static::normalizerPath($path);
169
            $params = array(
170
                'Bucket' => $this->bucket,
171
                'Key' => $path
172
            );
173
            $result = $this->getClient()->getObject($params);
174
            return ['contents' => $result['Body']->getContents()];
175
        }catch (Exception $e){
176
            throw new TinymengException($e->getMessage());
177
        }
178
    }
179
180
    /**
181
     * 获得文件流
182
     * @param string $path
183
     * @return array|bool
184
     * @throws TinymengException
185
     * @author Tinymeng <[email protected]>
186
     */
187
    public function readStream($path)
188
    {
189
        try {
190
            //获得一个临时文件
191
            $tmpfname       = FileFunction::getTmpFile();
192
193
            file_put_contents($tmpfname, $this->read($path)['contents'] );
194
195
            $handle         = fopen($tmpfname, 'r');
196
197
            //删除临时文件
198
            FileFunction::deleteTmpFile($tmpfname);
199
200
            return ['stream' => $handle];
201
        }catch (Exception $e){
202
            throw new TinymengException($e->getMessage());
203
        }
204
    }
205
206
    /**
207
     * 写入文件
208
     *
209
     * @param $path
210
     * @param $contents
211
     * @param array $option
212
     * @return mixed
213
     * @throws TinymengException
214
     * @author Tinymeng <[email protected]>
215
     */
216
    public function write($path, $contents,$option=[])
217
    {
218
        try {
219
            $path = static::normalizerPath($path);
220
            $params = array_merge([
221
                'Bucket' => $this->bucket,
222
                'Key' => $path,
223
                'Body' => $contents
224
            ], $option);
225
            return $this->getClient()->putObject($params);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getClient()->putObject($params) returns the type object which is incompatible with the return type mandated by tinymeng\uploads\Connect...tewayInterface::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...
226
        }catch (Exception $e){
227
            throw new TinymengException($e->getMessage());
228
        }
229
    }
230
231
    /**
232
     * 写入文件流
233
     * @param string $path
234
     * @param resource $resource
235
     * @param array $option
236
     * @return array|bool|false
237
     * @throws TinymengException
238
     */
239
    public function writeStream($path, $resource, $option=[])
240
    {
241
        try{
242
            $path = static::normalizerPath($path);
243
            //获得一个临时文件
244
            $tmpfname = FileFunction::getTmpFile();
245
246
            // 将资源流写入临时文件
247
            $contents = stream_get_contents($resource);
248
            file_put_contents($tmpfname, $contents);
249
250
            $params = array_merge([
251
                'Bucket' => $this->bucket,
252
                'Key' => $path,
253
                'Body' => fopen($tmpfname, 'rb')
254
            ], $option);
255
            
256
            $this->getClient()->putObject($params);
257
258
            //删除临时文件
259
            FileFunction::deleteTmpFile($tmpfname);
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 tinymeng\uploads\Connect...nterface::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...
261
        } catch (Exception $e){
262
            throw new TinymengException($e->getMessage());
263
        }
264
    }
265
266
    /**
267
     * Name: 上传文件
268
     * Author: Tinymeng <[email protected]>
269
     * @param $path
270
     * @param $tmpfname
271
     * @param array $option
272
     * @return array 返回文件信息,包含 url, etag, size 等
273
     * @throws TinymengException
274
     */
275
    public function uploadFile($path, $tmpfname, $option = []){
276
        try{
277
            $path = static::normalizerPath($path);
278
            if (!file_exists($tmpfname)) {
279
                throw new TinymengException("文件不存在: {$tmpfname}");
280
            }
281
            
282
            $params = array_merge([
283
                'Bucket' => $this->bucket,
284
                'Key' => $path,
285
                'Body' => fopen($tmpfname, 'rb')
286
            ], $option);
287
            
288
            $result = $this->getClient()->putObject($params);
289
            
290
            if ($result === false || $result === null) {
291
                throw new TinymengException("文件上传失败");
292
            }
293
            
294
            // 构建返回信息
295
            $fileInfo = [
296
                'success' => true,
297
                'path' => $path,
298
                'key' => $path,
299
                'etag' => isset($result['ETag']) ? trim($result['ETag'], '"') : '',
300
                'size' => filesize($tmpfname),
301
            ];
302
            
303
            // 获取文件 URL
304
            try {
305
                $fileInfo['url'] = $this->getUrl($path, 0); // 0 表示永久 URL
306
            } catch (Exception $e) {
307
                // 如果获取 URL 失败,至少返回路径
308
                $fileInfo['url'] = $path;
309
            }
310
            
311
            // 添加其他可能的响应信息
312
            if (isset($result['Location'])) {
313
                $fileInfo['location'] = $result['Location'];
314
            }
315
            if (isset($result['RequestId'])) {
316
                $fileInfo['request_id'] = $result['RequestId'];
317
            }
318
            
319
            return $fileInfo;
320
        } catch (Exception $e){
321
            throw new TinymengException($e->getMessage());
322
        }
323
    }
324
325
    /**
326
     * 更新文件
327
     * @param string $path
328
     * @param string $contents
329
     * @return array|bool|false
330
     */
331
    public function update($path, $contents)
332
    {
333
        return $this->write($path, $contents);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->write($path, $contents) returns the type object which is incompatible with the documented return type array|boolean.
Loading history...
334
    }
335
336
    /**
337
     * 更新文件流
338
     * @param string $path
339
     * @param resource $resource
340
     * @return array|bool|false
341
     */
342
    public function updateStream($path, $resource){
343
        return $this->writeStream($path, $resource);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->writeStream($path, $resource) returns the type true which is incompatible with the return type mandated by tinymeng\uploads\Connect...terface::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...
344
    }
345
346
    /**
347
     * 列出目录文件
348
     * @param string $directory
349
     * @param bool|false $recursive
350
     * @return array
351
     * @throws TinymengException
352
     * @author Tinymeng <[email protected]>
353
     */
354
    public function listContents($directory = '', $recursive = false){
0 ignored issues
show
Unused Code introduced by
The parameter $recursive 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

354
    public function listContents($directory = '', /** @scrutinizer ignore-unused */ $recursive = false){

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...
355
        try{
356
            $directory = static::normalizerPath($directory, true);
357
358
            $params = [
359
                'Bucket' => $this->bucket,
360
                'Delimiter' => '/',
361
                'Prefix'    => $directory,
362
                'MaxKeys'  => isset($this->config['max_keys']) ? (int)$this->config['max_keys'] : 1000,
363
            ];
364
            
365
            if (!empty($directory)) {
366
                $params['Marker'] = '';
367
            }
368
369
            $result_obj = $this->getClient()->listObjects($params);
370
371
            $file_list  = isset($result_obj['Contents']) ? $result_obj['Contents'] : [];//文件列表
372
            $dir_list   = isset($result_obj['CommonPrefixes']) ? $result_obj['CommonPrefixes'] : [];//文件夹列表
373
            $data       = [];
374
375
            if (is_array($dir_list) && count($dir_list) > 0 ) {
376
                foreach ($dir_list as $key => $dir) {
377
                    $prefix = isset($dir['Prefix']) ? $dir['Prefix'] : (is_string($dir) ? $dir : '');
378
                    $data[] = [
379
                        'path'      => $prefix,
380
                        'prefix'    => $params['Prefix'],
381
                        'marker'    => isset($params['Marker']) ? $params['Marker'] : '',
382
                        'file_type' => self::FILE_TYPE_DIR
383
                    ];
384
                }
385
            }
386
387
            if (is_array($file_list) && count($file_list) > 0 ) {
388
                foreach ($file_list as $key => $file) {
389
                    $fileKey = isset($file['Key']) ? $file['Key'] : (is_string($file) ? $file : '');
390
                    if ($fileKey == $directory) {
391
                        continue; // 跳过目录本身
392
                    }
393
                    $data[] = [
394
                        'path'              => $fileKey,
395
                        'last_modified'     => isset($file['LastModified']) ? $file['LastModified'] : '',
396
                        'e_tag'             => isset($file['ETag']) ? $file['ETag'] : '',
397
                        'file_size'         => isset($file['Size']) ? $file['Size'] : 0,
398
                        'prefix'            => $params['Prefix'],
399
                        'marker'            => isset($params['Marker']) ? $params['Marker'] : '',
400
                        'file_type'         => self::FILE_TYPE_FILE,
401
                    ];
402
                }
403
            }
404
405
            return $data;
406
        }catch (Exception $e){
407
            throw new TinymengException($e->getMessage());
408
        }
409
    }
410
411
    /**
412
     * 获取资源的元信息,但不返回文件内容
413
     * @param $path
414
     * @return array|bool
415
     * @throws TinymengException
416
     * @author Tinymeng <[email protected]>
417
     */
418
    public function getMetadata($path)
419
    {
420
        try {
421
            $path = static::normalizerPath($path);
422
            $params = array(
423
                'Bucket' => $this->bucket,
424
                'Key' => $path
425
            );
426
            $result = $this->getClient()->headObject($params);
427
            if ( !empty($result) ) {
428
                return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type object which is incompatible with the documented return type array|boolean.
Loading history...
429
            }
430
        }catch (Exception $e) {
431
            throw new TinymengException($e->getMessage());
432
        }
433
        return false;
434
    }
435
436
    /**
437
     * 获得文件大小
438
     * @param string $path
439
     * @return array
440
     * @author Tinymeng <[email protected]>
441
     */
442
    public function getSize($path)
443
    {
444
        $file_info = $this->getMetadata($path);
445
        $contentLength = isset($file_info['ContentLength']) ? $file_info['ContentLength'] : (isset($file_info['content-length']) ? $file_info['content-length'] : 0);
446
        return $file_info != false && $contentLength > 0 ? [ 'size' => $contentLength ] : ['size' => 0];
447
    }
448
449
    /**
450
     * 获得文件Mime类型
451
     * @param string $path
452
     * @return mixed string|null
453
     * @author Tinymeng <[email protected]>
454
     */
455
    public function getMimetype($path)
456
    {
457
        $file_info = $this->getMetadata($path);
458
        $contentType = isset($file_info['ContentType']) ? $file_info['ContentType'] : (isset($file_info['content-type']) ? $file_info['content-type'] : '');
459
        return $file_info != false && !empty($contentType) ? [ 'mimetype' => $contentType ] : false;
460
    }
461
462
    /**
463
     * 获得文件最后修改时间
464
     * @param string $path
465
     * @return array 时间戳
466
     * @author Tinymeng <[email protected]>
467
     */
468
    public function getTimestamp($path){
469
        $file_info = $this->getMetadata($path);
470
        $lastModified = isset($file_info['LastModified']) ? $file_info['LastModified'] : (isset($file_info['last-modified']) ? $file_info['last-modified'] : '');
471
        return $file_info != false && !empty($lastModified)
472
            ? ['timestamp' => is_numeric($lastModified) ? $lastModified : strtotime($lastModified) ]
473
            : ['timestamp' => 0 ];
474
    }
475
476
    /**
477
     * 获得文件模式 (未实现)
478
     * @param string $path
479
     * @author Tinymeng <[email protected]>
480
     * @return string
481
     */
482
    public function getVisibility($path){
0 ignored issues
show
Unused Code introduced by
The parameter $path 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

482
    public function getVisibility(/** @scrutinizer ignore-unused */ $path){

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...
483
        return self::VISIBILITY_PUBLIC;
484
    }
485
486
    /**
487
     * 重命名文件
488
     * @param string $path
489
     * @param string $newpath
490
     * @return bool
491
     * @throws TinymengException
492
     * @internal param $oldname
493
     * @internal param $newname
494
     * @author Tinymeng <[email protected]>
495
     */
496
    public function rename($path, $newpath)
497
    {
498
        try {
499
            /**
500
             * 如果是一个资源,请保持最后不是以"/"结尾!
501
             *
502
             */
503
            $path = static::normalizerPath($path);
504
            $newpath = static::normalizerPath($newpath);
505
506
            // 先复制文件
507
            $copyParams = [
508
                'Bucket' => $this->bucket,
509
                'Key' => $newpath,
510
                'CopySource' => $this->bucket . '/' . $path
511
            ];
512
            $this->getClient()->copyObject($copyParams);
513
            
514
            // 删除原文件
515
            return $this->delete($path);
516
        }catch (Exception $e){
517
            throw new TinymengException($e->getMessage());
518
        }
519
    }
520
521
    /**
522
     * 复制文件
523
     *
524
     * @param string $path
525
     * @param string $newpath
526
     * @return bool
527
     * @throws TinymengException
528
     * @author Tinymeng <[email protected]>
529
     */
530
    public function copy($path, $newpath)
531
    {
532
        try {
533
            $path = static::normalizerPath($path);
534
            $newpath = static::normalizerPath($newpath);
535
            
536
            $params = [
537
                'Bucket' => $this->bucket,
538
                'Key' => $newpath,
539
                'CopySource' => $this->bucket . '/' . $path
540
            ];
541
            $result = $this->getClient()->copyObject($params);
542
            return $result !== false;
543
        }catch (Exception $e){
544
            throw new TinymengException($e->getMessage());
545
        }
546
    }
547
548
    /**
549
     * 删除文件或者文件夹
550
     * @param string $path
551
     * @return bool
552
     * @throws TinymengException
553
     * @author Tinymeng <[email protected]>
554
     */
555
    public function delete($path)
556
    {
557
        try{
558
            $path = static::normalizerPath($path);
559
            $params = array(
560
                'Bucket' => $this->bucket,
561
                'Key' => $path
562
            );
563
            $result = $this->getClient()->deleteObject($params);
564
            return $result !== false;
565
        }catch (Exception $e){
566
            throw new TinymengException($e->getMessage());
567
        }
568
    }
569
570
    /**
571
     * 删除文件夹
572
     * @param string $path
573
     * @return mixed
574
     * @throws TinymengException
575
     * @author Tinymeng <[email protected]>
576
     */
577
    public function deleteDir($path)
578
    {
579
        try{
580
            //递归去删除全部文件
581
            return $this->recursiveDelete($path);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->recursiveDelete($path) targeting tinymeng\uploads\Gateways\Cos::recursiveDelete() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
582
        }catch (Exception $e){
583
            throw new TinymengException($e->getMessage());
584
        }
585
    }
586
587
    /**
588
     * 递归删除全部文件
589
     * @param $path
590
     * @author Tinymeng <[email protected]>
591
     */
592
    protected function recursiveDelete($path)
593
    {
594
        $file_list = $this->listContents($path);
595
596
        // 如果当前文件夹文件不为空,则直接去删除文件夹
597
        if ( is_array($file_list) && count($file_list) > 0 ) {
598
            foreach ($file_list as $file) {
599
                if ($file['path'] == $path) {
600
                    continue;
601
                }
602
                if ($file['file_type'] == self::FILE_TYPE_FILE) {
603
                    $this->delete($file['path']);
604
                } else {
605
                    $this->recursiveDelete($file['path']);
606
                }
607
            }
608
        }
609
610
        $params = array(
611
            'Bucket' => $this->bucket,
612
            'Key' => static::normalizerPath($path)
613
        );
614
        $this->getClient()->deleteObject($params);
615
    }
616
617
    /**
618
     * 创建文件夹
619
     * @param string $dirname
620
     * @return array|false
621
     * @throws TinymengException
622
     * @author Tinymeng <[email protected]>
623
     */
624
    public function createDir($dirname)
625
    {
626
        try{
627
            $dirname = static::normalizerPath($dirname, true);
628
            // COS 中创建文件夹实际上是通过上传一个以 "/" 结尾的空对象来实现的
629
            $params = [
630
                'Bucket' => $this->bucket,
631
                'Key' => $dirname,
632
                'Body' => ''
633
            ];
634
            $result = $this->getClient()->putObject($params);
635
            return $result !== false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result !== false returns the type boolean which is incompatible with the documented return type array|false.
Loading history...
636
        }catch (Exception $e){
637
            throw new TinymengException($e->getMessage());
638
        }
639
    }
640
641
    /**
642
     * 设置文件模式 (未实现)
643
     * @param string $path
644
     * @param string $visibility
645
     * @return bool
646
     * @author Tinymeng <[email protected]>
647
     */
648
    public function setVisibility($path, $visibility)
649
    {
650
        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 tinymeng\uploads\Connect...erface::setVisibility() 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...
651
    }
652
653
    /**
654
     * 获取当前文件的URL访问路径
655
     * @param  string $file 文件名
656
     * @param  integer $expire_at 有效期,单位:秒(0 表示永久有效,使用配置的 urlPrefix)
657
     * @return string
658
     * @throws TinymengException
659
     * @author Tinymeng <[email protected]>
660
     */
661
    public function getUrl($file, $expire_at = 3600)
662
    {
663
        try {
664
            $file = static::normalizerPath($file);
665
            
666
            // 如果配置了 urlPrefix 且不需要签名 URL,直接使用配置的 URL
667
            if ($expire_at == 0 && isset($this->config['urlPrefix'])) {
668
                return rtrim($this->config['urlPrefix'], '/') . '/' . ltrim($file, '/');
669
            }
670
            
671
            // 需要签名 URL 或没有配置 urlPrefix
672
            if ($expire_at > 0) {
673
                $params = [
674
                    'Bucket' => $this->bucket,
675
                    'Key' => $file
676
                ];
677
                
678
                // 生成预签名 URL
679
                $command = $this->getClient()->getCommand('getObject', $params);
680
                $request = $this->getClient()->createPresignedRequest($command, '+' . $expire_at . ' seconds');
681
                return (string)$request->getUri();
0 ignored issues
show
Bug introduced by
The method getUri() does not exist on GuzzleHttp\Promise\PromiseInterface. ( Ignorable by Annotation )

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

681
                return (string)$request->/** @scrutinizer ignore-call */ getUri();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getUri() does not exist on GuzzleHttp\Command\ResultInterface. ( Ignorable by Annotation )

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

681
                return (string)$request->/** @scrutinizer ignore-call */ getUri();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
682
            } else {
683
                // 没有配置 urlPrefix 且不需要签名,尝试使用 getObjectUrl
684
                try {
685
                    return $this->getClient()->getObjectUrl($this->bucket, $file);
686
                } catch (Exception $e) {
687
                    // 如果失败,使用配置的 urlPrefix
688
                    if (isset($this->config['urlPrefix'])) {
689
                        return rtrim($this->config['urlPrefix'], '/') . '/' . ltrim($file, '/');
690
                    }
691
                    throw $e;
692
                }
693
            }
694
        } catch (Exception $e) {
695
            // 如果生成签名 URL 失败,尝试使用配置的 urlPrefix
696
            if (isset($this->config['urlPrefix'])) {
697
                $file = static::normalizerPath($file);
698
                return rtrim($this->config['urlPrefix'], '/') . '/' . ltrim($file, '/');
699
            }
700
            throw new TinymengException($e->getMessage());
701
        }
702
    }
703
704
}
705