Download the PHP package kopaing/laravel-cloudflare-kv without Composer

On this page you can find all versions of the php package kopaing/laravel-cloudflare-kv. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-cloudflare-kv

Laravel Cloudflare KV Cache Driver

A Laravel cache store backed by Cloudflare Workers KV, used through Laravel's normal Cache API:

The goal is to feel like Laravel's Redis driver while being upfront about where KV differs. Workers KV is an eventually consistent, globally replicated key-value store. It has no atomic counters, no compare-and-set, no transactions and no locks. This package does not fake any of those. Operations that would need them are rejected, made opt-in with a clear warning, or delegated to a store that supports them.

Contents: License


Requirements

Installation

Laravel package discovery registers the service provider automatically.

If you want to publish the package defaults (optional):

Cloudflare setup

1. Create a KV namespace

Using the dashboard: Storage & Databases → KV → Create namespace.

Or using Wrangler:

Copy the namespace ID (32 hex characters), not its title. Your account ID is on the dashboard overview page and appears in dashboard URLs.

Use a separate namespace for each application and environment (for example myapp-production-cache and myapp-staging-cache). The namespace is the only hard isolation boundary KV gives you.

2. Create an API token

My Profile → API Tokens → Create Token → Create Custom Token:

Setting Value
Permissions Account → Workers KV Storage → Edit
Account resources Include → only the account that owns the namespace
Client IP filtering Your servers' egress IPs, if they are static
TTL Set an expiry and rotate the token

This is the least privilege the driver needs. Don't use a Global API Key. When this was written, the Workers KV Storage permission covered every namespace in the selected account and could not be limited to one namespace. If you need hard isolation, use a dedicated Cloudflare account.

Laravel configuration

.env

config/cache.php

Add a store. The smallest valid definition is:

Credentials and defaults then come from config/cloudflare-kv.php, which reads the env variables above. You can also set every option directly on the store:

Configuration precedence

The first value that isn't null wins:

  1. The store entry in config/cache.php (stores.<name>.<option>)
  2. The package defaults in config/cloudflare-kv.php
  3. Laravel defaults: cache.prefix (prefix) and app.key (signing key)

retry and flush are merged one level deep, so 'retry' => ['times' => 5] on a store keeps the default sleep. Several stores can share credentials and use different prefixes or namespaces.

The configuration contains no closures, so php artisan config:cache is supported. As with any Laravel config, env() is only read when the config is built or cached.

All options

Option Default Description
account_id, namespace_id, api_token env Required. Validated before any request is sent.
prefix cache.prefix Key prefix. If it ends in a letter or digit, : is appended. flush() only deletes keys under this prefix.
base_url https://api.cloudflare.com/client/v4 Must be https://.
timeout / connect_timeout 10 / 5 Seconds; fractions are allowed.
retry.times 3 Total attempts, including the first (1–10).
retry.sleep / retry.max_sleep 200 / 2000 Backoff base and cap, in ms.
serializer php php (any serializable value, HMAC-signed) or json (scalars and arrays only).
signing_key APP_KEY Secret used to sign payloads.
serializable_classes true Classes unserialize() may create (true, false or a list). Not inherited from cache.serializable_classes; see below.
encrypt false Encrypt values with Laravel's encrypter before they leave the app.
allow_non_atomic_updates false Enables increment, decrement and touch as non-atomic read-modify-write.
forever_ttl null If set (≥ 60), forever() entries expire after this many seconds.
bulk_get true Use the bulk read endpoint for many().
flush.enabled true Set to false to make flush() / cache:clear throw.
flush.allow_without_prefix false Allow flushing an unprefixed (whole) namespace.
lock_store null A lock-capable store that lock() is delegated to.
events true Dispatch instrumentation events.

Usage

With CACHE_STORE=cloudflare you can call Cache::get() and the rest without store().

Eloquent models and collections work out of the box, including on Laravel 13. New Laravel 13 apps set 'serializable_classes' => false in config/cache.php. Laravel's own stores then return objects as __PHP_Incomplete_Class, because anyone who can write to Redis or the database could plant a malicious serialized object. This driver deliberately does not inherit that setting. It only unserializes payloads carrying a valid HMAC signature made with your APP_KEY (or signing_key), so values planted by anyone else are rejected before unserialize() runs. To restrict classes anyway, set this store's serializable_classes to a list of classes or to false.

Locks

KV can't provide mutual exclusion. Delegate locks to a store that can:

Cache::flexible(), ShouldBeUnique jobs and withoutOverlapping() then work too. Values stay in KV; only the lock lives in the other store. Without lock_store, lock() throws CloudflareKVUnsupportedOperationException.

TTL and expiration

Cloudflare KV doesn't accept expirations shorter than 60 seconds (expiration_ttl ≥ 60). Redis does, so this package handles the gap explicitly:

Expiry is checked against your application servers' clocks, so keep them NTP-synced.

Supported and unsupported cache APIs

API Status Notes
get, put, has, missing, pull, forget ✅ One request each.
remember, rememberForever, sear ✅ Not single-flight: concurrent misses can each run the callback. Wrap the call in a lock if that matters.
many, putMany ✅ Bulk endpoints. putMany returns false if some keys still failed after retries; bulk writes aren't transactional.
forever ✅
flush / cache:clear ✅ Prefix-scoped, paginated, bulk delete. See below.
add ⚠️ Uses Laravel's generic get-then-put fallback, which is not atomic.
increment, decrement ⚠️ opt-in Throw unless allow_non_atomic_updates is true. Even then they're non-atomic read-modify-write, and concurrent increments can be lost. Use Redis or a database store for counters.
touch (Laravel 13) ⚠️ opt-in KV can't change an expiry without rewriting the value; same rule as increment.
lock, restoreLock, flexible, withoutOverlapping ⚠️ via lock_store Delegated to another store, otherwise they throw.
tags ❌ BadMethodCallException. A KV tag index can't be invalidated reliably under eventual consistency and concurrent writers.
Rate limiting (RateLimiter, throttle) ❌ Needs atomic add and increment. Point cache.limiter at Redis or a database store.
Sessions on the cloudflare cache store ⚠️ Works, but a write can take up to ~60 s to be visible in other regions. Not recommended.
Cache::memo() ✅ Laravel's request-scoped memoization (later Laravel 12 releases and 13). This package adds no local cache of its own.

Flush safety

flush() lists only keys that start with this store's prefix. It pages through them 1,000 at a time and deletes in batches of up to 10,000, and it also drops any listed key that doesn't match the prefix before deleting. It refuses to run with an empty prefix unless flush.allow_without_prefix is true, and flush.enabled => false blocks it completely. Because of eventual consistency, keys written in the last ~60 s may be missed, and deleted keys can stay readable at some edge locations for up to ~60 s.

Prefixes nested inside each other (app: and app:v2:) will be flushed together. Give each app its own namespace, or at least prefixes that don't overlap.

Consistency and performance limitations

Error handling

Every exception extends Kopaing\CloudflareKV\Exceptions\CloudflareKVException. The exception is CloudflareKVSerializationException, which extends InvalidArgumentException.

Exception When
CloudflareKVConfigurationException Missing or invalid config, a refused flush, or a bad lock_store.
CloudflareKVAuthenticationException HTTP 401/403: bad token or missing permission. Not retried.
CloudflareKVRateLimitException HTTP 429 after retries, or a Retry-After longer than retry.max_sleep. Has ->retryAfter.
CloudflareKVRequestException Other API errors, 5xx after retries, or invalid response bodies. Has ->status, ->operation and ->errorCodes().
CloudflareKVConnectionException DNS, TLS, connect or read timeout after retries.
CloudflareKVLimitExceededException A key, value or TTL outside Cloudflare's documented limits.
CloudflareKVUnsupportedOperationException increment/decrement/touch without opt-in, or lock without lock_store.
CloudflareKVSerializationException The json serializer received an object or a non-JSON value.

Retries: connection failures, 408, 429 and 5xx get bounded exponential backoff with jitter. All the REST calls the package makes are idempotent, so retrying them can't apply a change twice. Bulk writes and deletes resend only the keys Cloudflare reports as failed. A Retry-After longer than retry.max_sleep fails fast instead of blocking a web request for minutes.

Cache outages: as with Redis, transport errors are thrown, not swallowed. To degrade gracefully, wrap calls yourself or use Laravel's failover cache driver (later Laravel 12 releases and 13).

A 404 means a miss. The values endpoint answers 404 both for missing keys and for some namespace misconfigurations. A wrong namespace_id therefore shows up as permanent misses on reads and as errors on writes.

Instrumentation

When events is enabled, these events are dispatched. They never include keys, values or credentials:

Event Properties
CloudflareKVRequestCompleted operation, status, durationMs, attempts
CloudflareKVRequestRetrying operation, attempt, delayMs, reason (connection, http_503, partial_failure, …)
CloudflareKVRequestFailed operation, exception (class), status, durationMs, attempts
CloudflareKVPayloadRejected reason: malformed, unsupported_version, signature or encryption

Laravel's own CacheHit, CacheMissed and KeyWritten events are also dispatched as usual.

Security recommendations

Testing

The Feature suite runs the real client against a stateful in-memory imitation of the KV REST API (tests/Fakes/FakeCloudflareKVApi.php) through Http::fake(). It covers the HTTP formats, pagination, partial bulk failures, rate limiting, timeouts and expiry.

Live integration tests are opt-in and must use a dedicated, empty test namespace:

Testing your own app: use the array store in tests (CACHE_STORE=array in phpunit.xml) so your test suite never calls Cloudflare.

Troubleshooting

Symptom Likely cause
Cloudflare KV "account_id" is not configured Env variable missing, or config was cached before it was set. Run php artisan config:clear.
HTTP 401 [10000] Authentication error Wrong or expired token.
HTTP 403 The token lacks Workers KV Storage on that account.
Every read is a miss Wrong namespace_id, a rotated APP_KEY, or encrypt was switched off. Listen for CloudflareKVPayloadRejected.
Cached models come back as __PHP_Incomplete_Class The store's serializable_classes (or cloudflare-kv.serializable_classes) is false or doesn't list that class. cache.serializable_classes has no effect on this store.
Value changed but old value still returned Eventual consistency; wait up to ~60 s.
CloudflareKVRateLimitException More than 1,200 API calls per 5 minutes, or more than 1 write per second to one key.
increment() throws Expected; see Supported APIs.
Refusing to flush ... without a prefix Set a prefix, or flush.allow_without_prefix on a dedicated namespace.
Composer refuses to install on Laravel 11 Every laravel/framework 11.x release is flagged by a Packagist security advisory. Upgrade to Laravel 12 or 13.

Version compatibility

Package PHP Laravel Guzzle Status
1.x 8.3, 8.4, 8.5 13.0+ 7.8.2+, 8.x ✅ Supported
1.x 8.3, 8.4, 8.5 12.0.1+ 7.8.2+, 8.x ✅ Supported
1.x 8.3, 8.4 11.33.2+ 7.8.2+ ⚠️ Works and is tested. Laravel 11 security support ended in March 2026, and Composer blocks every 11.x release by default because of open advisories.

CI tests every Laravel and PHP combination above, with both the lowest and the latest allowed dependencies. Verified for this release: Laravel 13.0.0 and 13.34.0, 12.0.1 and 12.69.3, and 11.33.2 and 11.57.0, all on PHP 8.4. PHP 8.3 and 8.5 are covered by the CI matrix.

Contributing

See CONTRIBUTING.md. Please report security issues privately through GitHub Security Advisories, not public issues.

Publishing and upgrading

First publication

  1. Create an empty GitHub repository kopaing/laravel-cloudflare-kv. Keep the name in sync with homepage/support in composer.json.
  2. Push the code:

  3. Wait for the tests workflow to pass.
  4. In CHANGELOG.md, rename ## [Unreleased] to ## [1.0.0] - YYYY-MM-DD, commit, then tag. The release workflow runs the full matrix and creates the GitHub release from that changelog section.

  5. Submit the repository URL at https://packagist.org/packages/submit. Packagist reads composer.json from GitHub, and its GitHub integration picks up later tags automatically. If it doesn't, add the Packagist webhook under Settings → Webhooks.
  6. Check the result from a fresh Laravel app:

Versioning

The package follows Semantic Versioning. The public API is the store's behaviour, the config keys, the exception classes, the events and CloudflareKVClientInterface. Patch releases contain fixes, minor releases add backwards-compatible features, and major releases contain breaking changes. Before 1.0.0, use pre-release tags like v1.0.0-beta.1 (the release workflow marks them as pre-releases).

Upgrading

Read CHANGELOG.md before upgrading. The stored payload has a version field ("v": 1), so a future format change can still read old entries or treat them as misses. It will never misread them.

License

MIT. See LICENSE.


All versions of laravel-cloudflare-kv with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
ext-json Version *
guzzlehttp/guzzle Version ^7.8.2 || ^8.0
illuminate/cache Version ^11.33.2 || ^12.0.1 || ^13.0
illuminate/contracts Version ^11.33.2 || ^12.0.1 || ^13.0
illuminate/http Version ^11.33.2 || ^12.0.1 || ^13.0
illuminate/support Version ^11.33.2 || ^12.0.1 || ^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package kopaing/laravel-cloudflare-kv contains the following files

Loading the files please wait ...