premier commit
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Cache
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Cache\Adapter;
|
||||
|
||||
use DateInterval;
|
||||
use Grav\Framework\Cache\AbstractCache;
|
||||
use Grav\Framework\Cache\CacheInterface;
|
||||
use Grav\Framework\Cache\Exception\InvalidArgumentException;
|
||||
use function count;
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* Cache class for PSR-16 compatible "Simple Cache" implementation using chained cache adapters.
|
||||
*
|
||||
* @package Grav\Framework\Cache
|
||||
*/
|
||||
class ChainCache extends AbstractCache
|
||||
{
|
||||
/** @var CacheInterface[] */
|
||||
protected $caches;
|
||||
|
||||
/** @var int */
|
||||
protected $count;
|
||||
|
||||
/**
|
||||
* Chain Cache constructor.
|
||||
* @param array $caches
|
||||
* @param null|int|DateInterval $defaultLifetime
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(array $caches, $defaultLifetime = null)
|
||||
{
|
||||
try {
|
||||
parent::__construct('', $defaultLifetime);
|
||||
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if (!$caches) {
|
||||
throw new InvalidArgumentException('At least one cache must be specified');
|
||||
}
|
||||
|
||||
foreach ($caches as $cache) {
|
||||
if (!$cache instanceof CacheInterface) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
"The class '%s' does not implement the '%s' interface",
|
||||
get_class($cache),
|
||||
CacheInterface::class
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->caches = array_values($caches);
|
||||
$this->count = count($caches);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doGet($key, $miss)
|
||||
{
|
||||
foreach ($this->caches as $i => $cache) {
|
||||
$value = $cache->doGet($key, $miss);
|
||||
if ($value !== $miss) {
|
||||
while (--$i >= 0) {
|
||||
// Update all the previous caches with missing value.
|
||||
$this->caches[$i]->doSet($key, $value, $this->getDefaultLifetime());
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $miss;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doSet($key, $value, $ttl)
|
||||
{
|
||||
$success = true;
|
||||
$i = $this->count;
|
||||
|
||||
while ($i--) {
|
||||
$success = $this->caches[$i]->doSet($key, $value, $ttl) && $success;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doDelete($key)
|
||||
{
|
||||
$success = true;
|
||||
$i = $this->count;
|
||||
|
||||
while ($i--) {
|
||||
$success = $this->caches[$i]->doDelete($key) && $success;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doClear()
|
||||
{
|
||||
$success = true;
|
||||
$i = $this->count;
|
||||
|
||||
while ($i--) {
|
||||
$success = $this->caches[$i]->doClear() && $success;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doGetMultiple($keys, $miss)
|
||||
{
|
||||
$list = [];
|
||||
/**
|
||||
* @var int $i
|
||||
* @var CacheInterface $cache
|
||||
*/
|
||||
foreach ($this->caches as $i => $cache) {
|
||||
$list[$i] = $cache->doGetMultiple($keys, $miss);
|
||||
|
||||
$keys = array_diff_key($keys, $list[$i]);
|
||||
|
||||
if (!$keys) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update all the previous caches with missing values.
|
||||
$values = [];
|
||||
/**
|
||||
* @var int $i
|
||||
* @var CacheInterface $items
|
||||
*/
|
||||
foreach (array_reverse($list) as $i => $items) {
|
||||
$values += $items;
|
||||
if ($i && $values) {
|
||||
$this->caches[$i-1]->doSetMultiple($values, $this->getDefaultLifetime());
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doSetMultiple($values, $ttl)
|
||||
{
|
||||
$success = true;
|
||||
$i = $this->count;
|
||||
|
||||
while ($i--) {
|
||||
$success = $this->caches[$i]->doSetMultiple($values, $ttl) && $success;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doDeleteMultiple($keys)
|
||||
{
|
||||
$success = true;
|
||||
$i = $this->count;
|
||||
|
||||
while ($i--) {
|
||||
$success = $this->caches[$i]->doDeleteMultiple($keys) && $success;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doHas($key)
|
||||
{
|
||||
foreach ($this->caches as $cache) {
|
||||
if ($cache->doHas($key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Cache
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Cache\Adapter;
|
||||
|
||||
use DateInterval;
|
||||
use Doctrine\Common\Cache\CacheProvider;
|
||||
use Grav\Framework\Cache\AbstractCache;
|
||||
use Grav\Framework\Cache\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Cache class for PSR-16 compatible "Simple Cache" implementation using Doctrine Cache backend.
|
||||
* @package Grav\Framework\Cache
|
||||
*/
|
||||
class DoctrineCache extends AbstractCache
|
||||
{
|
||||
/** @var CacheProvider */
|
||||
protected $driver;
|
||||
|
||||
/**
|
||||
* Doctrine Cache constructor.
|
||||
*
|
||||
* @param CacheProvider $doctrineCache
|
||||
* @param string $namespace
|
||||
* @param null|int|DateInterval $defaultLifetime
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(CacheProvider $doctrineCache, $namespace = '', $defaultLifetime = null)
|
||||
{
|
||||
// Do not use $namespace or $defaultLifetime directly, store them with constructor and fetch with methods.
|
||||
try {
|
||||
parent::__construct($namespace, $defaultLifetime);
|
||||
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
// Set namespace to Doctrine Cache provider if it was given.
|
||||
$namespace = $this->getNamespace();
|
||||
if ($namespace) {
|
||||
$doctrineCache->setNamespace($namespace);
|
||||
}
|
||||
|
||||
$this->driver = $doctrineCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doGet($key, $miss)
|
||||
{
|
||||
$value = $this->driver->fetch($key);
|
||||
|
||||
// Doctrine cache does not differentiate between no result and cached 'false'. Make sure that we do.
|
||||
return $value !== false || $this->driver->contains($key) ? $value : $miss;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doSet($key, $value, $ttl)
|
||||
{
|
||||
return $this->driver->save($key, $value, (int) $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doDelete($key)
|
||||
{
|
||||
return $this->driver->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doClear()
|
||||
{
|
||||
return $this->driver->deleteAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doGetMultiple($keys, $miss)
|
||||
{
|
||||
return $this->driver->fetchMultiple($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doSetMultiple($values, $ttl)
|
||||
{
|
||||
return $this->driver->saveMultiple($values, (int) $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doDeleteMultiple($keys)
|
||||
{
|
||||
return $this->driver->deleteMultiple($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doHas($key)
|
||||
{
|
||||
return $this->driver->contains($key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Cache
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Cache\Adapter;
|
||||
|
||||
use ErrorException;
|
||||
use FilesystemIterator;
|
||||
use Grav\Framework\Cache\AbstractCache;
|
||||
use Grav\Framework\Cache\Exception\CacheException;
|
||||
use Grav\Framework\Cache\Exception\InvalidArgumentException;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use RuntimeException;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* Cache class for PSR-16 compatible "Simple Cache" implementation using file backend.
|
||||
*
|
||||
* Defaults to 1 year TTL. Does not support unlimited TTL.
|
||||
*
|
||||
* @package Grav\Framework\Cache
|
||||
*/
|
||||
class FileCache extends AbstractCache
|
||||
{
|
||||
/** @var string */
|
||||
private $directory;
|
||||
/** @var string|null */
|
||||
private $tmp;
|
||||
|
||||
/**
|
||||
* FileCache constructor.
|
||||
* @param string $namespace
|
||||
* @param int|null $defaultLifetime
|
||||
* @param string|null $folder
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException
|
||||
*/
|
||||
public function __construct($namespace = '', $defaultLifetime = null, $folder = null)
|
||||
{
|
||||
try {
|
||||
parent::__construct($namespace, $defaultLifetime ?: 31557600); // = 1 year
|
||||
|
||||
$this->initFileCache($namespace, $folder ?? '');
|
||||
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doGet($key, $miss)
|
||||
{
|
||||
$now = time();
|
||||
$file = $this->getFile($key);
|
||||
|
||||
if (!file_exists($file) || !$h = @fopen($file, 'rb')) {
|
||||
return $miss;
|
||||
}
|
||||
|
||||
if ($now >= (int) $expiresAt = fgets($h)) {
|
||||
fclose($h);
|
||||
@unlink($file);
|
||||
} else {
|
||||
$i = rawurldecode(rtrim((string)fgets($h)));
|
||||
$value = stream_get_contents($h) ?: '';
|
||||
fclose($h);
|
||||
|
||||
if ($i === $key) {
|
||||
return unserialize($value, ['allowed_classes' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
return $miss;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @throws CacheException
|
||||
*/
|
||||
public function doSet($key, $value, $ttl)
|
||||
{
|
||||
$expiresAt = time() + (int)$ttl;
|
||||
|
||||
$result = $this->write(
|
||||
$this->getFile($key, true),
|
||||
$expiresAt . "\n" . rawurlencode($key) . "\n" . serialize($value),
|
||||
$expiresAt
|
||||
);
|
||||
|
||||
if (!$result && !is_writable($this->directory)) {
|
||||
throw new CacheException(sprintf('Cache directory is not writable (%s)', $this->directory));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doDelete($key)
|
||||
{
|
||||
$file = $this->getFile($key);
|
||||
|
||||
$result = false;
|
||||
if (file_exists($file)) {
|
||||
$result = @unlink($file);
|
||||
$result &= !file_exists($file);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doClear()
|
||||
{
|
||||
$result = true;
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->directory, FilesystemIterator::SKIP_DOTS));
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
$result = ($file->isDir() || @unlink($file) || !file_exists($file)) && $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function doHas($key)
|
||||
{
|
||||
$file = $this->getFile($key);
|
||||
|
||||
return file_exists($file) && (@filemtime($file) > time() || $this->doGet($key, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param bool $mkdir
|
||||
* @return string
|
||||
*/
|
||||
protected function getFile($key, $mkdir = false)
|
||||
{
|
||||
$hash = str_replace('/', '-', base64_encode(hash('sha256', static::class . $key, true)));
|
||||
$dir = $this->directory . $hash[0] . DIRECTORY_SEPARATOR . $hash[1] . DIRECTORY_SEPARATOR;
|
||||
|
||||
if ($mkdir) {
|
||||
$this->mkdir($dir);
|
||||
}
|
||||
|
||||
return $dir . substr($hash, 2, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @param string $directory
|
||||
* @return void
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function initFileCache($namespace, $directory)
|
||||
{
|
||||
if ($directory === '') {
|
||||
$directory = sys_get_temp_dir() . '/grav-cache';
|
||||
} else {
|
||||
$directory = realpath($directory) ?: $directory;
|
||||
}
|
||||
|
||||
if (isset($namespace[0])) {
|
||||
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
|
||||
throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
|
||||
}
|
||||
$directory .= DIRECTORY_SEPARATOR . $namespace;
|
||||
}
|
||||
|
||||
$this->mkdir($directory);
|
||||
|
||||
$directory .= DIRECTORY_SEPARATOR;
|
||||
// On Windows the whole path is limited to 258 chars
|
||||
if ('\\' === DIRECTORY_SEPARATOR && strlen($directory) > 234) {
|
||||
throw new InvalidArgumentException(sprintf('Cache folder is too long (%s)', $directory));
|
||||
}
|
||||
$this->directory = $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param string $data
|
||||
* @param int|null $expiresAt
|
||||
* @return bool
|
||||
*/
|
||||
private function write($file, $data, $expiresAt = null)
|
||||
{
|
||||
set_error_handler(__CLASS__.'::throwError');
|
||||
|
||||
try {
|
||||
if ($this->tmp === null) {
|
||||
$this->tmp = $this->directory . uniqid('', true);
|
||||
}
|
||||
|
||||
file_put_contents($this->tmp, $data);
|
||||
|
||||
if ($expiresAt !== null) {
|
||||
touch($this->tmp, $expiresAt);
|
||||
}
|
||||
|
||||
return rename($this->tmp, $file);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dir
|
||||
* @return void
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function mkdir($dir)
|
||||
{
|
||||
// Silence error for open_basedir; should fail in mkdir instead.
|
||||
if (@is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$success = @mkdir($dir, 0777, true);
|
||||
|
||||
if (!$success) {
|
||||
// Take yet another look, make sure that the folder doesn't exist.
|
||||
clearstatcache(true, $dir);
|
||||
if (!@is_dir($dir)) {
|
||||
throw new RuntimeException(sprintf('Unable to create directory: %s', $dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
* @param string $message
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
* @return bool
|
||||
* @internal
|
||||
* @throws ErrorException
|
||||
*/
|
||||
public static function throwError($type, $message, $file, $line)
|
||||
{
|
||||
throw new ErrorException($message, 0, $type, $file, $line);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->tmp !== null && file_exists($this->tmp)) {
|
||||
unlink($this->tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Cache
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Cache\Adapter;
|
||||
|
||||
use Grav\Framework\Cache\AbstractCache;
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* Cache class for PSR-16 compatible "Simple Cache" implementation using in memory backend.
|
||||
*
|
||||
* Memory backend does not use namespace or default ttl as the cache is unique to each cache object and request.
|
||||
*
|
||||
* @package Grav\Framework\Cache
|
||||
*/
|
||||
class MemoryCache extends AbstractCache
|
||||
{
|
||||
/** @var array */
|
||||
protected $cache = [];
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $miss
|
||||
* @return mixed
|
||||
*/
|
||||
public function doGet($key, $miss)
|
||||
{
|
||||
if (!array_key_exists($key, $this->cache)) {
|
||||
return $miss;
|
||||
}
|
||||
|
||||
return $this->cache[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function doSet($key, $value, $ttl)
|
||||
{
|
||||
$this->cache[$key] = $value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function doDelete($key)
|
||||
{
|
||||
unset($this->cache[$key]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function doClear()
|
||||
{
|
||||
$this->cache = [];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function doHas($key)
|
||||
{
|
||||
return array_key_exists($key, $this->cache);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Cache
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Cache\Adapter;
|
||||
|
||||
use Grav\Framework\Cache\AbstractCache;
|
||||
|
||||
/**
|
||||
* Cache class for PSR-16 compatible "Simple Cache" implementation using session backend.
|
||||
*
|
||||
* @package Grav\Framework\Cache
|
||||
*/
|
||||
class SessionCache extends AbstractCache
|
||||
{
|
||||
public const VALUE = 0;
|
||||
public const LIFETIME = 1;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $miss
|
||||
* @return mixed
|
||||
*/
|
||||
public function doGet($key, $miss)
|
||||
{
|
||||
$stored = $this->doGetStored($key);
|
||||
|
||||
return $stored ? $stored[self::VALUE] : $miss;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $ttl
|
||||
* @return bool
|
||||
*/
|
||||
public function doSet($key, $value, $ttl)
|
||||
{
|
||||
$stored = [self::VALUE => $value];
|
||||
if (null !== $ttl) {
|
||||
$stored[self::LIFETIME] = time() + $ttl;
|
||||
}
|
||||
|
||||
$_SESSION[$this->getNamespace()][$key] = $stored;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function doDelete($key)
|
||||
{
|
||||
unset($_SESSION[$this->getNamespace()][$key]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function doClear()
|
||||
{
|
||||
unset($_SESSION[$this->getNamespace()]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function doHas($key)
|
||||
{
|
||||
return $this->doGetStored($key) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return 'cache-' . parent::getNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed|null
|
||||
*/
|
||||
protected function doGetStored($key)
|
||||
{
|
||||
$stored = $_SESSION[$this->getNamespace()][$key] ?? null;
|
||||
|
||||
if (isset($stored[self::LIFETIME]) && $stored[self::LIFETIME] < time()) {
|
||||
unset($_SESSION[$this->getNamespace()][$key]);
|
||||
$stored = null;
|
||||
}
|
||||
|
||||
return $stored ?: null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user