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

Storage Laravel Package

styleci/storage

StyleCI Storage provides a simple, consistent abstraction for persisting and retrieving data across multiple backends. It integrates smoothly with Laravel and PHP applications, letting you swap storage drivers without changing your application code.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm the package is installable first. styleci/storage is published from GrahamDeprecated/Storage — the vendor namespace is a fork/archive marker, so treat it as a semi-private package until you verify it resolves:

composer require styleci/storage

If it isn't on Packagist, add a VCS repository entry and require it by branch:

"repositories": [{ "type": "vcs", "url": "https://github.com/GrahamDeprecated/Storage" }],
"require": { "styleci/storage": "dev-master" }

2. Register the provider. Check composer.json for extra.laravel.providers — if present, auto-discovery handles it. Otherwise add StyleCI\Storage\StorageServiceProvider::class to config/app.php.

3. Publish the config, then read it end-to-end before writing any code. The config file is the real documentation for this package:

php artisan vendor:publish --provider="StyleCI\Storage\StorageServiceProvider"

4. Look at these three files first (in vendor/styleci/storage/src/):

  • the service provider — what it binds as a singleton and whether it registers a Storage driver or a standalone facade;
  • the config file — the underlying disk, cache store, TTL, and key/cipher settings;
  • the adapter class — whether it implements Illuminate\Contracts\Filesystem\Filesystem. That single fact determines whether this is a drop-in disk or a bespoke API.

5. First use case: encrypted-at-rest, read-hot files. The natural fit is a private disk holding invoice PDFs, signed contracts, or KYC documents that are read far more often than written. Encrypt on write so the object store (S3, etc.) never sees plaintext; cache the decrypted body so a page listing 20 documents doesn't pay 20 decrypt round-trips.

// If it registers a disk driver:
$path = Storage::disk('secure')->putFile('invoices', $request->file('invoice'));

// If it's a facade/wrapper, expect the same shape:
$storage->put($path, $contents);
$contents = $storage->get($path);

Because it's a cache, expect stale reads if you write outside the wrapper. Always write through the package, never directly to the underlying disk.

Implementation Patterns

Drop-in disk swap. If the adapter implements the Filesystem contract, keep your application code untouched and change only config/filesystems.php. This is the cheapest adoption path: Storage::disk('secure')->put/get/delete/exists keeps working, and you get encryption + caching as a config change rather than a refactor. Verify the contract is actually implemented — a wrapper that only exposes put/get will break assertExists, temporaryUrl, and allFiles calls scattered around your app.

Cache-aside read path. The cache is only correct if the key encodes file identity. Include disk, path, and a version marker (mtime, ETag, or a monotonic counter you bump on write) in the cache key. Anything less and an overwrite serves the old bytes. Wrap writes so invalidation is impossible to forget:

public function replace(string $path, string $contents): void
{
    $this->storage->put($path, $contents);
    Cache::forget($this->key($path)); // never omit this
}

Encryption boundary discipline. Pick exactly one layer that encrypts. If the package encrypts, do not also use an encrypted Eloquent cast, a Crypt::encryptString() call, or an S3 SSE-KMS policy you then try to decrypt twice. Document the boundary in the model or service that owns the files.

Signed/temporary URLs. If your documents are served to browsers, the encryption layer usually kills temporaryUrl() — a presigned S3 URL returns ciphertext. The safe pattern is a short-lived controller route that streams decrypted bytes with an authorization check, and let the package's cache absorb repeat reads:

Route::get('/documents/{document}', [DocumentController::class, 'show'])
    ->middleware('can:view,document');

// controller
return response()->streamDownload(
    fn () => print($storage->get($document->path)),
    $document->filename
);

Metadata in the database, bytes in storage. Keep filename, mime type, size, owner, and a content hash in your model. Encrypted blobs are opaque, so anything you want to query, sort, or display must live in SQL — not be inferred from storage listings.

Queue-friendly usage. Decryption is CPU-bound and caching is I/O-bound; both belong off the request path for large files. Dispatch a job that reads via the package and writes a derived artifact (thumbnail, text extraction) to a plaintext-scoped disk.

Testing. Use Storage::fake() for the underlying disk and a fixed test key in phpunit.xml, and disable the cache layer in the test config so assertions aren't polluted by hits from earlier tests. Add one integration test that reads back through the wrapper — a pure unit test of your service will happily mock away the encryption bug.

Gotchas and Tips

  • This package has no measurable adoption. Zero stars, zero dependents, published under a GrahamDeprecated namespace. Vendor it, pin an exact commit, and budget for taking ownership. Do not build a compliance story on an unmaintained dependency without wrapping it behind your own interface so you can swap it out.
  • Cache invalidation is the entire risk surface. Every stale-read bug in this class of package traces to a cache key that omitted a version component. Write a test that puts, overwrites, and reads the same path.
  • Don't cache large files in Redis. A 20 MB PDF in a shared cache store will blow your memory budget and evict the session data you actually need. Cache only small documents, or point the cache config at a local file store.
  • Streams vs. strings. get() returns the full plaintext in memory. If the adapter's readStream() hands back an encrypted stream, you'll silently serve ciphertext — check whether streaming is genuinely supported before using it for downloads.
  • Offloading breaks. Nginx X-Accel-Redirect, Apache X-Sendfile, and CDN edge caching all serve the raw object. Behind encryption, they serve garbage. If raw throughput matters more than at-rest encryption for a given bucket, split your disks.
  • Key rotation has no obvious story. Changing APP_KEY or the package key will make every previously written file undecryptable. Plan a re-encrypt command (read with old key, write with new) before you have data in production, and store the key outside .env rotation churn.
  • Debugging decryption failures. A failed read after deploying to a new environment is almost always a key mismatch, not corruption. Log the cache key and the key fingerprint (never the key) on failure, and surface a distinct exception type so you can distinguish "missing file" from "wrong key."
  • Extension points to look for: a configurable cache store and TTL, an injectable cipher/key resolver, and a non-final adapter class you can subclass to add metrics or hit/miss logging. If the adapter is final and the cache store is hardcoded, that's your first fork patch.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib