1
0

Run 'compose update'

This commit is contained in:
onli
2021-04-27 21:30:20 +02:00
parent 05f58f90d7
commit 717282a58a
315 changed files with 35191 additions and 987 deletions

View File

@ -1,3 +1,30 @@
# Changelog 4.0.5 (2020-03-15)
- fix "symfony/var-exporter" for OpCache
# Changelog 4.0.4 (2020-03-15)
- use "symfony/var-exporter" for OpCache
-> better performance, because we don't need to serialize the data
-> but it's optional, because it required PHP >= 7.1
# Changelog 4.0.3 (2019-11-18)
- "iSerializer" -> add "getName()"
- fix usage of "file_put_contents"
- fix errors from php 7.4
- fix return of "CacheChain" (return true, if one cache-instance was successfully)
# Changelog 4.0.2 (2019-04-23)
- fix errors reported by phpstan (level 7)
- fix for APC(u) + CLI usage
- fix & new tests for "CacheChain" -> now accepts Cache objects instead of "iCache"
# Changelog 4.0.1 (2019-03-03)
- hide "warning" about Zend OPcache API is restricted by "restrict_api"

View File

@ -27,6 +27,10 @@
"require-dev": {
"phpunit/phpunit": "~6.0 || ~7.0"
},
"suggest": {
"symfony/var-exporter" : "~3.0 || ~4.0 || ~5.0",
"predis/predis": "~1.1"
},
"autoload": {
"psr-4": {
"voku\\cache\\": "src/voku/cache/"

View File

@ -0,0 +1,21 @@
parameters:
level: max
paths:
- %currentWorkingDirectory%/src/
reportUnmatchedIgnoredErrors: false
checkMissingIterableValueType: false
excludes_analyse:
- %currentWorkingDirectory%/vendor/*
- %currentWorkingDirectory%/tests/*
autoload_files:
- %currentWorkingDirectory%/vendor/autoload.php
ignoreErrors:
- '/always false/'
- '/always true/'
- '/Predis\\Client/'
- '/Symfony\\Component\\VarExporter/'
- '/Memcache(d)*/'
- '/MEMCACHE_COMPRESSED/'
- '/Function checkForDev not found\./'
- '/Function msgpack/'
- '/function unserialize expects array/'

View File

@ -43,6 +43,8 @@ class AdapterApc implements iAdapter
&&
\ini_get('apc.enable_cli')
) {
\ini_set('apc.use_request_time', '0');
$this->installed = true;
}
}
@ -85,12 +87,19 @@ class AdapterApc implements iAdapter
* @param bool $limited - If $limited is TRUE, the return value will exclude the individual list of cache
* entries. This is useful when trying to optimize calls for statistics gathering
*
* @return array|false
* <p>Array of cached data (and meta-data) or FALSE on failure.</p>
* @return array
* <p>Array of cached data (and meta-data) or empty array on failure.</p>
*/
public function cacheInfo(string $type = '', bool $limited = false): array
{
return \apc_cache_info($type, $limited);
/** @var array|false $return */
$return = \apc_cache_info($type, $limited);
if ($return === false) {
return [];
}
return $return;
}
/**

View File

@ -43,6 +43,8 @@ class AdapterApcu implements iAdapter
&&
\ini_get('apc.enable_cli')
) {
\ini_set('apc.use_request_time', '0');
$this->installed = true;
}
}
@ -84,12 +86,19 @@ class AdapterApcu implements iAdapter
* @param bool $limited - If $limited is TRUE, the return value will exclude the individual list of cache
* entries. This is useful when trying to optimize calls for statistics gathering
*
* @return array|false
* <p>Array of cached data (and meta-data) or FALSE on failure.</p>
* @return array
* <p>Array of cached data (and meta-data) or empty array on failure.</p>
*/
public function cacheInfo(bool $limited = false): array
{
return \apcu_cache_info($limited);
/** @var array|false $return */
$return = \apcu_cache_info($limited);
if ($return === false) {
return [];
}
return $return;
}
/**

View File

@ -15,7 +15,7 @@ class AdapterArray implements iAdapter
private static $values = [];
/**
* @var array
* @var array<string, array<int>>
*/
private static $expired = [];
@ -89,7 +89,7 @@ class AdapterArray implements iAdapter
{
self::$values[$key] = $value;
if ($ttl !== null) {
if ($ttl !== 0) {
self::$expired[$key] = [\time(), $ttl];
}
@ -114,6 +114,8 @@ class AdapterArray implements iAdapter
}
list($time, $ttl) = self::$expired[$key];
\assert(\is_int($time));
\assert(\is_int($ttl));
if (\time() > ($time + $ttl)) {
unset(self::$values[$key]);

View File

@ -34,7 +34,7 @@ abstract class AdapterFileAbstract implements iAdapter
protected $fileMode = '0755';
/**
* @param \callable|string|null $cacheDir
* @param callable|string|null $cacheDir
*/
public function __construct($cacheDir = null)
{
@ -204,6 +204,8 @@ abstract class AdapterFileAbstract implements iAdapter
* e.g. '0777', or '0755' ...
*
* @param string $fileMode
*
* @return void
*/
public function setFileMode($fileMode)
{
@ -243,4 +245,56 @@ abstract class AdapterFileAbstract implements iAdapter
return true;
}
/**
* copy&past from https://github.com/webimpress/safe-writer (thx @michalbundyra)
*
* @param string $file
* @param string $content
* @param int|null $chmod
*
* @return bool
*/
protected function writeFile($file, $content, $chmod = null): bool
{
if (!$file) {
return false;
}
if ($chmod === null) {
$chmod = \intval($this->fileMode, 8);
}
$dir = \dirname($file);
$tmp = \tempnam($dir, 'wsw');
if ($tmp === false) {
throw Exception\RuntimeException::unableToCreateTemporaryFile($dir);
}
if (\file_put_contents($tmp, $content) === false) {
\unlink($tmp);
throw Exception\WriteContentException::unableToWriteContent($tmp);
}
if (\chmod($tmp, $chmod & ~\umask()) === false) {
\unlink($tmp);
throw Exception\ChmodException::unableToChangeChmod($tmp);
}
// On windows try again if rename was not successful but target file is writable.
/** @noinspection PhpUsageOfSilenceOperatorInspection */
while (@\rename($tmp, $file) === false) {
if (\is_writable($file) && \stripos(\PHP_OS, 'WIN') === 0) {
continue;
}
\unlink($tmp);
throw Exception\RenameException::unableToMoveFile($tmp, $file);
}
return true;
}
}

View File

@ -11,6 +11,9 @@ class AdapterFileSimple extends AdapterFileAbstract
{
const CACHE_FILE_PREFIX = '__simple_';
/**
* @return resource
*/
protected function getContext()
{
static $CONTEXT_CACHE = null;
@ -74,16 +77,14 @@ class AdapterFileSimple extends AdapterFileAbstract
*/
public function setExpired(string $key, $value, int $ttl = 0): bool
{
return (bool) \file_put_contents(
return $this->writeFile(
$this->getFileName($key),
$this->serializer->serialize(
[
'value' => $value,
'ttl' => $ttl ? $ttl + \time() : 0,
]
),
0,
$this->getContext()
)
);
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace voku\cache;
use Memcache;
use voku\cache\Exception\InvalidArgumentException;
/**
@ -17,7 +18,7 @@ class AdapterMemcache implements iAdapter
public $installed = false;
/**
* @var \Memcache
* @var Memcache
*/
private $memcache;
@ -29,19 +30,19 @@ class AdapterMemcache implements iAdapter
/**
* __construct
*
* @param \Memcache|null $memcache
* @param Memcache|null $memcache
*/
public function __construct($memcache = null)
{
if ($memcache instanceof \Memcache) {
if ($memcache instanceof Memcache) {
$this->setMemcache($memcache);
}
}
/**
* @param \Memcache $memcache
* @param Memcache $memcache
*/
public function setMemcache(\Memcache $memcache)
public function setMemcache(Memcache $memcache)
{
$this->memcache = $memcache;
$this->installed = true;

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace voku\cache;
use Memcached;
use voku\cache\Exception\InvalidArgumentException;
/**
@ -17,26 +18,26 @@ class AdapterMemcached implements iAdapter
public $installed = false;
/**
* @var \Memcached
* @var Memcached
*/
private $memcached;
/**
* __construct
*
* @param \Memcached|null $memcached
* @param Memcached|null $memcached
*/
public function __construct($memcached = null)
{
if ($memcached instanceof \Memcached) {
if ($memcached instanceof Memcached) {
$this->setMemcached($memcached);
}
}
/**
* @param \Memcached $memcached
* @param Memcached $memcached
*/
public function setMemcached(\Memcached $memcached)
public function setMemcached(Memcached $memcached)
{
$this->memcached = $memcached;
$this->installed = true;
@ -90,7 +91,7 @@ class AdapterMemcached implements iAdapter
public function set(string $key, $value): bool
{
// Make sure we are under the proper limit
if (\strlen($this->memcached->getOption(\Memcached::OPT_PREFIX_KEY) . $key) > 250) {
if (\strlen($this->memcached->getOption(Memcached::OPT_PREFIX_KEY) . $key) > 250) {
throw new InvalidArgumentException('The passed cache key is over 250 bytes:' . \print_r($key, true));
}
@ -111,18 +112,22 @@ class AdapterMemcached implements iAdapter
/**
* Set the MemCached settings.
*
* @noinspection PhpUndefinedClassConstantInspection -> MSGPACK is not added into phpstorm stubs
*/
private function setSettings()
{
// Use faster compression if available
if (\Memcached::HAVE_IGBINARY) {
$this->memcached->setOption(\Memcached::OPT_SERIALIZER, \Memcached::SERIALIZER_IGBINARY);
if (Memcached::HAVE_IGBINARY) {
$this->memcached->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_IGBINARY);
} elseif (\defined('Memcached::HAVE_MSGPACK') && Memcached::HAVE_MSGPACK) {
$this->memcached->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_MSGPACK);
}
$this->memcached->setOption(\Memcached::OPT_DISTRIBUTION, \Memcached::DISTRIBUTION_CONSISTENT);
$this->memcached->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$this->memcached->setOption(\Memcached::OPT_NO_BLOCK, true);
$this->memcached->setOption(\Memcached::OPT_TCP_NODELAY, true);
$this->memcached->setOption(\Memcached::OPT_COMPRESSION, false);
$this->memcached->setOption(\Memcached::OPT_CONNECT_TIMEOUT, 2);
$this->memcached->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$this->memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$this->memcached->setOption(Memcached::OPT_NO_BLOCK, true);
$this->memcached->setOption(Memcached::OPT_TCP_NODELAY, true);
$this->memcached->setOption(Memcached::OPT_COMPRESSION, false);
$this->memcached->setOption(Memcached::OPT_CONNECT_TIMEOUT, 2);
}
}

View File

@ -79,6 +79,10 @@ class AdapterOpCache extends AdapterFileSimple
/**
* {@inheritdoc}
*
* @noinspection PhpUndefinedClassInspection
* @noinspection PhpUndefinedNamespaceInspection
* @noinspection BadExceptionsProcessingInspection
*/
public function setExpired(string $key, $value, int $ttl = 0): bool
{
@ -86,17 +90,23 @@ class AdapterOpCache extends AdapterFileSimple
'value' => $value,
'ttl' => $ttl ? $ttl + \time() : 0,
];
$content = \var_export($item, true);
if (\class_exists('\Symfony\Component\VarExporter\VarExporter')) {
try {
$content = \Symfony\Component\VarExporter\VarExporter::export($item);
} catch (\Symfony\Component\VarExporter\Exception\ExceptionInterface $e) {
$content = \var_export($item, true);
}
} else {
$content = \var_export($item, true);
}
$content = '<?php return ' . $content . ';';
$cacheFile = $this->getFileName($key);
$result = (bool) \file_put_contents(
$result = $this->writeFile(
$cacheFile,
$content,
0,
$this->getContext()
$content
);
if (

View File

@ -33,6 +33,8 @@ class AdapterPredis implements iAdapter
/**
* @param Client $client
*
* @return void
*/
public function setPredisClient(Client $client)
{
@ -45,7 +47,7 @@ class AdapterPredis implements iAdapter
*/
public function exists(string $key): bool
{
return $this->client->exists($key);
return (bool) $this->client->exists($key);
}
/**
@ -69,7 +71,7 @@ class AdapterPredis implements iAdapter
*/
public function remove(string $key): bool
{
return $this->client->del($key);
return (bool) $this->client->del($key);
}
/**
@ -93,6 +95,6 @@ class AdapterPredis implements iAdapter
*/
public function setExpired(string $key, $value, int $ttl = 0): bool
{
return $this->client->setex($key, $ttl, $value);
return (bool) $this->client->setex($key, $ttl, $value);
}
}

View File

@ -9,6 +9,9 @@ namespace voku\cache;
*/
class AdapterXcache implements iAdapter
{
/**
* @var bool
*/
public $installed = false;
/**

View File

@ -44,6 +44,11 @@ class Cache implements iCache
*/
protected $serializer;
/**
* @var array
*/
protected $unserialize_options = ['allowed_classes' => true];
/**
* @var string
*/
@ -92,27 +97,30 @@ class Cache implements iCache
/**
* __construct
*
* @param iAdapter|null $adapter
* @param iSerializer|null $serializer
* @param bool $checkForUsage <p>check for admin-session && check for
* server-ip == client-ip
* && check for dev</p>
* @param bool $cacheEnabled <p>false === disable the cache (use it
* e.g. for global settings)</p>
* @param bool $isAdminSession <p>true === disable cache for this user
* (use it e.g. for admin user settings)
* @param bool $useCheckForAdminSession <p>use $isAdminSession flag or not</p>
* @param bool $useCheckForDev <p>use checkForDev() or not</p>
* @param bool $useCheckForServerIpIsClientIp <p>use check for server-ip == client-ip
* or
* not</p>
* @param string $disableCacheGetParameter <p>set the _GET parameter for disabling
* the cache, disable this check via empty
* string</p>
* @param CacheAdapterAutoManager $cacheAdapterManagerForAutoConnect <p>Overwrite some Adapters for the
* auto-connect-function.</p>
* @param bool $cacheAdapterManagerForAutoConnectOverwrite <p>true === Use only Adapters from your
* "CacheAdapterManager".</p>
* @param iAdapter|null $adapter
* @param iSerializer|null $serializer
* @param bool $checkForUsage <p>check for admin-session && check
* for server-ip == client-ip
* && check for dev</p>
* @param bool $cacheEnabled <p>false === disable the cache (use
* it
* e.g. for global settings)</p>
* @param bool $isAdminSession <p>true === disable cache for this
* user
* (use it e.g. for admin user settings)
* @param bool $useCheckForAdminSession <p>use $isAdminSession flag or
* not</p>
* @param bool $useCheckForDev <p>use checkForDev() or not</p>
* @param bool $useCheckForServerIpIsClientIp <p>use check for server-ip ==
* client-ip or not</p>
* @param string $disableCacheGetParameter <p>set the _GET parameter for
* disabling the cache, disable this
* check via empty string</p>
* @param CacheAdapterAutoManager $cacheAdapterManagerForAutoConnect <p>Overwrite some Adapters for the
* auto-connect-function.</p>
* @param bool $cacheAdapterManagerForAutoConnectOverwrite <p>true === Use only Adapters from
* your
* "CacheAdapterManager".</p>
*/
public function __construct(
iAdapter $adapter = null,
@ -153,13 +161,20 @@ class Cache implements iCache
$adapter = $this->autoConnectToAvailableCacheSystem($cacheAdapterManagerForAutoConnect, $cacheAdapterManagerForAutoConnectOverwrite);
}
// INFO: Memcache(d) has his own "serializer", so don't use it twice
if (!\is_object($serializer) && $serializer === null) {
if (
$adapter instanceof AdapterMemcached
||
$adapter instanceof AdapterMemcache
) {
// INFO: Memcache(d) has his own "serializer", so don't use it twice
$serializer = new SerializerNo();
} elseif (
$adapter instanceof AdapterOpCache
&&
\class_exists('\Symfony\Component\VarExporter\VarExporter')
) {
// INFO: opcache + Symfony-VarExporter don't need any "serializer"
$serializer = new SerializerNo();
} else {
// set default serializer
@ -177,17 +192,31 @@ class Cache implements iCache
$this->setCacheIsReady(true);
$this->adapter = $adapter;
$this->serializer = $serializer;
$this->serializer->setUnserializeOptions($this->unserialize_options);
}
}
/**
* @param array $array
*
* @return void
*/
public function setUnserializeOptions(array $array = [])
{
$this->unserialize_options = $array;
}
/**
* Auto-connect to the available cache-system on the server.
*
* @param CacheAdapterAutoManager $cacheAdapterManagerForAutoConnect <p>Overwrite some Adapters for the
* auto-connect-function.</p>
* @param bool $cacheAdapterManagerForAutoConnectOverwrite <p>true === Use only Adapters from your
* "CacheAdapterManager".</p>
* auto-connect-function.</p>
* @param bool $cacheAdapterManagerForAutoConnectOverwrite <p>true === Use only Adapters from
* your
* "CacheAdapterManager".</p>
*
* @return iAdapter
*/
@ -381,7 +410,11 @@ class Cache implements iCache
}
$serialized = $this->adapter->get($storeKey);
$value = $serialized && $this->serializer ? $this->serializer->unserialize($serialized) : null;
if ($this->serializer && $this->serializer instanceof SerializerNo) {
$value = $serialized;
} else {
$value = $serialized && $this->serializer ? $this->serializer->unserialize($serialized) : null;
}
self::$STATIC_CACHE_COUNTER[$storeKey]++;
@ -468,7 +501,7 @@ class Cache implements iCache
* @param mixed $value
* @param \DateInterval|int|null $ttl
*
* @throws InvalidArgumentException
* @throws \InvalidArgumentException
*
* @return bool
*/
@ -493,7 +526,6 @@ class Cache implements iCache
if ($ttl) {
if ($ttl instanceof \DateInterval) {
// Converting to a TTL in seconds
/** @noinspection PhpUnhandledExceptionInspection */
$ttl = (new \DateTimeImmutable('now'))->add($ttl)->getTimestamp() - \time();
}
@ -593,6 +625,8 @@ class Cache implements iCache
/**
* Set the default-prefix via "SERVER"-var + "SESSION"-language.
*
* @return string
*/
protected function getTheDefaultPrefix(): string
{
@ -600,18 +634,21 @@ class Cache implements iCache
($_SERVER['THEME'] ?? '') . '_' .
($_SERVER['STAGE'] ?? '') . '_' .
($_SESSION['language'] ?? '') . '_' .
($_SESSION['language_extra'] ?? '');
($_SESSION['language_extra'] ?? '') . '_' .
\PHP_VERSION_ID . '_' .
($this->serializer ? $this->serializer->getName() : '');
}
/**
* Get the current adapter class-name.
*
* @return string
*
* @psalm-return class-string|string
*/
public function getUsedAdapterClassName(): string
{
if ($this->adapter) {
/** @noinspection GetClassUsageInspection */
return \get_class($this->adapter);
}
@ -622,11 +659,12 @@ class Cache implements iCache
* Get the current serializer class-name.
*
* @return string
*
* @psalm-return class-string|string
*/
public function getUsedSerializerClassName(): string
{
if ($this->serializer) {
/** @noinspection GetClassUsageInspection */
return \get_class($this->serializer);
}
@ -640,6 +678,7 @@ class Cache implements iCache
*/
public function isCacheActiveForTheCurrentUser(): bool
{
// init
$active = true;
// test the cache, with this GET-parameter
@ -685,6 +724,8 @@ class Cache implements iCache
* enable / disable the cache
*
* @param bool $isActive
*
* @return void
*/
public function setActive(bool $isActive)
{
@ -695,6 +736,8 @@ class Cache implements iCache
* Set "isReady" state.
*
* @param bool $isReady
*
* @return void
*/
protected function setCacheIsReady(bool $isReady)
{
@ -707,6 +750,8 @@ class Cache implements iCache
* WARNING: Do not use if you don't know what you do. Because this will overwrite the default prefix.
*
* @param string $prefix
*
* @return void
*/
public function setPrefix(string $prefix)
{
@ -717,6 +762,8 @@ class Cache implements iCache
* Set the static-hit-counter: Who often do we hit the cache, before we use static cache?
*
* @param int $staticCacheHitCounter
*
* @return void
*/
public function setStaticCacheHitCounter(int $staticCacheHitCounter)
{

View File

@ -22,6 +22,8 @@ class CacheAdapterAutoManager
* @param string $adapter
* @param callable|null $callableFunction
*
* @psalm-param class-string $adapter
*
* @throws InvalidArgumentException
*
* @return $this
@ -29,8 +31,7 @@ class CacheAdapterAutoManager
public function addAdapter(
string $adapter,
callable $callableFunction = null
): self
{
): self {
$this->validateAdapter($adapter);
$this->validateCallable($callableFunction);
@ -55,7 +56,7 @@ class CacheAdapterAutoManager
*
* @throws InvalidArgumentException
*
* @return CacheAdapterAutoManager
* @return self
*/
public function merge(self $adapterManager): self
{
@ -80,7 +81,11 @@ class CacheAdapterAutoManager
/**
* @param string $replaceAdapter
*
* @psalm-param class-string $replaceAdapter
*
* @throws InvalidArgumentException
*
* @return void
*/
private function validateAdapter(string $replaceAdapter)
{
@ -95,6 +100,8 @@ class CacheAdapterAutoManager
* @param callable $callableFunction
*
* @throws InvalidArgumentException
*
* @return void
*/
private function validateCallable(callable $callableFunction = null)
{
@ -170,6 +177,7 @@ class CacheAdapterAutoManager
) {
/** @noinspection PhpUndefinedNamespaceInspection */
/** @noinspection PhpUndefinedClassInspection */
/** @noinspection PhpFullyQualifiedNameUsageInspection */
$redis = new \Predis\Client(
[
'scheme' => 'tcp',

View File

@ -7,7 +7,7 @@ namespace voku\cache;
class CacheChain implements iCache
{
/**
* @var array|iCache[]
* @var Cache[]
*/
private $caches = [];
@ -40,17 +40,13 @@ class CacheChain implements iCache
/**
* add cache
*
* @param iCache $cache
* @param bool $prepend
* @param Cache $cache
* @param bool $prepend
*
* @throws \InvalidArgumentException
* @return void
*/
public function addCache(iCache $cache, $prepend = true)
public function addCache(Cache $cache, $prepend = true)
{
if ($this === $cache) {
throw new \InvalidArgumentException('loop-error, put into other cache');
}
if ($prepend) {
\array_unshift($this->caches, $cache);
} else {
@ -72,6 +68,22 @@ class CacheChain implements iCache
return null;
}
/**
* Get the "isReady" state.
*
* @return bool
*/
public function getCacheIsReady(): bool
{
foreach ($this->caches as $cache) {
if (!$cache->getCacheIsReady()) {
return false;
}
}
return true;
}
/**
* {@inheritdoc}
*/
@ -84,7 +96,7 @@ class CacheChain implements iCache
$results[] = $cache->setItem($key, $value, $ttl);
}
return !\in_array(false, $results, true);
return \in_array(true, $results, true);
}
/**
@ -95,12 +107,27 @@ class CacheChain implements iCache
// init
$results = [];
/* @var $cache iCache */
foreach ($this->caches as $cache) {
$results[] = $cache->setItemToDate($key, $value, $date);
}
return !\in_array(false, $results, true);
return \in_array(true, $results, true);
}
/**
* !!! Set the prefix. !!!
*
* WARNING: Do not use if you don't know what you do. Because this will overwrite the default prefix.
*
* @param string $prefix
*
* @return void
*/
public function setPrefix(string $prefix)
{
foreach ($this->caches as $cache) {
$cache->setPrefix($prefix);
}
}
/**
@ -115,7 +142,7 @@ class CacheChain implements iCache
$results[] = $cache->removeItem($key);
}
return !\in_array(false, $results, true);
return \in_array(true, $results, true);
}
/**
@ -144,6 +171,6 @@ class CacheChain implements iCache
$results[] = $cache->removeAll();
}
return !\in_array(false, $results, true);
return \in_array(true, $results, true);
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace voku\cache\Exception;
final class ChmodException extends \RuntimeException implements FileErrorExceptionInterface
{
/**
* @param string $file
*
* @return self
*/
public static function unableToChangeChmod($file)
{
return new self(\sprintf('Could not change chmod of the file "%s"', $file));
}
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace voku\cache\Exception;
interface FileErrorExceptionInterface
{
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace voku\cache\Exception;
final class RenameException extends \RuntimeException implements FileErrorExceptionInterface
{
/**
* @param string $source
* @param string $target
*
* @return self
*/
public static function unableToMoveFile($source, $target)
{
return new self(\sprintf(
'Could not move file "%s" to location "%s": '
. 'either the source file is not readable, or the destination is not writable',
$source,
$target
));
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace voku\cache\Exception;
final class RuntimeException extends \RuntimeException implements FileErrorExceptionInterface
{
/**
* @param string $dir
*
* @return self
*/
public static function unableToCreateTemporaryFile($dir)
{
return new self(\sprintf('Could not create temporary file in directory "%s"', $dir));
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace voku\cache\Exception;
final class WriteContentException extends \RuntimeException implements FileErrorExceptionInterface
{
/**
* @param string $file
*
* @return self
*/
public static function unableToWriteContent($file)
{
return new self(\sprintf('Could not write content to the file "%s"', $file));
}
}

View File

@ -9,6 +9,11 @@ namespace voku\cache;
*/
class SerializerDefault implements iSerializer
{
/**
* @var array|null
*/
private $unserialize_options;
/**
* {@inheritdoc}
*/
@ -17,11 +22,34 @@ class SerializerDefault implements iSerializer
return \serialize($value);
}
/**
* @return string
*/
public function getName(): string
{
return 'default';
}
/**
* {@inheritdoc}
*/
public function unserialize($value)
{
if ($this->unserialize_options !== null) {
return \unserialize($value, $this->unserialize_options);
}
/** @noinspection UnserializeExploitsInspection */
return \unserialize($value);
}
/**
* @param array $options
*
* @return void
*/
public function setUnserializeOptions(array $options)
{
$this->unserialize_options = $options;
}
}

View File

@ -14,16 +14,42 @@ class SerializerIgbinary implements iSerializer
*/
public static $_exists_igbinary;
/**
* @var array|null
*/
private $unserialize_options;
/**
* @var string
*/
private $name = '';
/**
* SerializerIgbinary constructor.
*/
public function __construct()
{
self::$_exists_igbinary = (
\function_exists('igbinary_serialize')
&&
\function_exists('igbinary_unserialize')
);
if (self::$_exists_igbinary === null) {
self::$_exists_igbinary = (
\function_exists('igbinary_serialize')
&&
\function_exists('igbinary_unserialize')
);
}
if (self::$_exists_igbinary) {
$this->name = 'igbinary';
} else {
$this->name = 'default';
}
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
@ -33,6 +59,7 @@ class SerializerIgbinary implements iSerializer
{
if (self::$_exists_igbinary === true) {
/** @noinspection PhpUndefinedFunctionInspection */
/** @noinspection PhpComposerExtensionStubsInspection */
return \igbinary_serialize($value);
}
@ -47,10 +74,26 @@ class SerializerIgbinary implements iSerializer
{
if (self::$_exists_igbinary === true) {
/** @noinspection PhpUndefinedFunctionInspection */
/** @noinspection PhpComposerExtensionStubsInspection */
return \igbinary_unserialize($value);
}
// fallback
if ($this->unserialize_options !== null) {
return \unserialize($value, $this->unserialize_options);
}
/** @noinspection UnserializeExploitsInspection */
return \unserialize($value);
}
/**
* @param array $options
*
* @return void
*/
public function setUnserializeOptions(array $options)
{
$this->unserialize_options = $options;
}
}

View File

@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace voku\cache;
/**
* SerializerMsgpack: serialize / unserialize
*/
class SerializerMsgpack implements iSerializer
{
/**
* @var bool
*/
public static $_exists_msgpack;
/**
* @var array|null
*/
private $unserialize_options;
/**
* @var string
*/
private $name = '';
/**
* SerializerIgbinary constructor.
*/
public function __construct()
{
if (self::$_exists_msgpack === null) {
self::$_exists_msgpack = (
\function_exists('msgpack_pack')
&&
\function_exists('msgpack_unpack')
);
}
if (self::$_exists_msgpack) {
$this->name = 'msgpack';
} else {
$this->name = 'default';
}
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function serialize($value)
{
if (self::$_exists_msgpack === true) {
/** @noinspection PhpUndefinedFunctionInspection */
return \msgpack_pack($value);
}
// fallback
return \serialize($value);
}
/**
* {@inheritdoc}
*/
public function unserialize($value)
{
if (self::$_exists_msgpack === true) {
/** @noinspection PhpUndefinedFunctionInspection */
return \msgpack_unpack($value);
}
// fallback
if ($this->unserialize_options !== null) {
return \unserialize($value, $this->unserialize_options);
}
/** @noinspection UnserializeExploitsInspection */
return \unserialize($value);
}
/**
* @param array $options
*
* @return void
*/
public function setUnserializeOptions(array $options)
{
$this->unserialize_options = $options;
}
}

View File

@ -24,4 +24,22 @@ class SerializerNo implements iSerializer
{
return $value;
}
/**
* @return string
*/
public function getName(): string
{
return 'no';
}
/**
* @param array $options
*
* @return void
*/
public function setUnserializeOptions(array $options)
{
// nothing to do here
}
}

View File

@ -14,7 +14,8 @@ interface iAdapter
*
* @param string $key
*
* @return mixed|null <p>will return NULL if the key not exists</p>
* @return mixed|null
* <p>will return NULL if the key not exists</p>
*/
public function get(string $key);

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace voku\cache;
use DateTimeInterface;
/**
* iCache: cache-global interface
*/
@ -34,11 +36,11 @@ interface iCache
*
* @param string $key
* @param mixed $value
* @param \DateTimeInterface $date
* @param DateTimeInterface $date
*
* @return bool
*/
public function setItemToDate(string $key, $value, \DateTimeInterface $date): bool;
public function setItemToDate(string $key, $value, DateTimeInterface $date): bool;
/**
* remove item

View File

@ -10,16 +10,28 @@ namespace voku\cache;
interface iSerializer
{
/**
* serialize
*
* @param mixed $value
*
* @return string
*/
public function serialize($value);
/**
* unserialize
*
* @param string $value
*
* @return mixed
*/
public function unserialize($value);
/**
* @param array $options
*
* @return void
*/
public function setUnserializeOptions(array $options);
/**
* @return string
*/
public function getName(): string;
}