├── .coveralls.yml.dist ├── LICENSE ├── README.md ├── composer.json ├── config └── config.php └── src ├── AliyunAdapter.php ├── AliyunException.php ├── AliyunFactory.php ├── OssOptions.php ├── UrlGenerator.php └── VisibilityConverter.php /.coveralls.yml.dist: -------------------------------------------------------------------------------- 1 | coverage_clover: coverage.xml 2 | json_path: coverage.json 3 | repo_token: 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 AlphaSnow 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aliyun OSS Flysystem 2 | 3 | 💾 Flysystem Adapter for [Aliyun Object Storage Service](https://www.alibabacloud.com/help/en/object-storage-service). 4 | 5 | [![Latest Stable Version](https://poser.pugx.org/alphasnow/aliyun-oss-flysystem/v/stable)](https://packagist.org/packages/alphasnow/aliyun-oss-flysystem) 6 | [![Total Downloads](https://poser.pugx.org/alphasnow/aliyun-oss-flysystem/downloads)](https://packagist.org/packages/alphasnow/aliyun-oss-flysystem) 7 | [![License](https://poser.pugx.org/alphasnow/aliyun-oss-flysystem/license)](https://packagist.org/packages/alphasnow/aliyun-oss-flysystem) 8 | [![tests](https://github.com/alphasnow/aliyun-oss-flysystem/actions/workflows/tests.yml/badge.svg?branch=3.x)](https://github.com/alphasnow/aliyun-oss-flysystem/actions/workflows/tests.yml) 9 | [![Coverage Status](https://coveralls.io/repos/github/alphasnow/aliyun-oss-flysystem/badge.svg?branch=3)](https://coveralls.io/github/alphasnow/aliyun-oss-flysystem?branch=3) 10 | 11 | ## Compatibility 12 | 13 | | **flysystem** | **aliyun-oss-flysystem** | **readme** 14 | |---|---|---| 15 | | ^3.0 | ^3.0 | [readme](https://github.com/alphasnow/aliyun-oss-flysystem/blob/3.x/README.md) | 16 | | ^2.0 | ^2.0 | [readme](https://github.com/alphasnow/aliyun-oss-flysystem/blob/2.x/README.md) | 17 | | ^1.0 | ^1.0 | [readme](https://github.com/alphasnow/aliyun-oss-flysystem/blob/1.x/README.md) | 18 | | ~1.0.0 | ^0.3 | [readme](https://github.com/alphasnow/aliyun-oss-flysystem/blob/0.x/README.md) | 19 | 20 | ## Installation 21 | 22 | ```bash 23 | composer require "alphasnow/aliyun-oss-flysystem" 24 | ``` 25 | 26 | ## Usage 27 | 28 | ### Initialize 29 | ```php 30 | use OSS\OssClient; 31 | use AlphaSnow\Flysystem\Aliyun\AliyunFactory; 32 | 33 | $config = [ 34 | "access_key_id" => "**************", // Required, YourAccessKeyId 35 | "access_key_secret" => "********************", // Required, YourAccessKeySecret 36 | "endpoint" => "oss-cn-shanghai.aliyuncs.com", // Required, Endpoint 37 | "bucket" => "bucket-name", // Required, Bucket 38 | ]; 39 | 40 | $flysystem = (new AliyunFactory())->createFilesystem($config); 41 | 42 | $flysystem->write("file.md", "contents"); 43 | $flysystem->writeStream("foo.md", fopen("file.md", "r")); 44 | 45 | $fileExists = $flysystem->fileExists("foo.md"); 46 | $flysystem->copy("foo.md", "baz.md"); 47 | $flysystem->move("baz.md", "bar.md"); 48 | $flysystem->delete("bar.md"); 49 | $has = $flysystem->has("bar.md"); 50 | 51 | $read = $flysystem->read("file.md"); 52 | $readStream = $flysystem->readStream("file.md"); 53 | 54 | $flysystem->createDirectory("foo/"); 55 | $directoryExists = $flysystem->directoryExists("foo/"); 56 | $flysystem->deleteDirectory("foo/"); 57 | 58 | $listContents = $flysystem->listContents("/", true); 59 | $listPaths = []; 60 | foreach ($listContents as $listContent) { 61 | $listPaths[] = $listContent->path(); 62 | } 63 | 64 | $lastModified = $flysystem->lastModified("file.md"); 65 | $fileSize = $flysystem->fileSize("file.md"); 66 | $mimeType = $flysystem->mimeType("file.md"); 67 | 68 | $flysystem->setVisibility("file.md", "private"); 69 | $visibility = $flysystem->visibility("file.md"); 70 | ``` 71 | 72 | ### Options 73 | ```php 74 | $flysystem->write("file.md", "contents", [ 75 | "options" => ["checkmd5" => false] 76 | ]); 77 | $flysystem->write("bar.md", "contents", [ 78 | "headers" => ["Content-Disposition" => "attachment;filename=bar.md"] 79 | ]); 80 | $flysystem->write("baz.md", "contents", [ 81 | "visibility" => "private" 82 | ]); 83 | ``` 84 | 85 | ## Reference 86 | [https://github.com/thephpleague/flysystem](https://github.com/thephpleague/flysystem) 87 | 88 | ## License 89 | The MIT License (MIT). Please see [License File](LICENSE) for more information. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alphasnow/aliyun-oss-flysystem", 3 | "description": "Flysystem adapter for the Aliyun storage", 4 | "keywords": [ 5 | "aliyun", 6 | "oss", 7 | "filesystem", 8 | "adapter" 9 | ], 10 | "homepage": "https://alphasnow.github.io/aliyun-oss-flysystem/", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Alpha Snow", 15 | "email": "wind91@foxmail.com" 16 | } 17 | ], 18 | "require": { 19 | "league/flysystem": "^3.0", 20 | "aliyuncs/oss-sdk-php": "^2.7" 21 | }, 22 | "require-dev": { 23 | "phpstan/phpstan": "^1.4", 24 | "phpunit/phpunit": "^9.5", 25 | "mockery/mockery": "^1.5", 26 | "friendsofphp/php-cs-fixer": "^3.6", 27 | "vlucas/phpdotenv": "^5.4", 28 | "php-coveralls/php-coveralls": "*" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "AlphaSnow\\Flysystem\\Aliyun\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "AlphaSnow\\Flysystem\\Aliyun\\Tests\\": "tests/" 38 | } 39 | }, 40 | "scripts": { 41 | "phpstan": "vendor/bin/phpstan analyse", 42 | "check-style": "vendor/bin/php-cs-fixer fix --using-cache=no --diff --config=.php-cs-fixer.php --dry-run --ansi", 43 | "fix-style": "vendor/bin/php-cs-fixer fix --using-cache=no --config=.php-cs-fixer.php --ansi", 44 | "test": "vendor/bin/phpunit", 45 | "coveralls": "vendor/bin/php-coveralls" 46 | }, 47 | "scripts-descriptions": { 48 | "phpstan": "Run static analysis", 49 | "check-style": "Run style checks (only dry run - no fixing!).", 50 | "fix-style": "Run style checks and fix violations.", 51 | "test": "Run all tests." 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /config/config.php: -------------------------------------------------------------------------------- 1 | "",// Required 5 | "access_key_secret" => "",// Required 6 | "endpoint" => "",// Required 7 | "bucket" => "",// Required 8 | "prefix" => "", 9 | "request_proxy" => null, 10 | "security_token" => null, 11 | "is_cname" => false, 12 | "use_ssl" => null, 13 | "max_retries" => null, 14 | "timeout" => null, 15 | "connect_timeout" => null, 16 | "enable_sts_in_url" => null, 17 | "options" => [ 18 | // \OSS\OssClient::OSS_CHECK_MD5 => false, 19 | ], 20 | "internal" => null, // For example: oss-cn-shanghai-internal.aliyuncs.com 21 | "domain" => null, // For example: oss.my-domain.com 22 | "signatureVersion" => null, 23 | "region" => "", 24 | ]; 25 | -------------------------------------------------------------------------------- /src/AliyunAdapter.php: -------------------------------------------------------------------------------- 1 | client = $client; 72 | $this->bucket = $bucket; 73 | $this->prefixer = new PathPrefixer($prefix); 74 | $this->config = $config; 75 | $this->visibility = new VisibilityConverter(); 76 | $this->options = new OssOptions($config["options"] ?? []); 77 | $this->urlGenerator = new UrlGenerator($config); 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | public function fileExists(string $path): bool 84 | { 85 | try { 86 | return $this->client->doesObjectExist($this->bucket, $this->prefixer->prefixPath($path), $this->options->getOptions()); 87 | } catch (OssException $exception) { 88 | throw UnableToCheckExistence::forLocation("{$path}. {$exception->getMessage()}", $exception); 89 | } 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function directoryExists(string $path): bool 96 | { 97 | try { 98 | return $this->client->doesObjectExist($this->bucket, $this->prefixer->prefixDirectoryPath($path), $this->options->getOptions()); 99 | } catch (OssException $exception) { 100 | throw UnableToCheckExistence::forLocation("{$path}. {$exception->getMessage()}", $exception); 101 | } 102 | } 103 | 104 | /** 105 | * {@inheritdoc} 106 | */ 107 | public function write(string $path, string $contents, Config $config): void 108 | { 109 | try { 110 | $this->client->putObject($this->bucket, $this->prefixer->prefixPath($path), $contents, $this->options->mergeConfig($config, $this->visibility)); 111 | } catch (OssException $exception) { 112 | throw UnableToWriteFile::atLocation($path, $exception->getMessage(), $exception); 113 | } 114 | } 115 | 116 | /** 117 | * {@inheritdoc} 118 | */ 119 | public function writeStream(string $path, $contents, Config $config): void 120 | { 121 | try { 122 | $this->client->uploadStream($this->bucket, $this->prefixer->prefixPath($path), $contents, $this->options->mergeConfig($config, $this->visibility)); 123 | } catch (OssException $exception) { 124 | throw UnableToWriteFile::atLocation($path, $exception->getMessage(), $exception); 125 | } 126 | } 127 | 128 | /** 129 | * {@inheritdoc} 130 | */ 131 | public function read(string $path): string 132 | { 133 | try { 134 | return $this->client->getObject($this->bucket, $this->prefixer->prefixPath($path), $this->options->getOptions()); 135 | } catch (OssException $exception) { 136 | throw UnableToReadFile::fromLocation($path, $exception->getMessage(), $exception); 137 | } 138 | } 139 | 140 | /** 141 | * {@inheritdoc} 142 | */ 143 | public function readStream(string $path) 144 | { 145 | $stream = fopen("php://temp", "w+b"); 146 | 147 | try { 148 | $options = array_merge($this->options->getOptions(), [OssClient::OSS_FILE_DOWNLOAD => $stream]); 149 | $this->client->getObject($this->bucket, $this->prefixer->prefixPath($path), $options); 150 | } catch (OssException $exception) { 151 | fclose($stream); 152 | throw UnableToReadFile::fromLocation($path, $exception->getMessage(), $exception); 153 | } 154 | 155 | rewind($stream); 156 | return $stream; 157 | } 158 | 159 | /** 160 | * {@inheritdoc} 161 | */ 162 | public function delete(string $path): void 163 | { 164 | try { 165 | $this->client->deleteObject($this->bucket, $this->prefixer->prefixPath($path), $this->options->getOptions()); 166 | } catch (OssException $exception) { 167 | throw UnableToDeleteFile::atLocation($path, $exception->getMessage(), $exception); 168 | } 169 | } 170 | 171 | /** 172 | * {@inheritdoc} 173 | */ 174 | public function deleteDirectory(string $path): void 175 | { 176 | try { 177 | $contents = $this->listContents($path, true); 178 | $files = []; 179 | foreach ($contents as $i => $content) { 180 | if ($content instanceof DirectoryAttributes) { 181 | continue; 182 | } 183 | $files[] = $this->prefixer->prefixPath($content->path()); 184 | 185 | // A maximum of 1000 files can be deleted at a time 186 | if ($i && $i % 1000 == 0) { 187 | $this->client->deleteObjects($this->bucket, $files, $this->options->getOptions()); 188 | $files = []; 189 | } 190 | } 191 | !empty($files) && $this->client->deleteObjects($this->bucket, $files, $this->options->getOptions()); 192 | $this->directoryExists($path) && $this->client->deleteObject($this->bucket, $this->prefixer->prefixDirectoryPath($path), $this->options->getOptions()); 193 | } catch (OssException $exception) { 194 | throw UnableToDeleteDirectory::atLocation($path, $exception->getMessage(), $exception); 195 | } 196 | } 197 | 198 | /** 199 | * {@inheritdoc} 200 | */ 201 | public function createDirectory(string $path, Config $config): void 202 | { 203 | try { 204 | $this->client->putObject($this->bucket, $this->prefixer->prefixDirectoryPath($path), "", $this->options->mergeConfig($config, $this->visibility)); 205 | } catch (OssException $exception) { 206 | throw UnableToCreateDirectory::dueToFailure("{$path}. {$exception->getMessage()}", $exception); 207 | } 208 | } 209 | 210 | /** 211 | * {@inheritdoc} 212 | */ 213 | public function setVisibility(string $path, string $visibility): void 214 | { 215 | try { 216 | $this->client->putObjectAcl($this->bucket, $this->prefixer->prefixPath($path), $this->visibility->visibilityToAcl($visibility), $this->options->getOptions()); 217 | } catch (OssException $exception) { 218 | throw UnableToSetVisibility::atLocation($path, $exception->getMessage(), $exception); 219 | } 220 | } 221 | 222 | /** 223 | * {@inheritdoc} 224 | */ 225 | public function visibility(string $path): FileAttributes 226 | { 227 | try { 228 | $acl = $this->client->getObjectAcl($this->bucket, $this->prefixer->prefixPath($path), $this->options->getOptions()); 229 | } catch (OssException $exception) { 230 | throw UnableToRetrieveMetadata::visibility($path, $exception->getMessage(), $exception); 231 | } 232 | 233 | return new FileAttributes($path, null, $this->visibility->aclToVisibility($acl)); 234 | } 235 | 236 | /** 237 | * {@inheritdoc} 238 | */ 239 | public function mimeType(string $path): FileAttributes 240 | { 241 | return $this->metadata($path); 242 | } 243 | 244 | /** 245 | * {@inheritdoc} 246 | */ 247 | public function lastModified(string $path): FileAttributes 248 | { 249 | return $this->metadata($path); 250 | } 251 | 252 | /** 253 | * {@inheritdoc} 254 | */ 255 | public function fileSize(string $path): FileAttributes 256 | { 257 | return $this->metadata($path); 258 | } 259 | 260 | /** 261 | * {@inheritdoc} 262 | */ 263 | public function listContents(string $path, bool $deep): iterable 264 | { 265 | $prefix = $this->prefixer->prefixDirectoryPath($path); 266 | $delimiter = $deep ? "" : "/"; 267 | $nextToken = ""; 268 | while (true) { 269 | $options = array_merge( 270 | $this->options->getOptions(), 271 | [ 272 | OssClient::OSS_PREFIX => $prefix, 273 | OssClient::OSS_DELIMITER => $delimiter, 274 | OssClient::OSS_CONTINUATION_TOKEN => $nextToken 275 | ] 276 | ); 277 | try { 278 | $listObjects = $this->client->listObjectsV2($this->bucket, $options); 279 | } catch (OssException $exception) { 280 | throw new AliyunException($exception->getMessage(), 0, $exception); 281 | } 282 | 283 | $prefixList = $listObjects->getPrefixList(); 284 | foreach ($prefixList as $prefixInfo) { 285 | $prefixPath = $this->prefixer->stripDirectoryPrefix($prefixInfo->getPrefix()); 286 | yield new DirectoryAttributes($prefixPath); 287 | } 288 | 289 | $objectList = $listObjects->getObjectList(); 290 | if (!empty($objectList)) { 291 | foreach ($objectList as $objectInfo) { 292 | // Exclude the root folder 293 | if ($objectInfo->getKey() == $prefix) { 294 | continue; 295 | } 296 | $objectPath = $this->prefixer->stripPrefix($objectInfo->getKey()); 297 | $objectLastModified = strtotime($objectInfo->getLastModified()); 298 | if (substr($objectPath, -1, 1) === "/") { 299 | yield new DirectoryAttributes($objectPath, null, $objectLastModified); 300 | } else { 301 | yield new FileAttributes($objectPath, $objectInfo->getSize(), null, $objectLastModified); 302 | } 303 | } 304 | } 305 | 306 | if ($listObjects->getIsTruncated() === "false") { 307 | break; 308 | } 309 | $nextToken = $listObjects->getNextContinuationToken(); 310 | } 311 | } 312 | 313 | /** 314 | * {@inheritdoc} 315 | */ 316 | public function move(string $source, string $destination, Config $config): void 317 | { 318 | $this->copy($source, $destination, $config); 319 | $this->delete($source); 320 | } 321 | 322 | /** 323 | * {@inheritdoc} 324 | */ 325 | public function copy(string $source, string $destination, Config $config): void 326 | { 327 | try { 328 | $this->client->copyObject($this->bucket, $this->prefixer->prefixPath($source), $this->bucket, $this->prefixer->prefixPath($destination), $this->options->mergeConfig($config, $this->visibility)); 329 | } catch (OssException $exception) { 330 | throw UnableToCopyFile::fromLocationTo($source, $destination, $exception); 331 | } 332 | } 333 | 334 | /** 335 | * @param string $path 336 | * @return FileAttributes 337 | */ 338 | protected function metadata(string $path): FileAttributes 339 | { 340 | try { 341 | $result = $this->client->getObjectMeta($this->bucket, $this->prefixer->prefixPath($path), $this->options->getOptions()); 342 | } catch (OssException $exception) { 343 | throw UnableToRetrieveMetadata::create($path, "metadata", $exception->getMessage(), $exception); 344 | } 345 | 346 | $size = isset($result["content-length"]) ? intval($result["content-length"]) : 0; 347 | $timestamp = isset($result["last-modified"]) ? strtotime($result["last-modified"]) : 0; 348 | $mimetype = isset($result["content-type"]) ? $result["content-type"] : ""; 349 | return new FileAttributes($path, $size, null, $timestamp, $mimetype); 350 | } 351 | 352 | /** 353 | * @return OssClient 354 | */ 355 | public function getClient(): OssClient 356 | { 357 | return $this->client; 358 | } 359 | 360 | /** 361 | * @return OssOptions 362 | */ 363 | public function getOptions(): OssOptions 364 | { 365 | return $this->options; 366 | } 367 | 368 | /** 369 | * @return PathPrefixer 370 | */ 371 | public function getPrefixer(): PathPrefixer 372 | { 373 | return $this->prefixer; 374 | } 375 | 376 | /** 377 | * @return string 378 | */ 379 | public function getBucket(): string 380 | { 381 | return $this->bucket; 382 | } 383 | 384 | /** 385 | * @param string $path 386 | * @return string 387 | */ 388 | public function getUrl(string $path): string 389 | { 390 | $prefixed = $this->config["url_prefixed"] ?? false; 391 | if ($prefixed === false) { 392 | $path = $this->prefixer->prefixPath($path); 393 | } 394 | return $this->urlGenerator->fullUrl($path); 395 | } 396 | 397 | /** 398 | * @param string $path 399 | * @param \DateTimeInterface $expiration 400 | * @param array $options 401 | * @return string 402 | */ 403 | public function getTemporaryUrl(string $path, \DateTimeInterface $expiration, array $options = []): string 404 | { 405 | $object = $this->prefixer->prefixPath($path); 406 | $options = $this->options->mergeConfig(new Config($options)); 407 | $timeout = $expiration->getTimestamp() - (new \DateTime())->getTimestamp(); 408 | 409 | $method = $options[OssClient::OSS_METHOD] ?? OssClient::OSS_HTTP_GET; 410 | $url = $this->client->signUrl($this->bucket, $object, $timeout, $method, $options); 411 | return $this->urlGenerator->correctDomain($url); 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /src/AliyunException.php: -------------------------------------------------------------------------------- 1 | createClient($config); 19 | return new AliyunAdapter($client, $config["bucket"], $config["prefix"] ?? "", $config); 20 | } 21 | 22 | /** 23 | * @param array $config 24 | * @param OssClient|null $client 25 | * @return Filesystem 26 | */ 27 | public function createFilesystem(array $config, ?OssClient $client = null): Filesystem 28 | { 29 | return new Filesystem($this->createAdapter($config, $client)); 30 | } 31 | 32 | /** 33 | * @param array $config 34 | * @return OssClient 35 | * @throws \OSS\Core\OssException 36 | */ 37 | public function createClient(array $config): OssClient 38 | { 39 | if(!isset($config['provider']) || !$config['provider']) { 40 | $config['provider'] = new StaticCredentialsProvider($config["access_key_id"], $config["access_key_secret"], $config["security_token"] ?? null); 41 | } 42 | $config['endpoint'] = (new UrlGenerator($config))->getOssEndpoint(); 43 | $config['cname'] = $config['is_cname'] ?? false; 44 | $client = new OssClient($config); 45 | isset($config["use_ssl"]) && !is_null($config["use_ssl"]) && $client->setUseSSL($config["use_ssl"]); 46 | isset($config["max_retries"]) && !is_null($config["max_retries"]) && $client->setMaxTries($config["max_retries"]); 47 | isset($config["enable_sts_in_url"]) && !is_null($config["enable_sts_in_url"]) && $client->setSignStsInUrl($config["enable_sts_in_url"]); 48 | isset($config["timeout"]) && !is_null($config["timeout"]) && $client->setTimeout($config["timeout"]); 49 | isset($config["connect_timeout"]) && !is_null($config["connect_timeout"]) && $client->setConnectTimeout($config["connect_timeout"]); 50 | return $client; 51 | } 52 | } -------------------------------------------------------------------------------- /src/OssOptions.php: -------------------------------------------------------------------------------- 1 | options = $options; 21 | } 22 | 23 | /** 24 | * @return array 25 | */ 26 | public function getOptions(): array 27 | { 28 | return $this->options; 29 | } 30 | 31 | /** 32 | * @param array $options 33 | * @return OssOptions 34 | */ 35 | public function setOptions(array $options): OssOptions 36 | { 37 | $this->options = $options; 38 | return $this; 39 | } 40 | 41 | /** 42 | * @param Config $config 43 | * @param VisibilityConverter|null $visibilityConverter 44 | * @return array 45 | */ 46 | public function mergeConfig(Config $config, ?VisibilityConverter $visibilityConverter = null): array 47 | { 48 | $options = $config->get("options", []); 49 | 50 | if ($headers = $config->get("headers")) { 51 | $options[OssClient::OSS_HEADERS] = isset($options[OssClient::OSS_HEADERS]) ? array_merge($options[OssClient::OSS_HEADERS], $headers) : $headers; 52 | } 53 | 54 | if ($visibility = $config->get("visibility")) { 55 | is_null($visibilityConverter) && $visibilityConverter = new VisibilityConverter(); 56 | $options[OssClient::OSS_HEADERS][OssClient::OSS_OBJECT_ACL] = $visibilityConverter->visibilityToAcl($visibility); 57 | } 58 | 59 | return array_merge_recursive($this->options, $options); 60 | } 61 | } -------------------------------------------------------------------------------- /src/UrlGenerator.php: -------------------------------------------------------------------------------- 1 | null, 12 | "endpoint" => null, 13 | "internal" => null, 14 | "domain" => null, 15 | "use_ssl" => false, 16 | "is_cname" => false, 17 | ]; 18 | 19 | /** 20 | * @param array $config 21 | */ 22 | public function __construct(array $config) 23 | { 24 | $this->config = array_merge($this->config, $config); 25 | } 26 | 27 | /** 28 | * @param string $path 29 | * @return string 30 | */ 31 | public function fullUrl(string $path): string 32 | { 33 | return $this->getDomain() . "/" . ltrim($path, "/"); 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | protected function getDomain(): string 40 | { 41 | if ($this->config["domain"]) { 42 | return $this->getProtocol() . "://" . $this->config["domain"]; 43 | } 44 | return $this->getEndpointDomain(); 45 | } 46 | 47 | /** 48 | * @return string 49 | */ 50 | protected function getEndpointDomain(): string 51 | { 52 | return $this->getProtocol() . "://" . $this->config["bucket"] . "." . $this->config["endpoint"]; 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | protected function getInternalDomain(): string 59 | { 60 | return $this->getProtocol() . "://" . $this->config["bucket"] . "." . $this->config["internal"]; 61 | } 62 | 63 | /** 64 | * @return string 65 | */ 66 | protected function getProtocol(): string 67 | { 68 | return $this->config["use_ssl"] ? "https" : "http"; 69 | } 70 | 71 | /** 72 | * @return string 73 | */ 74 | public function getOssEndpoint(): string 75 | { 76 | if ($this->config["internal"]) { 77 | return $this->config["internal"] ?: ""; 78 | } 79 | if ($this->config["domain"] && $this->config["is_cname"]) { 80 | return $this->config["domain"] ?: ""; 81 | } 82 | return $this->config["endpoint"] ?: ""; 83 | } 84 | 85 | /** 86 | * @param string $url 87 | * @return string 88 | */ 89 | public function correctDomain(string $url): string 90 | { 91 | if ($this->config["internal"]) { 92 | return str_replace($this->getInternalDomain(), $this->getDomain(), $url); 93 | } 94 | 95 | if ($this->config["domain"]) { 96 | return str_replace($this->getEndpointDomain(), $this->getDomain(), $url); 97 | } 98 | 99 | return $url; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/VisibilityConverter.php: -------------------------------------------------------------------------------- 1 |