sinemacula / laravel-cached-crypt
A Laravel package that adds transparent caching to decrypted values for improved performance across encrypted attributes.
Installs: 10 302
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 1
Open Issues: 0
pkg:composer/sinemacula/laravel-cached-crypt
Requires
- php: ^8.3
- illuminate/encryption: ^12.9
- illuminate/support: ^12.9
Requires (Dev)
- brianium/paratest: ^7.8
- friendsofphp/php-cs-fixer: ^3.85
- orchestra/testbench: ^9.0 || ^10.0
- phpstan/extension-installer: ^1.4
- phpstan/phpdoc-parser: ^2.2
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^11.5.3
- slevomat/coding-standard: ^8.20
- squizlabs/php_codesniffer: ^3.13
This package is auto-updated.
Last update: 2026-02-20 22:30:06 UTC
README
Laravel Cached Crypt wraps Laravel's encrypter to reduce repeated decrypt overhead in hot paths. It is drop-in by default, memoizes decrypt results in-process, and can optionally persist plaintext with bounded TTL, epoch versioning, and size guardrails.
⚠️ Security Warning Persisted plaintext caching should only be enabled when operational controls are in place. Use secured Redis/Memcached with encryption in transit and at rest, private networking, and short TTLs. Prefer memo-only mode unless cross-request reuse is required.
Features
- Drop-in provider integration with no manual registration order requirements
- Enabled-by-default memo-only optimization path (
enabled=true,memo_only=true,cache_plaintext=false) - Optional cross-request plaintext persistence with TTL (no
rememberForever) - Epoch and optional key fingerprint namespacing for safe invalidation boundaries
- SHA-256 payload hashing for cache keys
- Optional dedicated cache store and optional cache tagging
- Size guardrails (
min_bytes_to_cache,max_memo_bytes,max_bytes_to_cache) - Optional eligibility resolver hook for app-specific persistence decisions
- Fail-open behavior for cache backend and resolver failures (decrypt path preserved)
- Optional sampled metric logging for cache/decrypt behavior
Installation
composer require sinemacula/laravel-cached-crypt
Laravel will automatically register the service provider via package discovery. No manual provider ordering is required.
Configuration
Publish the config file:
php artisan vendor:publish --tag=config
Default configuration in config/cached-crypt.php:
return [ 'enabled' => true, 'cache_plaintext' => false, 'memo_only' => true, 'ttl_seconds' => 120, 'epoch' => 'v1', 'key_fingerprint' => null, 'store' => null, 'min_bytes_to_cache' => 1024, 'max_memo_bytes' => 262144, 'max_bytes_to_cache' => 262144, 'use_tags' => false, 'eligibility_resolver' => null, 'metrics' => [ 'enabled' => false, 'sample_rate' => 0.10, ], ];
Safe defaults:
- Works out of the box with no additional env vars
- Package enabled in memo-only mode by default
- Cross-request plaintext persistence remains off unless explicitly enabled
How It Works
For each decrypt call:
- Build a namespaced key with epoch and SHA-256 payload hash.
- Read from in-process memoization cache first.
- Optionally read/write persistent plaintext cache when enabled and eligible.
- Decrypt via Laravel when needed, then memoize and optionally persist.
- Fail open on cache/resolver errors so decrypt behavior is preserved.
Persistent writes are bounded by:
ttl_secondsmin_bytes_to_cache(encrypted payload size)max_memo_bytes(in-process memo value size estimate)max_bytes_to_cache(decrypted value size estimate)- Optional resolver callback (
eligibility_resolver)
Operating Modes
memo_only = true: in-process reuse only, no cross-request plaintext persistence.cache_plaintext = trueandmemo_only = false: allows persistent plaintext caching with guardrails.
Key Rotation and Invalidation
When encryption settings change (for example APP_KEY, cipher, or previous_keys), bump epoch.
This immediately cold-starts cached plaintext keys without requiring global cache flushes.
If use_tags is enabled and the store supports tags, entries are grouped under:
cached-cryptcached-crypt:{epoch}
Metrics
When metrics.enabled is true, sampled events are logged with:
- cache hit/miss source (
memoorpersistent) - decrypt duration in milliseconds
- approximate bytes persisted for cache writes
- cache error events for persistent read/write failures
Testing
composer test
composer test-coverage
composer check
Contributing
Contributions are welcome via GitHub pull requests.
Security
If you discover a security issue, please contact Sine Macula directly rather than opening a public issue.
License
Licensed under the Apache License, Version 2.0.