umityatarkalkmaz / cache
Stores JSON-serialisable values as files, each with its own expiry
Requires
- php: >=8.2
- umityatarkalkmaz/string-helper: ^2.0
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.5 || ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Stores JSON-serialisable values as files, each with its own expiry.
Requirements
PHP 8.2 or newer.
Installation
composer require umityatarkalkmaz/cache
Usage
use UmitYatarkalkmaz\Cache; $cache = new Cache(__DIR__ . '/storage/cache'); $cache->put('videos', ['videoname', '21:20:10', 'creator' => 'Very Good People']); $videos = $cache->get('videos');
Reading
$cache->get(string $key, mixed $default = null): mixed
Returns $default when the entry is missing, expired, or unreadable. Pass a
$default you would never cache to tell a miss apart from a stored false or
null:
$value = $cache->get('flag', $miss = new stdClass()); if ($value === $miss) { // not cached }
has(string $key): bool answers the same question without returning the value.
Writing
$cache->put(string $key, mixed $value, ?int $ttl = 3600): bool
$ttl is a lifetime in seconds. Pass null to store an entry that never
expires; zero or a negative number throws InvalidArgumentException. put()
returns false when the value cannot be encoded or the file cannot be written —
check it rather than assuming the write landed.
Writes go through a temporary file in the same directory and are renamed into
place, so a concurrent reader never sees a half-written entry and a failed write
leaves the previous value intact. Entries are stored with mode 0600, and the
mode is set before the payload is written, so an entry is never briefly readable
under the process umask.
forget(string $key): bool removes an entry, and reports success when the entry
was already absent.
Pruning
$cache->prune(): int
Deletes every expired or unreadable entry and returns how many it removed. An
entry is otherwise only dropped when it is read, so a cache that is written to
more often than it is read grows without a periodic prune() — from a cron job
or a scheduled task, not from every request.
Keys
Any string is a valid key. It is slugified for readability and suffixed with a
SHA-256 hash of the original, so user/42/profile and ../../etc/passwd are
both stored safely inside the cache directory, and two keys that slugify the
same way stay separate entries.
Keys appear in filenames. The slug is a readable, lowercased form of the key
itself, so anyone who can list the cache directory sees them — put("password reset for ada@example.com", …) puts that address on disk in the clear, and it
survives in the directory listing until the entry is pruned. Entry contents are
mode 0600, but the directory listing is governed by the directory's own
permissions. Keep personal data out of keys, or hash it into them yourself.
What can be stored
Anything json_encode() accepts. Objects come back as stdClass, and
resources cannot be stored at all — put() returns false for them.
Development
composer install
composer check # phpstan (level max) + phpunit
License
MIT. See LICENSE.