├── _config.yml
├── .gitignore
├── .styleci.yml
├── composer.json
├── phpunit.xml.dist
├── CHANGELOG.md
├── LICENSE.md
├── _ide_helper.php
├── src
├── Plugins
│ ├── SignedDownloadUrl.php
│ └── PutFile.php
├── AliyunOssServiceProvider.php
└── AliyunOssAdapter.php
├── README.md
├── .php_cs
└── tests
└── AliyunOssAdapterTest.php
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.phar
3 | composer.lock
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: laravel
2 | finder:
3 | not-name:
4 | - "_ide_helper.php"
5 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "apollopy/flysystem-aliyun-oss",
3 | "description": "This is a Flysystem adapter for the Aliyun OSS ~2.3",
4 | "license": "MIT",
5 | "authors": [
6 | {
7 | "name": "ApolloPY",
8 | "email": "ApolloPY@Gmail.com"
9 | }
10 | ],
11 | "require": {
12 | "php": ">=5.5.9",
13 | "league/flysystem": "~1.0",
14 | "aliyuncs/oss-sdk-php": "~2.3"
15 | },
16 | "require-dev": {
17 | "phpunit/phpunit": "~4.0"
18 | },
19 | "autoload": {
20 | "psr-4": {
21 | "ApolloPY\\Flysystem\\AliyunOss\\": "src/"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
20 |
21 | ./src/
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # ChangeLog
2 |
3 | ## 1.1.3
4 |
5 | * 支持 config/filesystems.php 里配置目录前缀 (使用场景: 希望开发环境下上传的文件不要覆盖业务环境下上传的文件)
6 |
7 | ## 1.1.2
8 |
9 | * Plugin/PrivateDownloadUrl 改为 Plugin/SignedDownloadUrl, 获得带签名且有过期时间的下载地址, 支持自定义 hostname 和选择是否使用 ssl (使用场景: 远程配置上传地址为内网, 但需要获得外网的临时下载地址提供给用户)
10 |
11 | ## 1.1.1
12 |
13 | * ~~添加 Plugin/PrivateDownloadUrl, 获得私有下载地址~~ **(该方法设计不成熟, 下一版本就改掉了, 如要使用此功能, 建议升级 1.1.2)**
14 | * 添加 _ide_helper.php, 让 FilesystemAdapter __call 调用 Plugin 时, IDE 有代码提示
15 |
16 | ## 1.1.0
17 |
18 | * 添加 Plugin/PutFile 方法, 支持指定本地文件路径上传到 OSS
19 | * AliyunOssAdapter 支持外部传入 mimetype 和 size 两个参数
20 |
21 | ## 1.0.0
22 |
23 | * AliyunOssAdapter 实现 League\Flysystem\Adapter\AbstractAdapter 定义的所有接口
24 | * 添加 AliyunOssServiceProvider 用于 Laravel 注册
25 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | #The MIT License (MIT)
2 |
3 | Copyright (c) ApolloPY
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/_ide_helper.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class SignedDownloadUrl extends AbstractPlugin
14 | {
15 | /**
16 | * Get the method name.
17 | *
18 | * @return string
19 | */
20 | public function getMethod()
21 | {
22 | return 'signedDownloadUrl';
23 | }
24 |
25 | /**
26 | * Handle.
27 | *
28 | * @param string $path
29 | * @param int $expires
30 | * @param string $host_name
31 | * @param bool $use_ssl
32 | * @return string|false
33 | */
34 | public function handle($path, $expires = 3600, $host_name = '', $use_ssl = false)
35 | {
36 | if (! method_exists($this->filesystem, 'getAdapter')) {
37 | return false;
38 | }
39 |
40 | if (! method_exists($this->filesystem->getAdapter(), 'getSignedDownloadUrl')) {
41 | return false;
42 | }
43 |
44 | return $this->filesystem->getAdapter()->getSignedDownloadUrl($path, $expires, $host_name, $use_ssl);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Plugins/PutFile.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | class PutFile extends AbstractPlugin
15 | {
16 | /**
17 | * Get the method name.
18 | *
19 | * @return string
20 | */
21 | public function getMethod()
22 | {
23 | return 'putFile';
24 | }
25 |
26 | /**
27 | * Handle.
28 | *
29 | * @param string $path
30 | * @param string $localFilePath
31 | * @param array $config
32 | * @return bool
33 | */
34 | public function handle($path, $localFilePath, array $config = [])
35 | {
36 | if (! method_exists($this->filesystem, 'getAdapter')) {
37 | return false;
38 | }
39 |
40 | if (! method_exists($this->filesystem->getAdapter(), 'putFile')) {
41 | return false;
42 | }
43 |
44 | $config = new Config($config);
45 | if (method_exists($this->filesystem, 'getConfig')) {
46 | $config->setFallback($this->filesystem->getConfig());
47 | }
48 |
49 | return (bool) $this->filesystem->getAdapter()->putFile($path, $localFilePath, $config);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/AliyunOssServiceProvider.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class AliyunOssServiceProvider extends ServiceProvider
18 | {
19 | /**
20 | * Perform post-registration booting of services.
21 | *
22 | * @return void
23 | */
24 | public function boot()
25 | {
26 | Storage::extend('oss', function ($app, $config) {
27 | $accessId = $config['access_id'];
28 | $accessKey = $config['access_key'];
29 | $endPoint = $config['endpoint'];
30 | $bucket = $config['bucket'];
31 |
32 | $prefix = null;
33 | if (isset($config['prefix'])) {
34 | $prefix = $config['prefix'];
35 | }
36 |
37 | $client = new OssClient($accessId, $accessKey, $endPoint);
38 | $adapter = new AliyunOssAdapter($client, $bucket, $prefix);
39 |
40 | $filesystem = new Filesystem($adapter);
41 | $filesystem->addPlugin(new PutFile());
42 | $filesystem->addPlugin(new SignedDownloadUrl());
43 |
44 | return $filesystem;
45 | });
46 | }
47 |
48 | /**
49 | * Register bindings in the container.
50 | *
51 | * @return void
52 | */
53 | public function register()
54 | {
55 | //
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flysystem Adapter for Aliyun OSS.
2 |
3 | This is a Flysystem adapter for the Aliyun OSS ~2.3
4 |
5 | inspire by [aobozhang/aliyun-oss-adapter](https://github.com/aobozhang/aliyun-oss-adapter)
6 |
7 | ## Installation
8 |
9 | ```bash
10 | composer require apollopy/flysystem-aliyun-oss
11 | ```
12 |
13 | ## for Laravel
14 |
15 | This service provider must be registered.
16 |
17 | ```php
18 | // config/app.php
19 |
20 | 'providers' => [
21 | '...',
22 | ApolloPY\Flysystem\AliyunOss\AliyunOssServiceProvider::class,
23 | ];
24 | ```
25 |
26 | edit the config file: config/filesystems.php
27 |
28 | add config
29 |
30 | ```php
31 | 'oss' => [
32 | 'driver' => 'oss',
33 | 'access_id' => env('OSS_ACCESS_ID','your id'),
34 | 'access_key' => env('OSS_ACCESS_KEY','your key'),
35 | 'bucket' => env('OSS_BUCKET','your bucket'),
36 | 'endpoint' => env('OSS_ENDPOINT','your endpoint'),
37 | 'prefix' => env('OSS_PREFIX', ''), // optional
38 | ],
39 | ```
40 |
41 | change default to oss
42 |
43 | ```php
44 | 'default' => 'oss'
45 | ```
46 |
47 | ## Use
48 |
49 | see [Laravel wiki](https://laravel.com/docs/5.1/filesystem)
50 |
51 | ## Plugins
52 |
53 | inspire by [itbdw/laravel-storage-qiniu](https://github.com/itbdw/laravel-storage-qiniu)
54 |
55 | ```php
56 | Storage::disk('oss')->putFile($md5_path, '/local_file_path/1.png', ['mimetype' => 'image/png','filename' => 'filename_by_down.png']);
57 |
58 | Storage::disk('oss')->signedDownloadUrl($path, 3600, 'oss-cn-beijing.aliyuncs.com', true);
59 | ```
60 |
61 | ## IDE Helper
62 |
63 | if installed [barryvdh/laravel-ide-helper](https://github.com/barryvdh/laravel-ide-helper)
64 |
65 | edit the config file: config/ide-helper.php
66 |
67 | ```php
68 | 'interfaces' => [
69 | '\Illuminate\Contracts\Filesystem\Filesystem' => ApolloPY\Flysystem\AliyunOss\FilesystemAdapter::class,
70 | ],
71 | ```
72 |
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
1 | in(__DIR__)
9 | ;
10 |
11 | $fixers = '
12 | -psr0
13 | align_double_arrow
14 | class_definition
15 | new_with_braces
16 | no_closing_tag
17 | ordered_imports
18 | phpdoc_align
19 |
20 | binary_operator_spaces
21 | blank_line_after_namespace
22 | blank_line_after_opening_tag
23 | blank_line_before_return
24 | braces
25 | cast_spaces
26 | concat_without_spaces
27 | elseif
28 | encoding
29 | full_opening_tag
30 | function_declaration
31 | function_typehint_space
32 | hash_to_slash_comment
33 | heredoc_to_nowdoc
34 | include
35 | lowercase_cast
36 | lowercase_constants
37 | lowercase_keywords
38 | method_argument_space
39 | method_separation
40 | native_function_casing
41 | no_alias_functions
42 | no_blank_lines_after_class_opening
43 | no_blank_lines_after_phpdoc
44 | no_blank_lines_between_uses
45 | no_duplicate_semicolons
46 | no_empty_phpdoc
47 | no_extra_consecutive_blank_lines
48 | no_leading_import_slash
49 | no_leading_namespace_whitespace
50 | no_multiline_whitespace_around_double_arrow
51 | no_multiline_whitespace_before_semicolons
52 | no_short_bool_cast
53 | no_singleline_whitespace_before_semicolons
54 | no_spaces_after_function_name
55 | no_spaces_inside_parenthesis
56 | no_tab_indentation
57 | no_trailing_comma_in_list_call
58 | no_trailing_comma_in_singleline_array
59 | no_trailing_whitespace
60 | no_trailing_whitespace_in_comment
61 | no_unneeded_control_parentheses
62 | no_unreachable_default_argument_value
63 | no_unused_imports
64 | no_useless_return
65 | no_whitespace_before_comma_in_array
66 | no_whitespace_in_blank_lines
67 | not_operator_with_successor_space
68 | object_operator_without_whitespace
69 | phpdoc_indent
70 | phpdoc_inline_tag
71 | phpdoc_no_access
72 | phpdoc_no_package
73 | phpdoc_scalar
74 | phpdoc_single_line_var_spacing
75 | phpdoc_summary
76 | phpdoc_to_comment
77 | phpdoc_trim
78 | phpdoc_type_to_var
79 | phpdoc_types
80 | phpdoc_var_without_name
81 | print_to_echo
82 | psr4
83 | self_accessor
84 | short_array_syntax
85 | short_scalar_cast
86 | simplified_null_return
87 | single_blank_line_at_eof
88 | single_blank_line_before_namespace
89 | single_import_per_statement
90 | single_line_after_imports
91 | single_quote
92 | space_after_semicolon
93 | standardize_not_equals
94 | switch_case_semicolon_to_colon
95 | switch_case_space
96 | ternary_operator_spaces
97 | trailing_comma_in_multiline_array
98 | trim_array_spaces
99 | unalign_equals
100 | unary_operator_spaces
101 | unix_line_endings
102 | visibility_required
103 | whitespace_after_comma_in_array
104 | ';
105 |
106 | return Symfony\CS\Config\Config::create()
107 | ->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
108 | ->fixers(array_values(array_filter(explode("\n", $fixers))))
109 | ->finder($finder);
--------------------------------------------------------------------------------
/tests/AliyunOssAdapterTest.php:
--------------------------------------------------------------------------------
1 | deleteDir('test');
34 | $adapter->setPathPrefix('test');
35 |
36 | $filesystem = new Filesystem($adapter);
37 | $filesystem->addPlugin(new PutFile());
38 |
39 | $this->filesystem = $filesystem;
40 | }
41 |
42 | public function testPutFile()
43 | {
44 | $tmpfile = tempnam(sys_get_temp_dir(), 'OSS');
45 | file_put_contents($tmpfile, 'put file');
46 |
47 | $this->assertTrue($this->filesystem->putFile('1.txt', $tmpfile));
48 | $this->assertSame('put file', $this->filesystem->read('1.txt'));
49 |
50 | unlink($tmpfile);
51 | $this->filesystem->delete('1.txt');
52 | }
53 |
54 | /**
55 | * 1.txt.
56 | */
57 | public function testWrite()
58 | {
59 | $this->assertTrue($this->filesystem->write('1.txt', '123'));
60 | }
61 |
62 | /**
63 | * 1.txt
64 | * 2.txt.
65 | */
66 | public function testWriteStream()
67 | {
68 | $stream = tmpfile();
69 | fwrite($stream, 'OSS text');
70 | rewind($stream);
71 |
72 | $this->assertTrue($this->filesystem->writeStream('2.txt', $stream));
73 |
74 | fclose($stream);
75 | }
76 |
77 | /**
78 | * 1.txt
79 | * 2.txt.
80 | */
81 | public function testUpdate()
82 | {
83 | $this->assertTrue($this->filesystem->update('1.txt', '456'));
84 | }
85 |
86 | /**
87 | * 1.txt
88 | * 2.txt.
89 | */
90 | public function testUpdateStream()
91 | {
92 | $stream = tmpfile();
93 | fwrite($stream, 'OSS text2');
94 | rewind($stream);
95 |
96 | $this->assertTrue($this->filesystem->updateStream('2.txt', $stream));
97 |
98 | fclose($stream);
99 | }
100 |
101 | public function testHas()
102 | {
103 | $this->assertTrue($this->filesystem->has('1.txt'));
104 | $this->assertFalse($this->filesystem->has('3.txt'));
105 | }
106 |
107 | /**
108 | * 1.txt
109 | * 2.txt
110 | * 3.txt.
111 | */
112 | public function testCopy()
113 | {
114 | $this->assertTrue($this->filesystem->copy('1.txt', '3.txt'));
115 | $this->assertTrue($this->filesystem->has('3.txt'));
116 | }
117 |
118 | /**
119 | * 1.txt
120 | * 2.txt.
121 | */
122 | public function testDelete()
123 | {
124 | $this->assertTrue($this->filesystem->delete('3.txt'));
125 | $this->assertFalse($this->filesystem->has('3.txt'));
126 | }
127 |
128 | /**
129 | * 3.txt
130 | * 2.txt.
131 | */
132 | public function testRename()
133 | {
134 | $this->assertTrue($this->filesystem->rename('1.txt', '3.txt'));
135 | $this->assertFalse($this->filesystem->has('1.txt'));
136 | $this->assertTrue($this->filesystem->has('3.txt'));
137 | }
138 |
139 | /**
140 | * 3.txt
141 | * 2.txt
142 | * test/1.txt.
143 | */
144 | public function testCreateDir()
145 | {
146 | $this->assertTrue($this->filesystem->createDir('test'));
147 | $this->assertTrue($this->filesystem->copy('2.txt', 'test/1.txt'));
148 | }
149 |
150 | public function testListContents()
151 | {
152 | $list = $this->filesystem->listContents('');
153 | $this->assertArraySubset(
154 | [
155 | [
156 | 'type' => 'file',
157 | 'path' => '2.txt',
158 | ],
159 | [
160 | 'type' => 'file',
161 | 'path' => '3.txt',
162 | ],
163 | [
164 | 'type' => 'dir',
165 | 'path' => 'test',
166 | ],
167 | ],
168 | $list
169 | );
170 |
171 | $list = $this->filesystem->listContents('', true);
172 | $this->assertArraySubset(
173 | [
174 | [
175 | 'type' => 'file',
176 | 'path' => '2.txt',
177 | ],
178 | [
179 | 'type' => 'file',
180 | 'path' => '3.txt',
181 | ],
182 | [
183 | 'type' => 'dir',
184 | 'path' => 'test',
185 | ],
186 | [
187 | 'type' => 'file',
188 | 'path' => 'test/1.txt',
189 | ],
190 | ],
191 | $list
192 | );
193 | }
194 |
195 | /**
196 | * 3.txt
197 | * 2.txt.
198 | */
199 | public function testDeleteDir()
200 | {
201 | $this->assertTrue($this->filesystem->deleteDir('test'));
202 | $this->assertFalse($this->filesystem->has('test/'));
203 | }
204 |
205 | public function testRead()
206 | {
207 | $this->assertInternalType('string', $this->filesystem->read('2.txt'));
208 | }
209 |
210 | public function testReadStream()
211 | {
212 | $this->assertInternalType('resource', $this->filesystem->readStream('2.txt'));
213 | }
214 |
215 | public function testGetMetadata()
216 | {
217 | $data = $this->filesystem->getMetadata('2.txt');
218 |
219 | $this->assertArrayHasKey('type', $data);
220 | $this->assertArrayHasKey('dirname', $data);
221 | $this->assertArrayHasKey('path', $data);
222 | $this->assertArrayHasKey('timestamp', $data);
223 | $this->assertArrayHasKey('mimetype', $data);
224 | $this->assertArrayHasKey('size', $data);
225 | }
226 |
227 | public function testGetMimetype()
228 | {
229 | $this->assertInternalType('string', $this->filesystem->getMimetype('2.txt'));
230 | }
231 |
232 | public function testGetTimestamp()
233 | {
234 | $this->assertInternalType('integer', $this->filesystem->getTimestamp('2.txt'));
235 | }
236 |
237 | public function testGetSize()
238 | {
239 | $this->assertInternalType('integer', $this->filesystem->getSize('2.txt'));
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/src/AliyunOssAdapter.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | class AliyunOssAdapter extends AbstractAdapter
19 | {
20 | use StreamedTrait;
21 | use NotSupportingVisibilityTrait;
22 |
23 | /**
24 | * Aliyun Oss Client.
25 | *
26 | * @var \OSS\OssClient
27 | */
28 | protected $client;
29 |
30 | /**
31 | * bucket name.
32 | *
33 | * @var string
34 | */
35 | protected $bucket;
36 |
37 | /**
38 | * @var array
39 | */
40 | protected $options = [];
41 |
42 | /**
43 | * @var array
44 | */
45 | protected static $mappingOptions = [
46 | 'mimetype' => OssClient::OSS_CONTENT_TYPE,
47 | 'size' => OssClient::OSS_LENGTH,
48 | 'filename' => OssClient::OSS_CONTENT_DISPOSTION,
49 | ];
50 |
51 | /**
52 | * Constructor.
53 | *
54 | * @param OssClient $client
55 | * @param string $bucket
56 | * @param string $prefix
57 | * @param array $options
58 | */
59 | public function __construct(OssClient $client, $bucket, $prefix = null, array $options = [])
60 | {
61 | $this->client = $client;
62 | $this->bucket = $bucket;
63 | $this->setPathPrefix($prefix);
64 | $this->options = array_merge($this->options, $options);
65 | }
66 |
67 | /**
68 | * Get the Aliyun Oss Client bucket.
69 | *
70 | * @return string
71 | */
72 | public function getBucket()
73 | {
74 | return $this->bucket;
75 | }
76 |
77 | /**
78 | * Get the Aliyun Oss Client instance.
79 | *
80 | * @return \OSS\OssClient
81 | */
82 | public function getClient()
83 | {
84 | return $this->client;
85 | }
86 |
87 | /**
88 | * Write using a local file path.
89 | *
90 | * @param string $path
91 | * @param string $localFilePath
92 | * @param Config $config Config object
93 | * @return array|false false on failure file meta data on success
94 | */
95 | public function putFile($path, $localFilePath, Config $config)
96 | {
97 | $object = $this->applyPathPrefix($path);
98 | $options = $this->getOptionsFromConfig($config);
99 |
100 | $options[OssClient::OSS_CHECK_MD5] = true;
101 |
102 | if (! isset($options[OssClient::OSS_CONTENT_TYPE])) {
103 | $options[OssClient::OSS_CONTENT_TYPE] = Util::guessMimeType($path, '');
104 | }
105 |
106 | try {
107 | $this->client->uploadFile($this->bucket, $object, $localFilePath, $options);
108 | } catch (OssException $e) {
109 | return false;
110 | }
111 |
112 | $type = 'file';
113 | $result = compact('type', 'path');
114 | $result['mimetype'] = $options[OssClient::OSS_CONTENT_TYPE];
115 |
116 | return $result;
117 | }
118 |
119 | /**
120 | * Write a new file.
121 | *
122 | * @param string $path
123 | * @param string $contents
124 | * @param Config $config Config object
125 | * @return array|false false on failure file meta data on success
126 | */
127 | public function write($path, $contents, Config $config)
128 | {
129 | $object = $this->applyPathPrefix($path);
130 | $options = $this->getOptionsFromConfig($config);
131 |
132 | if (! isset($options[OssClient::OSS_LENGTH])) {
133 | $options[OssClient::OSS_LENGTH] = Util::contentSize($contents);
134 | }
135 |
136 | if (! isset($options[OssClient::OSS_CONTENT_TYPE])) {
137 | $options[OssClient::OSS_CONTENT_TYPE] = Util::guessMimeType($path, $contents);
138 | }
139 |
140 | try {
141 | $this->client->putObject($this->bucket, $object, $contents, $options);
142 | } catch (OssException $e) {
143 | return false;
144 | }
145 |
146 | $type = 'file';
147 | $result = compact('type', 'path', 'contents');
148 | $result['mimetype'] = $options[OssClient::OSS_CONTENT_TYPE];
149 | $result['size'] = $options[OssClient::OSS_LENGTH];
150 |
151 | return $result;
152 | }
153 |
154 | /**
155 | * Update a file.
156 | *
157 | * @param string $path
158 | * @param string $contents
159 | * @param Config $config Config object
160 | * @return array|false false on failure file meta data on success
161 | */
162 | public function update($path, $contents, Config $config)
163 | {
164 | return $this->write($path, $contents, $config);
165 | }
166 |
167 | /**
168 | * Rename a file.
169 | *
170 | * @param string $path
171 | * @param string $newpath
172 | * @return bool
173 | */
174 | public function rename($path, $newpath)
175 | {
176 | if (! $this->copy($path, $newpath)) {
177 | return false;
178 | }
179 |
180 | return $this->delete($path);
181 | }
182 |
183 | /**
184 | * Copy a file.
185 | *
186 | * @param string $path
187 | * @param string $newpath
188 | * @return bool
189 | */
190 | public function copy($path, $newpath)
191 | {
192 | $object = $this->applyPathPrefix($path);
193 | $newobject = $this->applyPathPrefix($newpath);
194 |
195 | try {
196 | $this->client->copyObject($this->bucket, $object, $this->bucket, $newobject);
197 | } catch (OssException $e) {
198 | return false;
199 | }
200 |
201 | return true;
202 | }
203 |
204 | /**
205 | * Delete a file.
206 | *
207 | * @param string $path
208 | * @return bool
209 | */
210 | public function delete($path)
211 | {
212 | $object = $this->applyPathPrefix($path);
213 |
214 | try {
215 | $this->client->deleteObject($this->bucket, $object);
216 | } catch (OssException $e) {
217 | return false;
218 | }
219 |
220 | return true;
221 | }
222 |
223 | /**
224 | * Delete a directory.
225 | *
226 | * @param string $dirname
227 | * @return bool
228 | */
229 | public function deleteDir($dirname)
230 | {
231 | $list = $this->listContents($dirname, true);
232 |
233 | $objects = [];
234 | foreach ($list as $val) {
235 | if ($val['type'] === 'file') {
236 | $objects[] = $this->applyPathPrefix($val['path']);
237 | } else {
238 | $objects[] = $this->applyPathPrefix($val['path']).'/';
239 | }
240 | }
241 |
242 | try {
243 | $this->client->deleteObjects($this->bucket, $objects);
244 | } catch (OssException $e) {
245 | return false;
246 | }
247 |
248 | return true;
249 | }
250 |
251 | /**
252 | * Create a directory.
253 | *
254 | * @param string $dirname directory name
255 | * @param Config $config
256 | * @return array|false
257 | */
258 | public function createDir($dirname, Config $config)
259 | {
260 | $object = $this->applyPathPrefix($dirname);
261 | $options = $this->getOptionsFromConfig($config);
262 |
263 | try {
264 | $this->client->createObjectDir($this->bucket, $object, $options);
265 | } catch (OssException $e) {
266 | return false;
267 | }
268 |
269 | return ['path' => $dirname, 'type' => 'dir'];
270 | }
271 |
272 | /**
273 | * Check whether a file exists.
274 | *
275 | * @param string $path
276 | * @return bool
277 | */
278 | public function has($path)
279 | {
280 | $object = $this->applyPathPrefix($path);
281 |
282 | try {
283 | $exists = $this->client->doesObjectExist($this->bucket, $object);
284 | } catch (OssException $e) {
285 | return false;
286 | }
287 |
288 | return $exists;
289 | }
290 |
291 | /**
292 | * Read a file.
293 | *
294 | * @param string $path
295 | * @return array|false
296 | */
297 | public function read($path)
298 | {
299 | $object = $this->applyPathPrefix($path);
300 |
301 | try {
302 | $contents = $this->client->getObject($this->bucket, $object);
303 | } catch (OssException $e) {
304 | return false;
305 | }
306 |
307 | return compact('contents', 'path');
308 | }
309 |
310 | /**
311 | * List contents of a directory.
312 | *
313 | * @param string $directory
314 | * @param bool $recursive
315 | * @return array
316 | */
317 | public function listContents($directory = '', $recursive = false)
318 | {
319 | $directory = rtrim($this->applyPathPrefix($directory), '\\/');
320 | if ($directory) $directory.='/';
321 |
322 | $bucket = $this->bucket;
323 | $delimiter = '/';
324 | $nextMarker = '';
325 | $maxkeys = 1000;
326 | $options = [
327 | 'delimiter' => $delimiter,
328 | 'prefix' => $directory,
329 | 'max-keys' => $maxkeys,
330 | 'marker' => $nextMarker,
331 | ];
332 |
333 | $listObjectInfo = $this->client->listObjects($bucket, $options);
334 |
335 | $objectList = $listObjectInfo->getObjectList(); // 文件列表
336 | $prefixList = $listObjectInfo->getPrefixList(); // 目录列表
337 |
338 | $result = [];
339 | foreach ($objectList as $objectInfo) {
340 | if ($objectInfo->getSize() === 0 && $directory === $objectInfo->getKey()) {
341 | $result[] = [
342 | 'type' => 'dir',
343 | 'path' => $this->removePathPrefix(rtrim($objectInfo->getKey(), '/')),
344 | 'timestamp' => strtotime($objectInfo->getLastModified()),
345 | ];
346 | continue;
347 | }
348 |
349 | $result[] = [
350 | 'type' => 'file',
351 | 'path' => $this->removePathPrefix($objectInfo->getKey()),
352 | 'timestamp' => strtotime($objectInfo->getLastModified()),
353 | 'size' => $objectInfo->getSize(),
354 | ];
355 | }
356 |
357 | foreach ($prefixList as $prefixInfo) {
358 | if ($recursive) {
359 | $next = $this->listContents($this->removePathPrefix($prefixInfo->getPrefix()), $recursive);
360 | $result = array_merge($result, $next);
361 | } else {
362 | $result[] = [
363 | 'type' => 'dir',
364 | 'path' => $this->removePathPrefix(rtrim($prefixInfo->getPrefix(), '/')),
365 | 'timestamp' => 0,
366 | ];
367 | }
368 | }
369 |
370 | return $result;
371 | }
372 |
373 | /**
374 | * Get all the meta data of a file or directory.
375 | *
376 | * @param string $path
377 | * @return array|false
378 | * @throws \OSS\Core\OssException
379 | */
380 | public function getMetadata($path)
381 | {
382 | $object = $this->applyPathPrefix($path);
383 |
384 | try {
385 | $result = $this->client->getObjectMeta($this->bucket, $object);
386 | } catch (OssException $e) {
387 | return false;
388 | }
389 |
390 | return [
391 | 'type' => 'file',
392 | 'dirname' => Util::dirname($path),
393 | 'path' => $path,
394 | 'timestamp' => strtotime($result['last-modified']),
395 | 'mimetype' => $result['content-type'],
396 | 'size' => $result['content-length'],
397 | ];
398 | }
399 |
400 | /**
401 | * Get all the meta data of a file or directory.
402 | *
403 | * @param string $path
404 | * @return array|false
405 | */
406 | public function getSize($path)
407 | {
408 | return $this->getMetadata($path);
409 | }
410 |
411 | /**
412 | * Get the mimetype of a file.
413 | *
414 | * @param string $path
415 | * @return array|false
416 | */
417 | public function getMimetype($path)
418 | {
419 | return $this->getMetadata($path);
420 | }
421 |
422 | /**
423 | * Get the timestamp of a file.
424 | *
425 | * @param string $path
426 | * @return array|false
427 | */
428 | public function getTimestamp($path)
429 | {
430 | return $this->getMetadata($path);
431 | }
432 |
433 | /**
434 | * Get the signed download url of a file.
435 | *
436 | * @param string $path
437 | * @param int $expires
438 | * @param string $host_name
439 | * @param bool $use_ssl
440 | * @return string
441 | */
442 | public function getSignedDownloadUrl($path, $expires = 3600, $host_name = '', $use_ssl = false)
443 | {
444 | $object = $this->applyPathPrefix($path);
445 | $url = $this->client->signUrl($this->bucket, $object, $expires);
446 |
447 | if (! empty($host_name) || $use_ssl) {
448 | $parse_url = parse_url($url);
449 | if (! empty($host_name)) {
450 | $parse_url['host'] = $this->bucket.'.'.$host_name;
451 | }
452 | if ($use_ssl) {
453 | $parse_url['scheme'] = 'https';
454 | }
455 |
456 | $url = (isset($parse_url['scheme']) ? $parse_url['scheme'].'://' : '')
457 | .(
458 | isset($parse_url['user']) ?
459 | $parse_url['user'].(isset($parse_url['pass']) ? ':'.$parse_url['pass'] : '').'@'
460 | : ''
461 | )
462 | .(isset($parse_url['host']) ? $parse_url['host'] : '')
463 | .(isset($parse_url['port']) ? ':'.$parse_url['port'] : '')
464 | .(isset($parse_url['path']) ? $parse_url['path'] : '')
465 | .(isset($parse_url['query']) ? '?'.$parse_url['query'] : '');
466 | }
467 |
468 | return $url;
469 | }
470 |
471 | /**
472 | * Get options from the config.
473 | *
474 | * @param Config $config
475 | * @return array
476 | */
477 | protected function getOptionsFromConfig(Config $config)
478 | {
479 | $options = $this->options;
480 | foreach (static::$mappingOptions as $option => $ossOption) {
481 | if (! $config->has($option)) {
482 | continue;
483 | }
484 | $options[$ossOption] = $config->get($option);
485 | }
486 |
487 | return $options;
488 | }
489 | }
490 |
--------------------------------------------------------------------------------