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

Rackspace Cloud Files Streamwrapper Laravel Package

tvision/rackspace-cloud-files-streamwrapper

A Laravel/PHP stream wrapper for Rackspace Cloud Files that lets you read, write, and manage remote objects using standard filesystem functions, bringing Cloud Files into familiar PHP file operations and Laravel workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a thin, single-purpose package: it registers a PHP stream wrapper so that Rackspace Cloud Files containers can be addressed with native filesystem functions (fopen, file_get_contents, file_put_contents, stream_copy_to_stream, copy). There is no Laravel service provider, no Facade, and no Flysystem adapter — the day-one value is that anything in PHP (and by extension Laravel) that accepts a path or a stream can now point at rscf://container/key.

1. Confirm it will even install. The last release was November 2013 and the package predates PHP 7. Before writing any code, open composer.json in the repo and check the PHP constraint and the Rackspace SDK it pulls in (php-cloudfiles vs rackspace/php-opencloud). On PHP 8 you will almost certainly need a fork or a compatibility patch; budget for that up front rather than discovering it in CI.

2. Install and register the wrapper. Installation is plain Composer; the wrapper registration is the only setup step:

composer require tvision/rackspace-cloud-files-streamwrapper
// bootstrap / service provider boot()
$wrapper = new \Tvision\RackspaceCloudFilesStreamWrapper\StreamWrapper(
    config('services.rackspace.username'),
    config('services.rackspace.api_key'),
    'my-container',
    'rscf' // the scheme you'll type in paths
);

$wrapper->register(); // internally: stream_wrapper_register('rscf', ...)

(Use the exact class name and constructor signature from the repo README — the package exposes a single wrapper class, and the argument order is the one thing worth double-checking before you build on it.)

3. First use case — prove the pipe works. Do not start with Laravel integration. Start with a one-liner that demonstrates the wrapper is registered and authenticated:

var_dump(in_array('rscf', stream_get_wrappers()));      // registered?
echo file_get_contents('rscf://my-container/health.txt');

Once that returns bytes, you have a real integration surface. The most common first production use is streaming a user upload straight to Cloud Files without ever touching local disk:

$in  = fopen($request->file('avatar')->getRealPath(), 'r');
$out = fopen('rscf://my-container/avatars/'.$user->id.'.jpg', 'w');
stream_copy_to_stream($in, $out);
fclose($out);

Implementation Patterns

Laravel service provider (the canonical wiring). Register once, lazily, and keep credentials in config/services.php:

class CloudFilesServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(StreamWrapper::class, fn () => new StreamWrapper(
            config('services.rackspace.username'),
            config('services.rackspace.api_key'),
            config('services.rackspace.container'),
            config('services.rackspace.scheme', 'rscf'),
        ));
    }

    public function boot(): void
    {
        if (! in_array(config('services.rackspace.scheme', 'rscf'), stream_get_wrappers())) {
            $this->app->make(StreamWrapper::class)->register();
        }
    }
}

The in_array(..., stream_get_wrappers()) guard matters because tests, Octane workers, and queue workers can boot the provider repeatedly; a duplicate stream_wrapper_register call emits a warning.

Streaming, not buffering. The wrapper's whole reason to exist is that fopen/stream_copy_to_stream keep memory flat. Treat file_get_contents and file_put_contents as convenience calls for small objects only. For downloads, let the framework stream the response:

return response()->streamDownload(function () use ($key) {
    $fp = fopen("rscf://my-container/{$key}", 'r');
    fpassthru($fp);
    fclose($fp);
}, basename($key));

Image pipelines. Because the wrapper is a real path, Intervention Image and similar libraries accept it directly:

$img = Image::make('rscf://my-container/uploads/original.jpg')->fit(300, 300);
$img->save('rscf://my-container/uploads/thumb.jpg');

This is the single highest-leverage integration — it means your resize/thumbnail jobs never need /tmp staging or a cleanup step.

Handing off to services that want a local path. For tools that insist on a real filesystem path (FFmpeg, finfo, mime_content_type, ZipArchive), download to storage_path('app/tmp') first, operate, then stream back up. Wrap that in a small helper (withLocalCopy($key, callable $fn)) so the temp-file lifecycle lives in one place.

Custom disk via Storage::extend, if you must. Laravel's Storage facade needs a Flysystem adapter, and the wrapper is not one. The pragmatic routes are (a) call the wrapper directly and skip Storage for this disk, or (b) write a ~40-line Flysystem adapter that delegates readStream/writeStream/delete to the wrapper. Option (a) is usually correct for a legacy package you do not want to entrench.

Keep object keys explicit. Cloud Files has flat keys, so build paths with a single helper (cloudPath($type, $id, $filename)) rather than concatenating in controllers. It makes future migration to S3/Swift a find-and-replace.

Gotchas and Tips

Assume it is unmaintained. Zero stars, zero dependents, no release since 2013. Treat it as vendored code you own: pin the exact version, vendor a fork if needed, and put a note in the README with the date you last audited it. The underlying php-cloudfiles-era code uses APIs removed in PHP 7/8 (each(), old constructors, deprecated mcrypt usage), so expect to patch.

The service itself is on borrowed time. Rackspace Cloud Files is a legacy product and the ecosystem has moved on. Use this wrapper as a bridge, not a foundation: abstract object access behind one class so swapping to S3-compatible storage later is a single-file change.

One scheme per credential set. stream_wrapper_register is global per-process, so a second account or container needs a distinct scheme (rscf2://, rscf-staging://). Registering the same scheme twice silently keeps the first registration.

Write semantics are object-storage semantics. There is no append and no partial write. fopen(..., 'a') will either fail or clobber — never assume it appends. rename() on Cloud Files is a copy+delete (or unsupported), so it is slow or absent; use the SDK's object move directly if you need it.

Content-Type defaults will bite you. Stream writes typically land as application/octet-stream, which means images render as downloads in the browser. After writing, set metadata explicitly (via the SDK or a subclassed wrapper that sniffs the extension in stream_write). This is the most common "it works but the file is broken" bug with stream wrappers.

stat, is_file, mkdir, scandir are the weak spots. Object stores have no directories and often no cheap url_stat. File::exists() and Storage-style checks against rscf:// can return false for objects that are perfectly readable. Test each wrapper method you rely on in isolation — don't infer support from the presence of a method.

Reads bypass the CDN. rscf:// reads authenticate and hit the API on every call, so latency is far higher than the public CDN URL. For user-facing assets, store the CDN URL alongside the key and serve that; reserve wrapper reads for backend jobs.

Debugging moves. stream_get_meta_data($fp) shows the wrapper and mode actually in play; stream_get_wrappers() confirms registration; error_get_last() catches failures that the wrapper swallows silently. When fopen returns false with no warning, the wrapper's stream_open is rejecting the path — usually a container-name or leading-slash mismatch (rscf://container/key vs rscf:///container/key).

Extension point. Subclass the wrapper and override stream_open/stream_write to add content-type detection, logging, or key prefixing. That is far cheaper than forking the package, and it keeps your customizations visible in one file when you eventually replace it.

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.
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen