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 Bundle Laravel Package

tvision/rackspace-cloud-files-bundle

A Symfony bundle for integrating Rackspace Cloud Files into PHP applications. It provides configuration and service wiring to upload, store, manage, and serve files via Rackspace cloud object storage, simplifying Cloud Files usage within Symfony projects.

View on GitHub
Deep Wiki
Context7

Getting Started

What you're actually looking at: a Symfony 2.x bundle (last touched 2013) that wires the rackspace/php-opencloud SDK into Symfony's DI container and — in most of these bundles — registers a rackspace:// stream wrapper so you can call file_get_contents() against Cloud Files containers. It is not a Laravel package, has no service provider, no facades, and zero dependents on Packagist.

Do not composer require it into a Laravel app. It declares a Symfony bundle class (extending Symfony\Component\HttpKernel\Bundle\Bundle), ships Resources/config/services.yml, and will pull Symfony 2 components plus an ancient Guzzle into your dependency graph. On PHP 8 you'll get resolution failures long before you get a working upload.

Read these files first (5 minutes, then stop):

  1. DependencyInjection/*Extension.php and Resources/config/services.yml — this tells you exactly which config keys the bundle expects (username, API key, region/identity endpoint, container, whether to enable the stream wrapper).
  2. The main service class — usually a thin holder for the OpenCloud\Rackspace client plus a helper to fetch the object store.
  3. The stream wrapper class, if present — this is the only genuinely interesting part, because it's the piece you'd re-register in Laravel.

First use case — reproduce the bundle's behavior directly with the SDK. This is the entire value the bundle provides, in one file:

// config/services.php
'rackspace' => [
    'username'   => env('RS_USERNAME'),
    'api_key'    => env('RS_API_KEY'),
    'region'     => env('RS_REGION', 'IAD'),   // IAD, DFW, ORD, LON, SYD, HKG
    'container'  => env('RS_CONTAINER'),
    'identity'   => env('RS_IDENTITY', 'https://identity.api.rackspacecloud.com/v2.0/'),
],
// AppServiceProvider::register()
$this->app->singleton(\OpenCloud\Rackspace::class, function () {
    return new \OpenCloud\Rackspace(config('services.rackspace.identity'), [
        'username' => config('services.rackspace.username'),
        'apiKey'   => config('services.rackspace.api_key'),
    ]);
});

$this->app->singleton(\OpenCloud\ObjectStore\Service::class, function ($app) {
    $client = $app->make(\OpenCloud\Rackspace::class);

    return $client->objectStoreService('cloudFiles', config('services.rackspace.region'));
});
// usage
$container = app(\OpenCloud\ObjectStore\Service::class)
    ->getContainer(config('services.rackspace.container'));

$container->uploadObject('uploads/2024/report.pdf', fopen($path, 'r'), [
    'ContentType' => 'application/pdf',
]);

Better first use case: wrap this in Flysystem and never touch the SDK again. league/flysystem-openstack-swift (Swift is the API Cloud Files speaks) gives you Storage::disk('rackspace'), put(), url(), temporaryUrl(), and a trivial future migration to S3. That's the day-to-day abstraction you actually want; the bundle is just historical precedent for it.

Implementation Patterns

Translate Symfony idioms to Laravel before porting anything. The mental mapping:

Bundle construct Laravel equivalent
services.yml service definition $this->app->singleton(...) in a provider
%parameter% config config('services.rackspace.*') + .env
Constructor @service injection Container autowiring / constructor typehints
Compiler pass overriding a definition $this->app->extend(...) or a decorator class
Bundle Configuration tree config/services.php array (no validation — validate in the provider)

Pattern: filesystem-first, not SDK-first. Register a rackspace disk and let the rest of the app speak in paths:

// config/filesystems.php
'disks' => [
    'rackspace' => [
        'driver'    => 'openstack',
        'container' => env('RS_CONTAINER'),
        'username'  => env('RS_USERNAME'),
        'password'  => env('RS_API_KEY'),
        'region'    => env('RS_REGION'),
        'endpoint'  => env('RS_IDENTITY'),
    ],
],

Everything downstream — uploads, exports, image resizing targets — becomes Storage::disk('rackspace')->put(...). Swapping to S3 later is a config change, which is the whole point of not adopting a 2013 bundle.

Pattern: stream wrapper for legacy-style code. If you're porting existing Symfony code that relied on rackspace://, register the wrapper once in boot() and leave the rest of the code untouched:

public function boot()
{
    if (config('services.rackspace.stream_wrapper')) {
        // class name depends on the bundle version; check src/StreamWrapper/
        stream_wrapper_register('rackspace', \App\Filesystem\RackspaceStreamWrapper::class);
    }
}

Then file_get_contents('rackspace://container/path.txt') works. Prefer this only for read-heavy, small-file paths — see Gotchas.

Pattern: store paths, not URLs. Persist container/path/to/object (or just the key) in the database. Public container URLs are CDN-hosted and the CDN hostname/SSL setting can change per region; temp URLs expire. Generate URLs at render time:

Storage::disk('rackspace')->temporaryUrl($path, now()->addMinutes(15));

Pattern: large uploads go through the transfer manager, not put(). For anything over a few tens of MB use php-opencloud's upload transfer (or Flysystem's write stream) so it chunks instead of buffering the whole file. Never file_get_contents() a 200 MB export into a string.

Pattern: reuse one client instance. Authentication against the v2 identity endpoint is a separate HTTP round-trip and tokens expire (~24 h). Bind the client and service as singletons — the bundle did this for you; in Laravel you must do it deliberately. Do not new Rackspace(...) inside a loop or a queued job's handle() without the container binding.

Pattern: environment isolation via key prefixes. Use container names or object key prefixes per environment (prod/, staging/) so a .env mistake doesn't write test artifacts into the production container. Cloud Files containers are cheap; a mis-targeted job is not.

Pattern: test against the in-memory disk. Never hit Rackspace from tests. Storage::fake('rackspace') plus assertions on the disk keeps the suite fast and lets you assert exact keys.

Workflow for a queued upload: accept the file into local temp storage → dispatch a job with the path → job streams to Cloud Files → persist the returned object key → delete local temp file in a finally. Keeps the HTTP request fast and gives you a retry point.

Gotchas and Tips

This package is dead by inspection. Five stars, no dependents, last release 2013-11-13, Symfony 2-era. Treat it strictly as documentation of an approach — copying code is fine, depending on it is not. Verify on your own account whether Rackspace Cloud Files is still provisioned for your region at all; Rackspace has been steering customers off legacy public-cloud products, so the more likely outcome is that you're migrating to S3/Spaces/B2 anyway.

PHP and Guzzle conflicts are the practical blocker. php-opencloud of that vintage pins Guzzle 3.x, which collides with the Guzzle 6/7 that Laravel and modern SDKs require. You cannot have both in one vendor tree comfortably. If you must talk to Cloud Files, use the maintained php-opencloud/openstack package in an isolated piece of code, or front it with a tiny internal HTTP client. Check with composer why-not guzzlehttp/guzzle 7 before spending time.

Identity endpoint vs region confusion. US accounts use https://identity.api.rackspacecloud.com/v2.0/, UK accounts use https://lon.identity.api.rackspacecloud.com/v2.0/. Wrong endpoint gives you an auth failure that looks like bad credentials. Correct endpoint + wrong region gives you a 404/401 on the object store that looks like a permissions bug. Log the resolved endpoint and region on boot in non-production.

Stream wrapper performance traps. stat(), filesize(), is_file(), and file_exists() each become a remote HTTP HEAD request — glob() or a loop over 500 files will take seconds and can trip rate limits. rename() across containers isn't atomic (copy + delete); a crash mid-way leaves duplicates. There is no real directory concept, only / in the key, so mkdir/rmdir are effectively no-ops. Use the wrapper for reads, not for filesystem bookkeeping.

Memory. file_get_contents('rackspace://...') loads the entire object into a PHP string. For anything user-generated, stream with fopen/Storage::readStream() and copy in chunks.

CDN TTL hides updates. CDN-enabled containers cache by TTL, so overwriting an object at the same key won't be visible immediately. This bites hard with versioned asset filenames baked into manifest.json — if you overwrite instead of creating new keys, users see stale files for the TTL window. Also: enabling/disabling CDN or changing the SSL option changes the URL hostname, so never persist the full URL.

ETags aren't MD5s on multipart uploads. Don't validate integrity by comparing your local MD5 to the object's ETag for chunked/large uploads — it's a composite value. Keep the local checksum in your own table if you need verification.

No purge API in the wrapper. If you relied on the bundle for CDN invalidation, it likely didn't provide it — TTL is your only lever. Design keys to be immutable-and-versioned rather than overwritten.

Symfony config quirks don't survive the port. The bundle's Configuration class may enforce required keys at container-compile time; Laravel won't. Add an explicit throw new \RuntimeException(...) in your provider for a missing username/key/container, otherwise you get an opaque SDK exception thirty seconds into a job.

Debugging network calls. Inject a logger into the HTTP client stack to dump requests (never log the X-Auth-Token header or the API key). Most "it just hangs" reports here are retries against an expired token or a misconfigured identity URL. Add retry-with-backoff (exponential, jitter) around 429/503 responses — the old SDK had none worth relying on.

Extension point that matters: the only thing worth extracting from the repo is the stream wrapper class itself. Everything else (DI wiring, config schema) is Symfony-specific boilerplate that has a one-line Laravel equivalent. Copy the wrapper, delete the bundle, and put Flysystem in front of 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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator