Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ali Oss Storage Laravel Package

jacobcyl/ali-oss-storage

Alibaba Cloud OSS adapter for Laravel's Flysystem storage, letting you use Aliyun OSS buckets like local disks via the Storage facade. Supports uploads, presigned URLs, and standard file operations, giving Laravel apps a drop-in cloud filesystem backed by Alibaba Cloud Object Storage Service.

View on GitHub
Deep Wiki
Context7

Getting Started

This package registers a custom Flysystem adapter with Laravel's Storage facade so you can drive Aliyun OSS with the same API you already use for local disks. It is a thin wrapper around aliyuncs/oss-sdk-php, so anything not exposed by Flysystem you can still reach through the raw OSS client on the adapter.

Install and register — pin the current 2.x line, which is where the endpoint fixes landed:

composer require jacobcyl/ali-oss-storage:^2.1

The 2.x line targets modern Laravel/Flysystem; the old 1.x releases (last one from 2018) were built against Flysystem 1.x. Check the constraints in composer.json against your Laravel version before adopting, and only fall back to the manual provider registration below if auto-discovery is not honored:

'providers' => [
    // ...
    Jacobcyl\AliOSS\AliOssServiceProvider::class,
],

Add a disk in config/filesystems.php. The config key names are case-sensitive and consumed directly by the provider:

'disks' => [
    'alioss' => [
        'driver'          => 'alioss',
        'AccessKeyId'    => env('ALIOSS_KEY_ID'),
        'AccessKeySecret'=> env('ALIOSS_KEY_SECRET'),
        'Endpoint'       => env('ALIOSS_ENDPOINT'), // e.g. oss-cn-hangzhou.aliyuncs.com
        'Bucket'         => env('ALIOSS_BUCKET'),
        'Domain'         => env('ALIOSS_DOMAIN', ''), // optional CDN/custom domain
    ],
],

First use case — replace a local disk for user uploads:

$path = $request->file('avatar')->store('avatars', 'alioss');
// or explicitly
Storage::disk('alioss')->put('uploads/hello.txt', 'hello');
Storage::disk('alioss')->putFile('avatars', $request->file('avatar'));
echo Storage::disk('alioss')->url($path);

Look first at config/filesystems.php, then at the AliOssAdapter source for what has been implemented (write, read, delete, rename, copy, getUrl, getMetadata, getTimestamp). If a method is missing or behaves oddly, getAdapter()->ossClient gives you the underlying OssClient.

Implementation Patterns

Stick to the Filesystem API. For most apps there is no reason to touch the OSS SDK. Use Storage::disk('alioss') for put, putFile, get, exists, delete, files, allFiles, size, lastModified, url, and deleteDirectory. Because it obeys the container contract, you can swap the disk driver per environment (local in tests, OSS in production) without touching call sites.

Uploading user files from requests. The putFile/putFileAs and $file->store() helpers go through writeStream, which avoids loading the whole payload into PHP memory. Prefer these for images and documents; avoid put($path, file_get_contents(...)) on large files.

$path = Storage::disk('alioss')->putFileAs(
    'invoices/2024',
    $request->file('invoice'),
    $request->user()->id . '.pdf'
);

Public assets with a CDN domain. Set Domain to your custom/CDN host (including scheme) so Storage::disk('alioss')->url($path) returns your cached, branded URL instead of a raw OSS URL. This is the standard pattern for avatars, thumbnails, and static uploads.

'Domain' => 'https://cdn.example.com',

Private files and temporary links. On Flysystem 1.x the adapter predated temporaryUrl(), so signed URLs had to go through the underlying client. On 2.x verify whether temporaryUrl() is wired up on your adapter before relying on it; the client call below works either way:

$client = Storage::disk('alioss')->getAdapter()->ossClient;
$url = $client->signUrl(config('filesystems.disks.alioss.Bucket'), $path, 3600);

Wrap this in a small service or URL helper — it is the most common reason developers drop to the SDK, and it keeps the call sites independent of which URL mechanism the package currently supports.

Multiple buckets / regions. Register several disks (alioss_media, alioss_backups) each with its own Bucket/Endpoint. Models or services can point at the right disk by name; keep it out of .env if you can, since env caching makes runtime env lookups unreliable.

Storage abstraction in domain code. Define an UploadService that takes a disk name, defaults to alioss, and returns the stored path plus URL. This keeps controllers clean and makes Storage::fake('alioss') injection trivial in tests.

class UploadService {
    public function __construct(protected string $disk = 'alioss') {}
    public function store(UploadedFile $file, string $dir = 'uploads'): string {
        return $file->store($dir, $this->disk);
    }
}

Testing. Storage::fake('alioss') swaps in an in-memory/local filesystem as long as the disk is configured, so feature tests can assert uploads without hitting OSS:

Storage::fake('alioss');
$this->post('/avatar', ['avatar' => UploadedFile::fake()->image('a.jpg')]);
Storage::disk('alioss')->assertExists('avatars/a.jpg');

Migration from local storage. Keep the same relative-path conventions (avatars/{id}.jpg) so existing URLs, model attributes, and cleanup jobs continue to work. Migrate files with a one-off command that streams each local file to the OSS disk via putFile/writeStream, then flip the default disk.

Gotchas and Tips

Pin ^2.1 deliberately. 2.1.0 fixes a batch of reported issues, most notably endpoint-related errors. If you were on an earlier 2.x, upgrading is low-risk and worth doing; if you are on 1.x, treat the move to 2.x as a genuine upgrade — re-verify the adapter methods you use rather than assuming drop-in behaviour.

Version compatibility. Match the package line to your Flysystem major: 1.x releases were built against Flysystem 1.x (League\Flysystem\AdapterInterface), which Laravel 9+ removed, so they fatal-error on modern Laravel. The 2.x line is the one to use on current Laravel; confirm the composer constraints resolve for your exact Laravel/Flysystem versions before committing.

Config key casing matters. The provider reads AccessKeyId, AccessKeySecret, Endpoint, Bucket, Domain — not snake_case. A snake_case disk will throw Undefined index at boot. Missing Domain is a common source of errors too; always declare it, even as an empty string.

Endpoint format. Historically the adapter wanted the bare region hostname (oss-cn-hangzhou.aliyuncs.com) with no https://, no bucket prefix, and no trailing slash; malformed endpoints and region mismatches produced RequestTimeTooSkewed or NoSuchBucket. 2.1.0 explicitly addresses endpoint-driven errors, so if you carried a workaround (trimming the scheme, string-munging the env var), retest on 2.1 before keeping it — leaving stale normalisation in place can now double-correct.

Domain format. The adapter typically concatenates Domain . '/' . $path, so include the scheme and strip the trailing slash: https://cdn.example.com. Using cdn.example.com yields protocol-relative/broken URLs.

Private buckets still return URLs. url() does not sign anything — on a private bucket the URL will 403. Either set the object/bucket ACL to public-read during upload, or generate signed URLs via the client as shown above.

No true multipart/resumable upload. Large files go through writeStream/putFile; the adapter does not expose OSS multipart APIs. For multi-GB uploads, use the OSS SDK directly (or a chunked-upload package) rather than this disk.

temporaryUrl() support varies. Do not assume Laravel's signed-URL helper works with this disk — on older adapter builds it throws or silently returns an unsigned URL. Probe it in a tinker session after upgrading; use signUrl on the client if it is not implemented.

Debugging failures. OSS errors surface as OSS\Http\Exception or OSS\Core\OssException with codes like AccessDenied, SignatureDoesNotMatch, InvalidAccessKeyId. Log the code and request ID; almost always the cause is wrong key, wrong region/endpoint (see the 2.1 fix above), or clock skew (NTP).

Config caching. Once you run php artisan config:cache, env() calls outside config files return null. Keep OSS credentials in config/filesystems.php (referencing env()), never in controllers — and re-run config:cache after upgrading, since stale cached disk config is a frequent false alarm when validating an endpoint fix.

Extension points. Because the underlying client is reachable through getAdapter()->ossClient, you can add features (signed URLs, multipart, ACL changes, lifecycle operations) without forking the package. If you need a lot of these, encapsulate them in a dedicated service rather than sprinkling SDK calls through the app — it keeps the eventual migration off this package cheap.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package