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
|
|
|
/** |
19
|
|
|
* @var bool |
20
|
|
|
*/ |
21
|
|
|
protected $debug; |
22
|
|
|
/** |
23
|
|
|
* @var array |
24
|
|
|
*/ |
25
|
|
|
protected static $resultMap = [ |
26
|
|
|
'Body' => 'raw_contents', |
27
|
|
|
'Content-Length' => 'size', |
28
|
|
|
'ContentType' => 'mimetype', |
29
|
|
|
'Size' => 'size', |
30
|
|
|
'StorageClass' => 'storage_class', |
31
|
|
|
]; |
32
|
|
|
/** |
33
|
|
|
* @var array |
34
|
|
|
*/ |
35
|
|
|
protected static $metaOptions = [ |
36
|
|
|
'CacheControl', |
37
|
|
|
'Expires', |
38
|
|
|
'ServerSideEncryption', |
39
|
|
|
'Metadata', |
40
|
|
|
'ACL', |
41
|
|
|
'ContentType', |
42
|
|
|
'ContentDisposition', |
43
|
|
|
'ContentLanguage', |
44
|
|
|
'ContentEncoding', |
45
|
|
|
]; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var string[] |
49
|
|
|
*/ |
50
|
|
|
protected static $metaMap = [ |
51
|
|
|
'CacheControl' => 'Cache-Control', |
52
|
|
|
'Expires' => 'Expires', |
53
|
|
|
'ServerSideEncryption' => 'x-oss-server-side-encryption', |
54
|
|
|
'Metadata' => 'x-oss-metadata-directive', |
55
|
|
|
'ACL' => 'x-oss-object-acl', |
56
|
|
|
'ContentType' => 'Content-Type', |
57
|
|
|
'ContentDisposition' => 'Content-Disposition', |
58
|
|
|
'ContentLanguage' => 'response-content-language', |
59
|
|
|
'ContentEncoding' => 'Content-Encoding', |
60
|
|
|
]; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @var OssClient |
64
|
|
|
*/ |
65
|
|
|
protected $client; |
66
|
|
|
/** |
67
|
|
|
* @var string |
68
|
|
|
*/ |
69
|
|
|
protected $bucket; |
70
|
|
|
/** |
71
|
|
|
* @var string |
72
|
|
|
*/ |
73
|
|
|
protected $endPoint; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @var string |
77
|
|
|
*/ |
78
|
|
|
protected $cdnDomain; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var bool |
82
|
|
|
*/ |
83
|
|
|
protected $ssl; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @var bool |
87
|
|
|
*/ |
88
|
|
|
protected $isCname; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @var array |
92
|
|
|
*/ |
93
|
|
|
protected $options = [ |
94
|
|
|
// 'Multipart' => 128 |
95
|
|
|
]; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* AliyunOssAdapter constructor. |
99
|
|
|
* @param OssClient $client |
100
|
|
|
* @param AliyunOssConfig $config |
101
|
|
|
* @param array $options |
102
|
|
|
*/ |
103
|
2 |
|
public function __construct( |
104
|
|
|
OssClient $client, |
105
|
|
|
AliyunOssConfig $config, |
106
|
|
|
array $options = [] |
107
|
|
|
) { |
108
|
2 |
|
$this->client = $client; |
109
|
2 |
|
$this->debug = $config->isDebug(); |
110
|
2 |
|
$this->bucket = $config->getBucket(); |
111
|
2 |
|
$this->endPoint = $config->getEndpoint(); |
112
|
2 |
|
$this->ssl = $config->isSsl(); |
113
|
2 |
|
$this->isCname = $config->isCname(); |
114
|
2 |
|
$this->cdnDomain = $config->getCdnDomain(); |
115
|
2 |
|
$this->options = array_merge($this->options, $options); |
116
|
2 |
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* {@inheritdoc} |
120
|
|
|
*/ |
121
|
3 |
View Code Duplication |
public function write($path, $contents, Config $config) |
|
|
|
|
122
|
|
|
{ |
123
|
3 |
|
$object = $this->applyPathPrefix($path); |
124
|
3 |
|
$options = $this->getOptions([], $config); |
125
|
|
|
|
126
|
3 |
|
if (!isset($options[OssClient::OSS_LENGTH])) { |
127
|
3 |
|
$options[OssClient::OSS_LENGTH] = Util::contentSize($contents); |
128
|
|
|
} |
129
|
3 |
|
if (!isset($options[OssClient::OSS_CONTENT_TYPE])) { |
130
|
3 |
|
$options[OssClient::OSS_CONTENT_TYPE] = Util::guessMimeType($path, $contents); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
try { |
134
|
|
|
// https://help.aliyun.com/document_detail/31978.html |
135
|
3 |
|
$this->client->putObject($this->bucket, $object, $contents, $options); |
136
|
|
|
} catch (OssException $e) { |
137
|
|
|
$this->logErr(__FUNCTION__, $e); |
138
|
|
|
return false; |
139
|
|
|
} |
140
|
|
|
|
141
|
3 |
|
return $this->normalizeResponse($options, $path); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* {@inheritdoc} |
146
|
|
|
*/ |
147
|
1 |
|
public function writeStream($path, $resource, Config $config) |
148
|
|
|
{ |
149
|
1 |
|
$object = $this->applyPathPrefix($path); |
150
|
1 |
|
$options = $this->getOptions([], $config); |
151
|
|
|
|
152
|
|
|
try { |
153
|
|
|
// https://help.aliyun.com/document_detail/31959.html |
154
|
1 |
|
$this->client->uploadStream($this->bucket, $object, $resource, $options); |
155
|
|
|
} catch (OssException $e) { |
156
|
|
|
$this->logErr(__FUNCTION__, $e); |
157
|
|
|
return false; |
158
|
|
|
} |
159
|
|
|
|
160
|
1 |
|
return $this->normalizeResponse($options, $path); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* {@inheritdoc} |
165
|
|
|
*/ |
166
|
1 |
View Code Duplication |
public function writeFile($path, $filePath, Config $config) |
|
|
|
|
167
|
|
|
{ |
168
|
1 |
|
$object = $this->applyPathPrefix($path); |
169
|
1 |
|
$options = $this->getOptions([], $config); |
170
|
|
|
|
171
|
1 |
|
if (!isset($options[OssClient::OSS_CONTENT_TYPE])) { |
172
|
1 |
|
$options[OssClient::OSS_CHECK_MD5] = true; |
173
|
|
|
} |
174
|
1 |
|
if (!isset($options[OssClient::OSS_CONTENT_TYPE])) { |
175
|
1 |
|
$options[OssClient::OSS_CONTENT_TYPE] = Util::guessMimeType($path, ''); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
try { |
179
|
1 |
|
$this->client->uploadFile($this->bucket, $object, $filePath, $options); |
180
|
|
|
} catch (OssException $e) { |
181
|
|
|
$this->logErr(__FUNCTION__, $e); |
182
|
|
|
return false; |
183
|
|
|
} |
184
|
|
|
|
185
|
1 |
|
return $this->normalizeResponse($options, $path); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* {@inheritdoc} |
190
|
|
|
*/ |
191
|
|
View Code Duplication |
public function update($path, $contents, Config $config) |
|
|
|
|
192
|
|
|
{ |
193
|
|
|
if (!$config->has('visibility') && !$config->has('ACL')) { |
194
|
|
|
// 新文件未配置权限情况下,继承旧文件权限 |
195
|
|
|
$config->set(static::$metaMap['ACL'], $this->getObjectACL($path)); |
196
|
|
|
} |
197
|
|
|
// 允许覆盖同名文件 |
198
|
|
|
$config->set('x-oss-forbid-overwrite','false'); |
199
|
|
|
|
200
|
|
|
return $this->write($path, $contents, $config); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* {@inheritdoc} |
205
|
|
|
*/ |
206
|
|
View Code Duplication |
public function updateStream($path, $resource, Config $config) |
|
|
|
|
207
|
|
|
{ |
208
|
|
|
if (!$config->has('visibility') && !$config->has('ACL')) { |
209
|
|
|
// 新文件未配置权限情况下,继承旧文件权限 |
210
|
|
|
$config->set(static::$metaMap['ACL'], $this->getObjectACL($path)); |
211
|
|
|
} |
212
|
|
|
// 允许覆盖同名文件 |
213
|
|
|
$config->set('x-oss-forbid-overwrite','false'); |
214
|
|
|
|
215
|
|
|
return $this->writeStream($path, $resource, $config); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* {@inheritdoc} |
220
|
|
|
*/ |
221
|
|
|
public function rename($path, $newpath) |
222
|
|
|
{ |
223
|
|
|
if (!$this->copy($path, $newpath)) { |
224
|
|
|
return false; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
return $this->delete($path); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* {@inheritdoc} |
232
|
|
|
*/ |
233
|
|
View Code Duplication |
public function copy($path, $newpath) |
|
|
|
|
234
|
|
|
{ |
235
|
|
|
$object = $this->applyPathPrefix($path); |
236
|
|
|
$newObject = $this->applyPathPrefix($newpath); |
237
|
|
|
|
238
|
|
|
try { |
239
|
|
|
$this->client->copyObject($this->bucket, $object, $this->bucket, $newObject); |
240
|
|
|
} catch (OssException $e) { |
241
|
|
|
$this->logErr(__FUNCTION__, $e); |
242
|
|
|
return false; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
return true; |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* {@inheritdoc} |
250
|
|
|
*/ |
251
|
|
View Code Duplication |
public function delete($path) |
|
|
|
|
252
|
|
|
{ |
253
|
|
|
$bucket = $this->bucket; |
254
|
|
|
$object = $this->applyPathPrefix($path); |
255
|
|
|
|
256
|
|
|
try { |
257
|
|
|
$this->client->deleteObject($bucket, $object); |
258
|
|
|
} catch (OssException $e) { |
259
|
|
|
$this->logErr(__FUNCTION__, $e); |
260
|
|
|
return false; |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
return !$this->has($path); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* {@inheritdoc} |
268
|
|
|
*/ |
269
|
|
|
public function deleteDir($dirname) |
270
|
|
|
{ |
271
|
|
|
$dirname = rtrim($this->applyPathPrefix($dirname), '/') . '/'; |
272
|
|
|
$dirObjects = $this->listDirObjects($dirname, true); |
273
|
|
|
|
274
|
|
|
if (count($dirObjects['objects']) > 0) { |
275
|
|
|
$objects = []; |
276
|
|
|
foreach ($dirObjects['objects'] as $object) { |
277
|
|
|
$objects[] = $object['Key']; |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
try { |
281
|
|
|
$this->client->deleteObjects($this->bucket, $objects); |
282
|
|
|
} catch (OssException $e) { |
283
|
|
|
$this->logErr(__FUNCTION__, $e); |
284
|
|
|
return false; |
285
|
|
|
} |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
try { |
289
|
|
|
$this->client->deleteObject($this->bucket, $dirname); |
290
|
|
|
} catch (OssException $e) { |
291
|
|
|
$this->logErr(__FUNCTION__, $e); |
292
|
|
|
return false; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
return true; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* {@inheritdoc} |
300
|
|
|
*/ |
301
|
|
|
public function createDir($dirname, Config $config) |
302
|
|
|
{ |
303
|
|
|
$object = $this->applyPathPrefix($dirname); |
304
|
|
|
$options = $this->getOptionsFromConfig($config); |
305
|
|
|
|
306
|
|
|
try { |
307
|
|
|
$this->client->createObjectDir($this->bucket, $object, $options); |
308
|
|
|
} catch (OssException $e) { |
309
|
|
|
$this->logErr(__FUNCTION__, $e); |
310
|
|
|
return false; |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
return ['path' => $dirname, 'type' => 'dir']; |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* {@inheritdoc} |
318
|
|
|
*/ |
319
|
|
|
public function setVisibility($path, $visibility) |
320
|
|
|
{ |
321
|
|
|
$object = $this->applyPathPrefix($path); |
322
|
|
|
$acl = ($visibility === AdapterInterface::VISIBILITY_PUBLIC) ? OssClient::OSS_ACL_TYPE_PUBLIC_READ : OssClient::OSS_ACL_TYPE_PRIVATE; |
323
|
|
|
|
324
|
|
|
$this->client->putObjectAcl($this->bucket, $object, $acl); |
325
|
|
|
|
326
|
|
|
return compact('visibility'); |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* 列举文件夹内文件列表;可递归获取子文件夹; |
331
|
|
|
* @param string $dirname 目录 |
332
|
|
|
* @param bool $recursive 是否递归 |
333
|
|
|
* @return mixed |
334
|
|
|
* @throws OssException |
335
|
|
|
*/ |
336
|
|
|
public function listDirObjects($dirname = '', $recursive = false) |
337
|
|
|
{ |
338
|
|
|
$delimiter = '/'; |
339
|
|
|
$nextMarker = ''; |
340
|
|
|
$maxkeys = 1000; |
341
|
|
|
|
342
|
|
|
//存储结果 |
343
|
|
|
$result = []; |
344
|
|
|
|
345
|
|
|
while (true) { |
346
|
|
|
$options = [ |
347
|
|
|
'delimiter' => $delimiter, |
348
|
|
|
'prefix' => $dirname, |
349
|
|
|
'max-keys' => $maxkeys, |
350
|
|
|
'marker' => $nextMarker, |
351
|
|
|
]; |
352
|
|
|
|
353
|
|
|
try { |
354
|
|
|
$listObjectInfo = $this->client->listObjects($this->bucket, $options); |
355
|
|
|
} catch (OssException $e) { |
356
|
|
|
$this->logErr(__FUNCTION__, $e); |
357
|
|
|
// return false; |
358
|
|
|
throw $e; |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
$nextMarker = $listObjectInfo->getNextMarker(); // 得到nextMarker,从上一次listObjects读到的最后一个文件的下一个文件开始继续获取文件列表 |
362
|
|
|
$objectList = $listObjectInfo->getObjectList(); // 文件列表 |
363
|
|
|
$prefixList = $listObjectInfo->getPrefixList(); // 目录列表 |
364
|
|
|
|
365
|
|
|
if (!empty($objectList)) { |
366
|
|
|
foreach ($objectList as $objectInfo) { |
367
|
|
|
$object = []; |
368
|
|
|
$object['Prefix'] = $dirname; |
369
|
|
|
$object['Key'] = $objectInfo->getKey(); |
370
|
|
|
$object['LastModified'] = $objectInfo->getLastModified(); |
371
|
|
|
$object['eTag'] = $objectInfo->getETag(); |
372
|
|
|
$object['Type'] = $objectInfo->getType(); |
373
|
|
|
$object['Size'] = $objectInfo->getSize(); |
374
|
|
|
$object['StorageClass'] = $objectInfo->getStorageClass(); |
375
|
|
|
|
376
|
|
|
$result['objects'][] = $object; |
377
|
|
|
} |
378
|
|
|
} else { |
379
|
|
|
$result["objects"] = []; |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
if (!empty($prefixList)) { |
383
|
|
|
foreach ($prefixList as $prefixInfo) { |
384
|
|
|
$result['prefix'][] = $prefixInfo->getPrefix(); |
385
|
|
|
} |
386
|
|
|
} else { |
387
|
|
|
$result['prefix'] = []; |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
//递归查询子目录所有文件 |
391
|
|
|
if ($recursive) { |
392
|
|
|
foreach ($result['prefix'] as $pfix) { |
393
|
|
|
$next = $this->listDirObjects($pfix, $recursive); |
394
|
|
|
$result["objects"] = array_merge($result['objects'], $next["objects"]); |
395
|
|
|
} |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
//没有更多结果了 |
399
|
|
|
if ($nextMarker === '') { |
400
|
|
|
break; |
401
|
|
|
} |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
return $result; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* {@inheritdoc} |
409
|
|
|
*/ |
410
|
|
|
public function has($path) |
411
|
|
|
{ |
412
|
|
|
$object = $this->applyPathPrefix($path); |
413
|
|
|
|
414
|
|
|
return $this->client->doesObjectExist($this->bucket, $object); |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
/** |
418
|
|
|
* {@inheritdoc} |
419
|
|
|
*/ |
420
|
|
|
public function read($path) |
421
|
|
|
{ |
422
|
|
|
$result = $this->readObject($path); |
423
|
|
|
$result['contents'] = (string)$result['raw_contents']; |
424
|
|
|
unset($result['raw_contents']); |
425
|
|
|
return $result; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* {@inheritdoc} |
430
|
|
|
*/ |
431
|
|
|
public function readStream($path) |
432
|
|
|
{ |
433
|
|
|
$result = $this->readObject($path); |
434
|
|
|
$result['stream'] = $result['raw_contents']; |
435
|
|
|
rewind($result['stream']); |
436
|
|
|
// Ensure the EntityBody object destruction doesn't close the stream |
437
|
|
|
// $result['raw_contents']->detachStream(); |
438
|
|
|
unset($result['raw_contents']); |
439
|
|
|
|
440
|
|
|
return $result; |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
/** |
444
|
|
|
* {@inheritdoc} |
445
|
|
|
*/ |
446
|
|
|
public function listContents($directory = '', $recursive = false) |
447
|
|
|
{ |
448
|
|
|
$dirObjects = $this->listDirObjects($directory, true); |
449
|
|
|
$contents = $dirObjects["objects"]; |
450
|
|
|
|
451
|
|
|
$result = array_map([$this, 'normalizeResponse'], $contents); |
452
|
|
|
$result = array_filter($result, function ($value) { |
453
|
|
|
return $value['path'] !== false; |
454
|
|
|
}); |
455
|
|
|
|
456
|
|
|
return Util::emulateDirectories($result); |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
/** |
460
|
|
|
* {@inheritdoc} |
461
|
|
|
*/ |
462
|
|
View Code Duplication |
public function getMetadata($path) |
|
|
|
|
463
|
|
|
{ |
464
|
|
|
$object = $this->applyPathPrefix($path); |
465
|
|
|
|
466
|
|
|
try { |
467
|
|
|
$objectMeta = $this->client->getObjectMeta($this->bucket, $object); |
468
|
|
|
} catch (OssException $e) { |
469
|
|
|
$this->logErr(__FUNCTION__, $e); |
470
|
|
|
return false; |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
return $objectMeta; |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* {@inheritdoc} |
478
|
|
|
*/ |
479
|
|
|
public function getSize($path) |
480
|
|
|
{ |
481
|
|
|
$object = $this->getMetadata($path); |
482
|
|
|
$object['size'] = $object['content-length']; |
483
|
|
|
return $object; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* {@inheritdoc} |
488
|
|
|
*/ |
489
|
|
|
public function getMimetype($path) |
490
|
|
|
{ |
491
|
|
|
if ($object = $this->getMetadata($path)) { |
492
|
|
|
$object['mimetype'] = $object['content-type']; |
493
|
|
|
} |
494
|
|
|
return $object; |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
/** |
498
|
|
|
* {@inheritdoc} |
499
|
|
|
*/ |
500
|
|
|
public function getTimestamp($path) |
501
|
|
|
{ |
502
|
|
|
if ($object = $this->getMetadata($path)) { |
503
|
|
|
$object['timestamp'] = strtotime($object['last-modified']); |
504
|
|
|
} |
505
|
|
|
return $object; |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
/** |
509
|
|
|
* {@inheritdoc} |
510
|
|
|
*/ |
511
|
|
|
public function getVisibility($path) |
512
|
|
|
{ |
513
|
|
|
$object = $this->applyPathPrefix($path); |
514
|
|
|
try { |
515
|
|
|
$acl = $this->client->getObjectAcl($this->bucket, $object); |
516
|
|
|
} catch (OssException $e) { |
517
|
|
|
$this->logErr(__FUNCTION__, $e); |
518
|
|
|
return false; |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
if ($acl == OssClient::OSS_ACL_TYPE_PUBLIC_READ) { |
522
|
|
|
$res['visibility'] = AdapterInterface::VISIBILITY_PUBLIC; |
|
|
|
|
523
|
|
|
} else { |
524
|
|
|
$res['visibility'] = AdapterInterface::VISIBILITY_PRIVATE; |
|
|
|
|
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
return $res; |
528
|
|
|
} |
529
|
|
|
|
530
|
|
|
/** |
531
|
|
|
* @param string $path |
532
|
|
|
* @return array|null[]|string[] |
533
|
|
|
*/ |
534
|
|
|
protected function readObject($path) |
535
|
|
|
{ |
536
|
|
|
$object = $this->applyPathPrefix($path); |
537
|
|
|
$result = []; |
538
|
|
|
$result['Body'] = $this->client->getObject($this->bucket, $object); |
539
|
|
|
$result = array_merge($result, ['type' => 'file']); |
540
|
|
|
return $this->normalizeResponse($result, $path); |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
/** |
544
|
|
|
* @param string $path |
545
|
|
|
* @return string |
546
|
|
|
*/ |
547
|
|
|
public function getUrl($path) |
548
|
|
|
{ |
549
|
|
|
// if (!$this->has($path)) throw new FileNotFoundException($path.' not found'); |
550
|
|
|
return ($this->ssl ? 'https://' : 'http://') . ($this->isCname ? ($this->cdnDomain == '' ? $this->endPoint : $this->cdnDomain) : $this->bucket . '.' . $this->endPoint) . '/' . ltrim($path, '/'); |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
/** |
554
|
|
|
* Get a temporary URL for the file at the given path. |
555
|
|
|
* |
556
|
|
|
* @param string $path |
557
|
|
|
* @param \DateTimeInterface|int $expiration |
558
|
|
|
* @param array $options |
559
|
|
|
* @return string |
560
|
|
|
* |
561
|
|
|
* @throws \RuntimeException |
562
|
|
|
*/ |
563
|
|
|
public function getTemporaryUrl($path, $expiration, array $options = []) |
564
|
|
|
{ |
565
|
|
|
if ($expiration instanceof Carbon) { |
566
|
|
|
return $this->client->generatePresignedUrl($this->bucket, $path, $expiration->getTimestamp(), $options); |
|
|
|
|
567
|
|
|
} |
568
|
|
|
return $this->client->signUrl($this->bucket, $path, $expiration, $options); |
|
|
|
|
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
/** |
572
|
|
|
* The the ACL visibility. |
573
|
|
|
* |
574
|
|
|
* @param string $path |
575
|
|
|
* |
576
|
|
|
* @return string |
577
|
|
|
*/ |
578
|
|
|
protected function getObjectACL($path) |
579
|
|
|
{ |
580
|
|
|
$metadata = $this->getVisibility($path); |
581
|
|
|
|
582
|
|
|
return $metadata['visibility'] === AdapterInterface::VISIBILITY_PUBLIC ? OssClient::OSS_ACL_TYPE_PUBLIC_READ : OssClient::OSS_ACL_TYPE_PRIVATE; |
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
/** |
586
|
|
|
* Normalize a result from OSS. |
587
|
|
|
* |
588
|
|
|
* @param array $object |
589
|
|
|
* @param string $path |
590
|
|
|
* |
591
|
|
|
* @return array file metadata |
592
|
|
|
*/ |
593
|
5 |
|
protected function normalizeResponse(array $object, $path = null) |
594
|
|
|
{ |
595
|
5 |
|
$result = ['path' => $path ?: $this->removePathPrefix(isset($object['Key']) ? $object['Key'] : $object['Prefix'])]; |
596
|
5 |
|
$result['dirname'] = Util::dirname($result['path']); |
597
|
|
|
|
598
|
5 |
|
if (isset($object['LastModified'])) { |
599
|
|
|
$result['timestamp'] = strtotime($object['LastModified']); |
600
|
|
|
} |
601
|
|
|
|
602
|
5 |
|
if (substr($result['path'], -1) === '/') { |
603
|
|
|
$result['type'] = 'dir'; |
604
|
|
|
$result['path'] = rtrim($result['path'], '/'); |
605
|
|
|
|
606
|
|
|
return $result; |
607
|
|
|
} |
608
|
|
|
|
609
|
5 |
|
$result = array_merge($result, Util::map($object, static::$resultMap), ['type' => 'file']); |
610
|
|
|
|
611
|
5 |
|
return $result; |
612
|
|
|
} |
613
|
|
|
|
614
|
|
|
/** |
615
|
|
|
* Get options for a OSS call. done |
616
|
|
|
* |
617
|
|
|
* @param array $options |
618
|
|
|
* |
619
|
|
|
* @return array OSS options |
620
|
|
|
*/ |
621
|
5 |
|
protected function getOptions(array $options = [], Config $config = null) |
622
|
|
|
{ |
623
|
5 |
|
$options = array_merge($this->options, $options); |
624
|
|
|
|
625
|
5 |
|
if ($config) { |
626
|
5 |
|
$options = array_merge($options, $this->getOptionsFromConfig($config)); |
627
|
|
|
} |
628
|
|
|
|
629
|
5 |
|
return array(OssClient::OSS_HEADERS => $options); |
630
|
|
|
} |
631
|
|
|
|
632
|
|
|
/** |
633
|
|
|
* Retrieve options from a Config instance. done |
634
|
|
|
* |
635
|
|
|
* @param Config $config |
636
|
|
|
* |
637
|
|
|
* @return array |
638
|
|
|
*/ |
639
|
5 |
|
protected function getOptionsFromConfig(Config $config) |
640
|
|
|
{ |
641
|
5 |
|
$options = []; |
642
|
|
|
|
643
|
5 |
|
foreach (static::$metaOptions as $option) { |
644
|
5 |
|
if (!$config->has($option)) { |
645
|
5 |
|
continue; |
646
|
|
|
} |
647
|
|
|
$options[static::$metaMap[$option]] = $config->get($option); |
648
|
|
|
} |
649
|
|
|
|
650
|
5 |
|
if ($visibility = $config->get('visibility')) { |
651
|
|
|
// Object ACL优先级高于Bucket ACL。 |
652
|
1 |
|
$options[OssClient::OSS_OBJECT_ACL] = $visibility === AdapterInterface::VISIBILITY_PUBLIC ? OssClient::OSS_ACL_TYPE_PUBLIC_READ : OssClient::OSS_ACL_TYPE_PRIVATE; |
653
|
|
|
} |
654
|
|
|
|
655
|
5 |
|
if ($mimetype = $config->get('mimetype')) { |
656
|
|
|
$options[OssClient::OSS_CONTENT_TYPE] = $mimetype; |
657
|
|
|
} |
658
|
|
|
|
659
|
5 |
|
return $options; |
660
|
|
|
} |
661
|
|
|
|
662
|
|
|
/** |
663
|
|
|
* @param string $func |
664
|
|
|
* @param \Exception $e |
665
|
|
|
*/ |
666
|
|
|
protected function logErr($func, $e) |
667
|
|
|
{ |
668
|
|
|
if ($this->debug) { |
669
|
|
|
Log::error($func . ": FAILED"); |
670
|
|
|
Log::error($e->getMessage()); |
671
|
|
|
} |
672
|
|
|
} |
673
|
|
|
} |
674
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.