mirror of
https://github.com/danog/Valinor.git
synced 2024-11-26 20:24:40 +01:00
fix: prevent illegal characters in PSR-16 cache keys
@see https://www.php-fig.org/psr/psr-16/#12-definitions
This commit is contained in:
parent
546fa5c6cf
commit
3c4d29901a
@ -4,22 +4,28 @@ declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
use Closure;
|
||||
use CuyZ\Valinor\Utility\Package;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Traversable;
|
||||
|
||||
use function sha1;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @template EntryType
|
||||
* @implements CacheInterface<EntryType>
|
||||
*/
|
||||
final class VersionedCache implements CacheInterface
|
||||
final class KeySanitizerCache implements CacheInterface
|
||||
{
|
||||
/** @var CacheInterface<EntryType> */
|
||||
private static string $version;
|
||||
|
||||
/** @var CacheInterface<EntryType> */
|
||||
private CacheInterface $delegate;
|
||||
|
||||
private string $version;
|
||||
/** @var Closure(string): string */
|
||||
private Closure $sanitize;
|
||||
|
||||
/**
|
||||
* @param CacheInterface<EntryType> $delegate
|
||||
@ -27,23 +33,29 @@ final class VersionedCache implements CacheInterface
|
||||
public function __construct(CacheInterface $delegate)
|
||||
{
|
||||
$this->delegate = $delegate;
|
||||
/** @infection-ignore-all */
|
||||
$this->version = PHP_VERSION . '/' . Package::version();
|
||||
|
||||
// Two things:
|
||||
// 1. We append the current version of the package to the cache key in
|
||||
// order to avoid collisions between entries from different versions
|
||||
// of the library.
|
||||
// 2. The key is sha1'd so that it does not contain illegal characters.
|
||||
// @see https://www.php-fig.org/psr/psr-16/#12-definitions
|
||||
$this->sanitize = static fn (string $key) => sha1("$key." . self::$version ??= PHP_VERSION . '/' . Package::version());
|
||||
}
|
||||
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
return $this->delegate->get($this->key($key), $default);
|
||||
return $this->delegate->get(($this->sanitize)($key), $default);
|
||||
}
|
||||
|
||||
public function set($key, $value, $ttl = null): bool
|
||||
{
|
||||
return $this->delegate->set($this->key($key), $value, $ttl);
|
||||
return $this->delegate->set(($this->sanitize)($key), $value, $ttl);
|
||||
}
|
||||
|
||||
public function delete($key): bool
|
||||
{
|
||||
return $this->delegate->delete($this->key($key));
|
||||
return $this->delegate->delete(($this->sanitize)($key));
|
||||
}
|
||||
|
||||
public function clear(): bool
|
||||
@ -53,7 +65,7 @@ final class VersionedCache implements CacheInterface
|
||||
|
||||
public function has($key): bool
|
||||
{
|
||||
return $this->delegate->has($this->key($key));
|
||||
return $this->delegate->has(($this->sanitize)($key));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +74,7 @@ final class VersionedCache implements CacheInterface
|
||||
public function getMultiple($keys, $default = null): Traversable
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
yield $key => $this->delegate->get($this->key($key), $default);
|
||||
yield $key => $this->delegate->get(($this->sanitize)($key), $default);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +83,7 @@ final class VersionedCache implements CacheInterface
|
||||
$versionedValues = [];
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$versionedValues[$this->key($key)] = $value;
|
||||
$versionedValues[($this->sanitize)($key)] = $value;
|
||||
}
|
||||
|
||||
return $this->delegate->setMultiple($versionedValues, $ttl);
|
||||
@ -82,14 +94,9 @@ final class VersionedCache implements CacheInterface
|
||||
$transformedKeys = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$transformedKeys[] = $this->key($key);
|
||||
$transformedKeys[] = ($this->sanitize)($key);
|
||||
}
|
||||
|
||||
return $this->delegate->deleteMultiple($transformedKeys);
|
||||
}
|
||||
|
||||
private function key(string $key): string
|
||||
{
|
||||
return "$key.$this->version";
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ namespace CuyZ\Valinor\Library;
|
||||
|
||||
use CuyZ\Valinor\Cache\ChainCache;
|
||||
use CuyZ\Valinor\Cache\RuntimeCache;
|
||||
use CuyZ\Valinor\Cache\VersionedCache;
|
||||
use CuyZ\Valinor\Cache\KeySanitizerCache;
|
||||
use CuyZ\Valinor\Cache\Warmup\RecursiveCacheWarmupService;
|
||||
use CuyZ\Valinor\Definition\FunctionsContainer;
|
||||
use CuyZ\Valinor\Definition\Repository\AttributesRepository;
|
||||
@ -222,10 +222,10 @@ final class Container
|
||||
$cache = new RuntimeCache();
|
||||
|
||||
if (isset($settings->cache)) {
|
||||
$cache = new ChainCache($cache, $settings->cache);
|
||||
$cache = new ChainCache($cache, new KeySanitizerCache($settings->cache));
|
||||
}
|
||||
|
||||
return new VersionedCache($cache);
|
||||
return $cache;
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -4,25 +4,25 @@ declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Tests\Unit\Cache;
|
||||
|
||||
use CuyZ\Valinor\Cache\VersionedCache;
|
||||
use CuyZ\Valinor\Cache\KeySanitizerCache;
|
||||
use CuyZ\Valinor\Tests\Fake\Cache\FakeCache;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
use function iterator_to_array;
|
||||
|
||||
final class VersionedCacheTest extends TestCase
|
||||
final class KeySanitizerCacheTest extends TestCase
|
||||
{
|
||||
private FakeCache $delegate;
|
||||
|
||||
/** @var VersionedCache<mixed> */
|
||||
private VersionedCache $cache;
|
||||
/** @var KeySanitizerCache<mixed> */
|
||||
private KeySanitizerCache $cache;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->delegate = new FakeCache();
|
||||
$this->cache = new VersionedCache($this->delegate);
|
||||
$this->cache = new KeySanitizerCache($this->delegate);
|
||||
}
|
||||
|
||||
public function test_set_value_sets_value_in_delegate_with_changed_key(): void
|
Loading…
Reference in New Issue
Block a user