Passed
Push — master ( e83d3e...f8b104 )
by alpha
02:24
created

AliyunOssAdapter::getUrl()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 4
nc 8
nop 1
crap 20
1
<?php
2
3
namespace AlphaSnow\AliyunOss;
4
5
use Carbon\Carbon;
6
use League\Flysystem\Adapter\AbstractAdapter;
7
use League\Flysystem\Adapter\CanOverwriteFiles;
8
use League\Flysystem\AdapterInterface;
9
use League\Flysystem\Config;
10
use League\Flysystem\Util;
11
use League\Flysystem\FileNotFoundException;
12
use OSS\Core\OssException;
13
use OSS\OssClient;
14
use Illuminate\Support\Facades\Log;
15
16
class AliyunOssAdapter extends AbstractAdapter implements CanOverwriteFiles
17
{
18
    use AliyunOssAdapterTrait;
19
    use AliyunOssReadTrait;
20
21
    /**
22
     * @var bool
23
     */
24
    protected $debug;
25
    /**
26
     * @var array
27
     */
28
29
    /**
30
     * @var OssClient
31
     */
32
    protected $client;
33
    /**
34
     * @var string
35
     */
36
    protected $bucket;
37
    /**
38
     * @var string
39
     */
40
    protected $endPoint;
41
42
    /**
43
     * @var string
44
     */
45
    protected $cdnDomain;
46
47
    /**
48
     * @var bool
49
     */
50
    protected $ssl;
51
52
    /**
53
     * @var bool
54
     */
55
    protected $isCname;
56
57
    /**
58
     * @var array
59
     */
60
    protected $options = [
61
62
    ];
63
64
    /**
65
     * AliyunOssAdapter constructor.
66
     * @param OssClient $client
67
     * @param AliyunOssConfig $config
68
     * @param array $options
69
     */
70 1
    public function __construct(
71
        OssClient $client,
72
        AliyunOssConfig $config,
73
        array $options = []
74
    ) {
75 1
        $this->client = $client;
76 1
        $this->debug = $config->isDebug();
77 1
        $this->bucket = $config->getBucket();
78 1
        $this->endPoint = $config->getEndpoint();
79 1
        $this->ssl = $config->isSsl();
80 1
        $this->isCname = $config->isCname();
81 1
        $this->cdnDomain = $config->getCdnDomain();
82 1
        $this->options = array_merge($this->options, $options);
83 1
    }
84
85
    /**
86
     * Used by \Illuminate\Filesystem\FilesystemAdapter::url
87
     *
88
     * @param string $path
89
     * @return string
90
     */
91
    public function getUrl($path)
92
    {
93
        // if (!$this->has($path)) throw new FileNotFoundException($path.' not found');
94
        return ($this->ssl ? 'https://' : 'http://') . ($this->isCname ? ($this->cdnDomain == '' ? $this->endPoint : $this->cdnDomain) : $this->bucket . '.' . $this->endPoint) . '/' . ltrim($path, '/');
95
    }
96
97
    /**
98
     * Used by \Illuminate\Filesystem\FilesystemAdapter::temporaryUrl
99
     * Get a temporary URL for the file at the given path.
100
     *
101
     * @param string $path
102
     * @param \DateTimeInterface|int $expiration
103
     * @param array $options
104
     * @return string
105
     *
106
     * @throws \RuntimeException
107
     */
108
    public function getTemporaryUrl($path, $expiration, array $options = [])
109
    {
110
        if ($expiration instanceof Carbon) {
111
            return $this->client->generatePresignedUrl($this->bucket, $path, $expiration->getTimestamp(), $options);
0 ignored issues
show
Documentation introduced by
$options is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
112
        }
113
        return $this->client->signUrl($this->bucket, $path, $expiration, $options);
0 ignored issues
show
Bug introduced by
It seems like $expiration defined by parameter $expiration on line 108 can also be of type object<DateTimeInterface>; however, OSS\OssClient::signUrl() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Documentation introduced by
$options is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
114
    }
115
116
    /**
117
     * 列举文件夹内文件列表;可递归获取子文件夹;
118
     * @param string $dirname 目录
119
     * @param bool $recursive 是否递归
120
     * @return mixed
121
     * @throws OssException
122
     */
123
    protected function listDirObjects($dirname = '', $recursive = false)
124
    {
125
        $delimiter = '/';
126
        $nextMarker = '';
127
        $maxkeys = 1000;
128
129
        //存储结果
130
        $result = [];
131
132
        while (true) {
133
            $options = [
134
                'delimiter' => $delimiter,
135
                'prefix' => $dirname,
136
                'max-keys' => $maxkeys,
137
                'marker' => $nextMarker,
138
            ];
139
140
            try {
141
                $listObjectInfo = $this->client->listObjects($this->bucket, $options);
142
            } catch (OssException $e) {
143
                $this->logErr(__FUNCTION__, $e);
144
                // return false;
145
                throw $e;
146
            }
147
148
            $nextMarker = $listObjectInfo->getNextMarker(); // 得到nextMarker,从上一次listObjects读到的最后一个文件的下一个文件开始继续获取文件列表
149
            $objectList = $listObjectInfo->getObjectList(); // 文件列表
150
            $prefixList = $listObjectInfo->getPrefixList(); // 目录列表
151
152
            if (!empty($objectList)) {
153
                foreach ($objectList as $objectInfo) {
154
                    $object = [];
155
                    $object['Prefix'] = $dirname;
156
                    $object['Key'] = $objectInfo->getKey();
157
                    $object['LastModified'] = $objectInfo->getLastModified();
158
                    $object['eTag'] = $objectInfo->getETag();
159
                    $object['Type'] = $objectInfo->getType();
160
                    $object['Size'] = $objectInfo->getSize();
161
                    $object['StorageClass'] = $objectInfo->getStorageClass();
162
163
                    $result['objects'][] = $object;
164
                }
165
            } else {
166
                $result["objects"] = [];
167
            }
168
169
            if (!empty($prefixList)) {
170
                foreach ($prefixList as $prefixInfo) {
171
                    $result['prefix'][] = $prefixInfo->getPrefix();
172
                }
173
            } else {
174
                $result['prefix'] = [];
175
            }
176
177
            //递归查询子目录所有文件
178
            if ($recursive) {
179
                foreach ($result['prefix'] as $pfix) {
180
                    $next = $this->listDirObjects($pfix, $recursive);
181
                    $result["objects"] = array_merge($result['objects'], $next["objects"]);
182
                }
183
            }
184
185
            //没有更多结果了
186
            if ($nextMarker === '') {
187
                break;
188
            }
189
        }
190
191
        return $result;
192
    }
193
194
    /**
195
     * @param string $path
196
     * @return array
197
     */
198
    protected function readObject($path)
199
    {
200
        $object = $this->applyPathPrefix($path);
201
        $result = [];
202
        $result['Body'] = $this->client->getObject($this->bucket, $object);
203
        $result = array_merge($result, ['type' => 'file']);
204
        return $this->normalizeResponse($result, $path);
205
    }
206
207
    /**
208
     * The the ACL visibility.
209
     *
210
     * @param string $path
211
     *
212
     * @return string
213
     */
214
    protected function getObjectACL($path)
215
    {
216
        $metadata = $this->getVisibility($path);
217
218
        return $metadata['visibility'] === AdapterInterface::VISIBILITY_PUBLIC ? OssClient::OSS_ACL_TYPE_PUBLIC_READ : OssClient::OSS_ACL_TYPE_PRIVATE;
219
    }
220
221
    /**
222
     * Normalize a result from OSS.
223
     *
224
     * @param array $object
225
     * @param string $path
226
     *
227
     * @return array file metadata
228
     */
229 4
    protected function normalizeResponse(array $object, $path = null)
230
    {
231 4
        $result = ['path' => $path ?: $this->removePathPrefix(isset($object['Key']) ? $object['Key'] : $object['Prefix'])];
232 4
        $result['dirname'] = Util::dirname($result['path']);
233
234 4
        if (isset($object['LastModified'])) {
235
            $result['timestamp'] = strtotime($object['LastModified']);
236
        }
237
238 4
        if (substr($result['path'], -1) === '/') {
239
            $result['type'] = 'dir';
240
            $result['path'] = rtrim($result['path'], '/');
241
242
            return $result;
243
        }
244
245 4
        $result = array_merge($result, Util::map($object, AliyunOssUtil::$resultMap), ['type' => 'file']);
246
247 4
        return $result;
248
    }
249
250
    /**
251
     * Get options for a OSS call. done
252
     *
253
     * @param array $options
254
     *
255
     * @return array OSS options
256
     */
257 4
    protected function getOptions(array $options = [], Config $config = null)
258
    {
259 4
        $options = array_merge($this->options, $options);
260
261 4
        if ($config) {
262 4
            $options = array_merge($options, $this->getOptionsFromConfig($config));
263
        }
264
265 4
        return array(OssClient::OSS_HEADERS => $options);
266
    }
267
268
    /**
269
     * Retrieve options from a Config instance. done
270
     *
271
     * @param Config $config
272
     *
273
     * @return array
274
     */
275 4
    protected function getOptionsFromConfig(Config $config)
276
    {
277 4
        $options = AliyunOssUtil::getHeadersFromConfig($config);
278
279
        // 常用 visibility mimetype
280 4
        if ($visibility = $config->get('visibility')) {
281
            // Object ACL优先级高于Bucket ACL。
282
            $options[OssClient::OSS_OBJECT_ACL] = $visibility === AdapterInterface::VISIBILITY_PUBLIC ? OssClient::OSS_ACL_TYPE_PUBLIC_READ : OssClient::OSS_ACL_TYPE_PRIVATE;
283
        }
284 4
        if ($mimetype = $config->get('mimetype')) {
285
            $options[OssClient::OSS_CONTENT_TYPE] = $mimetype;
286
        }
287
288 4
        return $options;
289
    }
290
291
    /**
292
     * @return OssClient
293
     */
294
    public function getClient()
295
    {
296
        return $this->client;
297
    }
298
299
    /**
300
     * @return string
301
     */
302
    public function getBucket()
303
    {
304
        return $this->bucket;
305
    }
306
307
    /**
308
     * @param string $func
309
     * @param \Exception $e
310
     */
311
    protected function logErr($func, $e)
312
    {
313
        if ($this->debug) {
314
            Log::error($func . ": FAILED");
315
            Log::error($e->getMessage());
316
        }
317
    }
318
}
319