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

B2Backblaze Laravel Package

kamilz/b2backblaze

A Laravel package that integrates Backblaze B2 cloud storage as a filesystem driver, making it easy to upload, store, retrieve, and delete files through familiar Laravel Storage APIs with simple configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and wire credentials into Laravel's config in three steps:

composer require kamilz/b2backblaze
  1. Add environment variables – Backblaze issues a key ID and application key per account, plus you need the target bucket ID:
    B2_ACCOUNT_ID=xxxxxxxxxxxx
    B2_APPLICATION_KEY=yyyyyyyyyyyy
    B2_BUCKET_ID=zzzzzzzzzzzz
    B2_BUCKET_NAME=my-app-bucket
    
  2. Create config/b2.php and pull from env(). Never hard-code keys; Backblaze keys are long-lived and bucket-scoped, so leaking one exposes the whole bucket.
  3. Register a singleton in AppServiceProvider (see Implementation Patterns) so the underlying B2\Client is reused per request.

First use case: authorize and list buckets before touching files. This validates credentials without risking a half-upload:

$client = app(\B2\Client::class);
$buckets = $client->listBuckets();
// confirm $buckets contains your expected bucketId

The library follows the Backblaze B2 REST API closely (listBuckets, listFiles, uploadFile, deleteFile, getFileInfo, getDownloadAuthorization). There is no facade, no service provider shipped, and no Laravel-specific sugar — expect to pass Backblaze parameter arrays directly.

Look first at the README and the B2\Client class methods; the package is a thin wrapper, so the real API documentation is Backblaze's own b2_* endpoint reference.

Implementation Patterns

Singleton binding in AppServiceProvider:

$this->app->singleton(\B2\Client::class, function () {
    return new \B2\Client(
        config('b2.account_id'),
        config('b2.application_key'),
    );
});

The client caches an auth token internally for ~24 hours; resolving it fresh each request wastes a round-trip. If you're on Octane, prefer a scoped binding or re-resolve when the token is near expiry.

Upload pattern (small files, < 100 MB):

$client->uploadFile([
    'BucketId' => config('b2.bucket_id'),
    'FileName' => "avatars/{$user->id}.png",
    'Body'     => $bytes,
    'mimeType' => 'image/png',
]);

Backblaze requires SHA1 and Content-Length; the wrapper computes them, but double-check on binary streams — a mangled upload usually surfaces as a 401 on the second step, not the first.

Large files: the B2 API is two-step (get an upload URL → POST bytes). For anything over a few hundred MB, split into parts and uploadPart calls. The package exposes getUploadUrl and uploadPart, but you own the chunking and retry logic. Wrap it in a Job with $tries = 3 and exponential backoff.

Downloads: private buckets are the norm. Do not build URLs directly. Use:

$url = $client->getDownloadAuthorization([
    'BucketId' => config('b2.bucket_id'),
    'FileName' => $path,
    'ValidDurationInSeconds' => 3600,
]);
// redirect to $url->downloadUrl

Cache these short-lived URLs and hand them to the browser; they expire and are safe to share briefly.

Deletion is versioned. deleteFile needs both FileName and FileId. Calling it with only a name will fail — always resolve the FileId via listFiles or store it alongside your DB record:

$file = $client->listFiles(['BucketId' => $id, 'Prefix' => $path, 'MaxFileCount' => 1]);
$client->deleteFile(['FileName' => $path, 'FileId' => $file[0]->fileId]);

Storage adapter: wrap the client in a small B2Storage class with put(), get(), exists(), url(). Keeping the raw client out of controllers makes it trivial to swap to the S3-compatible endpoint (Backblaze exposes one) if you later prefer Flysystem.

Testing: mock the B2\Client binding in your tests — the library makes real HTTP calls, and there is no fake shipped.

Gotchas and Tips

  • Two-step uploads fail weirdly. If uploadFile throws an authorization error, the most common cause is an expired upload URL — URLs are short-lived (24h). Re-call getUploadUrl on retry, don't reuse the old one.
  • Bucket region is permanent. Choose the region when creating the bucket; you cannot move it. A wrong region won't error on write, it'll just cost latency and egress forever.
  • Versioning bites deletes. B2 keeps every version. listFiles returns the latest, but storage fills up if you only "delete" — use lifecycle rules or explicit FileId deletes.
  • Token caching under Octane. The B2\Client holds state (auth token, upload URLs). A long-lived singleton across requests can serve a stale token. Add a health check or re-instantiate per worker cycle.
  • Timeouts: default HTTP timeouts are too short for multi-hundred-MB uploads. Pass a custom timeout or stream in parts; a truncated upload returns a generic 503, not a clear message.
  • Config caching: php artisan config:cache snapshots .env. Changing B2_APPLICATION_KEY after caching silently uses the old key until you re-cache.
  • Name uniqueness: bucket names are globally unique across all Backblaze accounts. Pick something organization- and app-scoped, or you'll collide during provisioning.
  • Rate limits and 503 SlowDown: Backblaze throttles per-account. Wrap mutating calls in a retry with jitter; queue heavy uploads and cap concurrency per bucket.
  • Extension points are sparse. The package is a thin wrapper — there's no event system, no middleware, no retry hooks. Add those yourself in a B2Storage service class or a Retryable trait. If you need more, note that Backblaze's S3-compatible API lets you drop in league/flysystem-aws-s3-v3 and get the whole Laravel Storage facade for free; only reach for this package when you need B2-native features (file versions, specific bucket IDs, cheap egress reporting).
  • Watch the abandoned-status signals. 16 stars and no recent commits means it likely won't track PHP 8.x or Backblaze API changes. Pin the version in composer.json and budget a fork or migration path.
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.
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
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource