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

Aliyun Oss Php Sdk Laravel Laravel Package

aliyuncs/aliyun-oss-php-sdk-laravel

A Laravel wrapper for the Aliyun OSS PHP SDK that adds a service provider, facade, and config for using Alibaba Cloud Object Storage Service as a Laravel filesystem. Upload, store, and manage files on OSS through familiar Laravel APIs.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register (manual, not discovered):

composer require aliyuncs/aliyun-oss-php-sdk-laravel

This package predates Laravel 5.5 package auto-discovery, so register it by hand in config/app.php unless you've verified the manifest in vendor/. You want both the provider and the facade:

'providers' => [
    Aliyun\Laravel\OssServiceProvider::class,
],
'aliases' => [
    'OSS' => Aliyun\Laravel\OssClientFacade::class,
],

Publish and configure. Run php artisan vendor:publish --provider="Aliyun\Laravel\OssServiceProvider" and then open the published config (look for config/oss.php in the package's src/config). It will expect, at minimum:

  • access_key_id / access_key_secret (or the equivalent key names in the published file)
  • endpoint — the region endpoint, e.g. oss-cn-hangzhou.aliyuncs.com
  • bucket

Put the credentials in .env and reference them from the config file. Never commit the keys; prefer a RAM sub-account with an OSS-only policy over the root AccessKey.

First use case — the smoke test. After registering, php artisan tinker and confirm the container resolves the client and that credentials/endpoint/bucket are correct in one shot:

OSS::putObject('healthcheck.txt', 'ok');          // upload
OSS::getObject('healthcheck.txt');                // download and read
OSS::doesObjectExist('healthcheck.txt');          // bool

If all three work, your endpoint/bucket pairing is right and you can stop debugging config. If putObject throws a 403 or SignatureDoesNotMatch, the problem is almost always endpoint or key, not code.

Where to look first in the source: the service provider (what it binds into the container and under what key), then the facade (which method it proxies). The facade proxies straight through to Aliyun\OSS\OssClient, so the real API surface is the upstream SDK's — read its README, not this wrapper's.

Implementation Patterns

Treat it as the raw client, not a storage abstraction. This package gives you the OssClient in the container. It does not register a Flysystem driver, so there is no Storage::disk('oss'), no Storage::put, no Storage::url. Every call is OSS::putObject($object, $content) style. If your app mostly needs Storage semantics, reach for a Flysystem OSS adapter instead and use this package only where you need SDK-specific features (signed URLs, multipart, callbacks).

Resolve via the container, not the global facade, in services. The facade is convenient in controllers and tinker, but for anything you test, inject Aliyun\OSS\OssClient through the constructor — the provider binds it, so Laravel resolves it for free:

final class AvatarStore
{
    public function __construct(private \Aliyun\OSS\OssClient $oss) {}

    public function store(UploadedFile $file, string $key): string
    {
        $this->oss->putObject($key, file_get_contents($file->path()));
        return $key;
    }
}

Upload pattern — always use object keys you control. OSS has no directory tree; avatars/42/abc.png is a flat key that looks like a path. Generate the key server-side (UUID + extension) rather than trusting the client filename, and normalize/sanitize anything user-supplied.

Private buckets: sign, don't proxy. For private ACL buckets, the pattern is to hand the browser a time-limited URL and let it download directly from OSS, rather than streaming every byte through PHP:

$url = OSS::signUrl($bucket, $key, $ttlSeconds);

That keeps your app servers out of the bandwidth path entirely. For truly private per-user access, keep the bucket private and issue short TTLs (minutes, not hours).

Public buckets: put a CDN in front. If objects are public, configure an Aliyun CDN domain against the bucket and store/emit the CDN hostname in your URLs. Otherwise you're paying for OSS egress on every page load.

Large files: stream, don't buffer. getObject() returns the whole body as a string in memory. For anything over a few MB use getObjectToFile($bucket, $key, $localPath) (or open a stream) and serve with a response that streams from disk. For uploads over ~100 MB, use the SDK's multipart methods (initiateMultipartUpload / uploadPart / completeMultipartUpload) — the single-shot putObject will time out or OOM.

Environment parity. Point dev at a separate bucket (or at least a dev/ key prefix) rather than reusing production. Because the SDK is endpoint-config-driven, it's cheap to run MinIO/S3-compatible locally, but OSS's API is not S3-compatible in the general case — don't assume your local S3 stub exercises the same code.

Cleanup and lifecycle. Deleting the app record and deleting the OSS object are not transactional. Either delete the object after the DB commit succeeds, or (better) let an OSS lifecycle rule on prefix tmp/ reap abandoned uploads, and keep a scheduled listObjects reconciliation job for orphans.

Gotchas and Tips

It's frozen since 2017 — verify compatibility explicitly. The last release is from August 2017, which puts it in the Laravel 5.4–5.5 era. Before adopting, check the composer constraint against your PHP and Laravel version; on PHP 8.x with Laravel 9+, this is likely to conflict or emit deprecations. The wrapper itself is thin — a provider and a facade — so if it breaks, the pragmatic fix is often to drop it and bind OssClient yourself in your own AppServiceProvider in about ten lines.

Auto-discovery almost certainly won't fire. If you don't see the client bound after composer install, don't hunt for a bug in your config — add the provider and alias to config/app.php manually.

No Storage::fake('oss') equivalent. There is no test double shipped with this package, and the class is concrete, so mocking OssClient directly is awkward. Extract your own interface (ObjectStore) with a thin OSS implementation and a fake implementation for tests. This one decision will save you the most pain.

Endpoint format is the #1 source of SignatureDoesNotMatch and connect failures. The endpoint must be the region hostname (e.g. oss-cn-hangzhou.aliyuncs.com), and it must match the bucket's actual region. A bucket in oss-cn-shanghai hit through the oss-cn-hangzhou endpoint will fail in confusing ways. Cross-check the region in the Aliyun console — the endpoint string is not derived from the bucket name.

Exceptions are Aliyun\OSS\Exceptions\OssException (upstream), not Laravel-flavored. Wrap OSS calls in a try/catch at your storage boundary and translate to your domain errors. Check the exception's getErrorCode() — string codes like NoSuchKey, AccessDenied, EntityTooLarge are more reliable to branch on than message text. Do not let raw SDK exceptions escape into your HTTP layer.

doesObjectExist can throw, not just return false. Depending on bucket ACL/permissions, an inaccessible bucket surfaces as an exception rather than false. Don't write if (!OSS::doesObjectExist(...)) assuming it's total — a permissions error will look like a crash, which is arguably fine, but be deliberate about it.

Signed URL TTLs and clock skew. signUrl bakes an expiry into the query string. Server clocks that drift, or proxies that rewrite query params, will produce 403s that look random. Keep TTLs generous enough to survive a slow redirect, and don't sign URLs and then cache them past their TTL — sign at request time, or cache for less than the TTL.

Memory on reads. This is worth repeating because it's the most common production incident: getObject() loads the object into a PHP string. A 50 MB file in a loop is 50 MB per iteration. Use getObjectToFile / streams for anything user-uploaded.

Config caching. php artisan config:cache will snapshot whatever is in the published config file. If you put logic (e.g. env() calls inside a closure or conditional) in there, it will break after caching on older Laravel. Keep the config file flat and env-driven.

Extension point is the container binding. If you need to tweak the client (timeouts, a custom RequestCore handler, retries, logging), the clean approach is to extend or bind your own OssClient in a provider that runs after this one, rather than editing vendor code. The facade resolves through the container, so an override there propagates everywhere the facade is used.

Retries are your responsibility. OSS intermittently returns 5xx and the SDK's default behavior isn't aggressive about retrying. For uploads in a queue job, wrap the call in a retry loop or lean on Laravel's job retry with a sensible backoff — but make sure your object keys are idempotent (same key overwrites safely, so retries are usually fine).

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console