initial commit; version 22.5.12042

This commit is contained in:
2022-12-12 23:28:25 -05:00
commit af1b03d79f
17653 changed files with 22692970 additions and 0 deletions

169
libs/Phpfastcache8/Api.php Normal file
View File

@ -0,0 +1,169 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache;
use Phpfastcache\Exceptions\PhpfastcacheIOException;
use Phpfastcache\Exceptions\PhpfastcacheLogicException;
/**
* Class Api
* @package phpFastCache
*/
class Api
{
protected static $version = '3.0.0';
/**
* Api constructor.
*/
final protected function __construct()
{
// The Api is not meant to be instantiated
}
/**
* This method will returns the current
* API version, the API version will be
* updated by following the semantic versioning
* based on changes of:
* - ExtendedCacheItemPoolInterface
* - ExtendedCacheItemInterface
* - AggregatablePoolInterface
* - AggregatorInterface
* - ClusterPoolInterface
* - EventManagerInterface
*
* @see https://semver.org/
* @return string
*/
public static function getVersion(): string
{
return self::$version;
}
/**
* @param bool $fallbackOnChangelog
* @param bool $cacheable
* @return string
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheIOException
*/
public static function getPhpFastCacheVersion(bool $fallbackOnChangelog = true, bool $cacheable = true): string
{
/**
* Cache the version statically to improve
* performances on multiple calls
*/
static $version;
if ($version && $cacheable) {
return $version;
}
if (\function_exists('shell_exec')) {
$command = 'git -C "' . __DIR__ . '" describe --abbrev=0 --tags';
$stdout = \shell_exec($command);
if (\is_string($stdout)) {
$version = trim($stdout);
return $version;
}
if (!$fallbackOnChangelog) {
throw new PhpfastcacheLogicException('The git command used to retrieve the PhpFastCache version has failed.');
}
}
if (!$fallbackOnChangelog) {
throw new PhpfastcacheLogicException('shell_exec is disabled therefore the PhpFastCache version cannot be retrieved.');
}
$changelogFilename = __DIR__ . '/../../CHANGELOG.md';
if (\file_exists($changelogFilename)) {
$versionPrefix = '## ';
$changelog = \explode("\n", self::getPhpFastCacheChangelog());
foreach ($changelog as $line) {
if (\strpos($line, $versionPrefix) === 0) {
$version = \trim(\str_replace($versionPrefix, '', $line));
return $version;
}
}
throw new PhpfastcacheLogicException('Unable to retrieve the PhpFastCache version through the CHANGELOG.md as no valid string were found in it.');
}
throw new PhpfastcacheLogicException(
'shell_exec being disabled we attempted to retrieve the PhpFastCache version through the CHANGELOG.md file but it is not readable or has been removed.'
);
}
/**
* Return the PhpFastCache changelog, as a string.
* @return string
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheIOException
*/
public static function getPhpFastCacheChangelog(): string
{
$changelogFilename = __DIR__ . '/../../CHANGELOG.md';
if (\file_exists($changelogFilename)) {
$string = \str_replace(["\r\n", "\r"], "\n", \trim(\file_get_contents($changelogFilename)));
if ($string) {
return $string;
}
throw new PhpfastcacheLogicException('Unable to retrieve the PhpFastCache changelog as it seems to be empty.');
}
throw new PhpfastcacheIOException('The CHANGELOG.md file is not readable or has been removed.');
}
/**
* @param bool $cacheable
* @return string
*/
public static function getPhpFastCacheGitHeadHash(bool $cacheable = true): string
{
static $hash;
if ($hash && $cacheable) {
return $hash;
}
if (\function_exists('shell_exec')) {
$stdout = \shell_exec('git rev-parse --short HEAD');
if (\is_string($stdout)) {
$hash = \trim($stdout);
return "#{$hash}";
}
}
return '';
}
/**
* Return the API changelog, as a string.
* @return string
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheIOException
*/
public static function getChangelog(): string
{
$changelogFilename = __DIR__ . '/../../CHANGELOG_API.md';
if (\file_exists($changelogFilename)) {
$string = \str_replace(["\r\n", "\r"], "\n", \trim(\file_get_contents($changelogFilename)));
if ($string) {
return $string;
}
throw new PhpfastcacheLogicException('Unable to retrieve the PhpFastCache API changelog as it seems to be empty.');
}
throw new PhpfastcacheIOException('The CHANGELOG_API.md file is not readable or has been removed.');
}
}

View File

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Phpfastcache\Autoload;
use Composer\Autoload\ClassLoader;
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
const PFC_PHP_EXT = 'php';
const PFC_BIN_DIR = __DIR__ . '/../../../bin/';
const PFC_LIB_DIR = __DIR__ . '/../../../lib/';
const PFC_TESTS_DIR = __DIR__ . '/../../../tests/lib/';
const PFC_TESTS_NS = 'Phpfastcache\\Tests\\';
\trigger_error('The legacy autoload will be removed in the next major release. Please include Phpfastcache through composer by running `composer require phpfastcache/phpfastcache`.', \E_USER_DEPRECATED);
/**
* Register Autoload
*/
spl_autoload_register(
static function ($entity): void {
$module = explode('\\', $entity, 2);
if (!\in_array($module[0], ['Phpfastcache', 'Psr'])) {
/**
* Not a part of phpFastCache file
* then we return here.
*/
return;
}
if (\strpos($entity, 'Psr\Cache') === 0) {
$path = PFC_BIN_DIR . 'dependencies/Psr/Cache/src/' . substr(strrchr($entity, '\\'), 1) . '.' . PFC_PHP_EXT;
if (\is_readable($path)) {
require_once $path;
} else {
\trigger_error('Cannot locate the Psr/Cache files', E_USER_ERROR);
}
return;
}
if (\strpos($entity, 'Psr\SimpleCache') === 0) {
$path = PFC_BIN_DIR . 'dependencies/Psr/SimpleCache/src/' . \substr(\strrchr($entity, '\\'), 1) . '.' . PFC_PHP_EXT;
if (\is_readable($path)) {
require_once $path;
} else {
\trigger_error('Cannot locate the Psr/SimpleCache files', E_USER_ERROR);
}
return;
}
$entityPath = str_replace('\\', '/', $entity);
if(\strpos($entity, PFC_TESTS_NS) === 0){
$path = PFC_TESTS_DIR . \str_replace(str_replace('\\', '/', PFC_TESTS_NS), '', $entityPath) . '.' . PFC_PHP_EXT;
}else{
$path = PFC_LIB_DIR . $entityPath . '.' . PFC_PHP_EXT;
}
$path = \realpath($path);
if (\is_readable($path)) {
require_once $path;
}
}
);
if ((!\defined('PFC_IGNORE_COMPOSER_WARNING') || !PFC_IGNORE_COMPOSER_WARNING) && \class_exists(ClassLoader::class)) {
trigger_error(
'Your project already makes use of Composer. You SHOULD use the composer dependency "phpfastcache/phpfastcache" instead of hard-autoloading.',
E_USER_WARNING
);
}

View File

@ -0,0 +1,505 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Config\ConfigurationOptionInterface;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Exceptions\{PhpfastcacheDriverCheckException,
PhpfastcacheDriverException,
PhpfastcacheDriverNotFoundException,
PhpfastcacheInstanceNotFoundException,
PhpfastcacheInvalidArgumentException,
PhpfastcacheInvalidConfigurationException,
PhpfastcacheLogicException,
PhpfastcacheUnsupportedOperationException
};
use Phpfastcache\Util\ClassNamespaceResolverTrait;
/**
* Class CacheManager
* @package phpFastCache
*
* @method static ExtendedCacheItemPoolInterface Apcu() Apcu($config = []) Return a driver "Apcu" instance
* @method static ExtendedCacheItemPoolInterface Cassandra() Cassandra($config = []) Return a driver "Cassandra" instance
* @method static ExtendedCacheItemPoolInterface Cookie() Cookie($config = []) Return a driver "Cookie" instance
* @method static ExtendedCacheItemPoolInterface Couchbase() Couchbase($config = []) Return a driver "Couchbase" instance
* @method static ExtendedCacheItemPoolInterface Couchdb() Couchdb($config = []) Return a driver "Couchdb" instance
* @method static ExtendedCacheItemPoolInterface Devnull() Devnull($config = []) Return a driver "Devnull" instance
* @method static ExtendedCacheItemPoolInterface Files() Files($config = []) Return a driver "files" instance
* @method static ExtendedCacheItemPoolInterface Leveldb() Leveldb($config = []) Return a driver "Leveldb" instance
* @method static ExtendedCacheItemPoolInterface Memcache() Memcache($config = []) Return a driver "Memcache" instance
* @method static ExtendedCacheItemPoolInterface Memcached() Memcached($config = []) Return a driver "Memcached" instance
* @method static ExtendedCacheItemPoolInterface Memstatic() Memstatic($config = []) Return a driver "Memstatic" instance
* @method static ExtendedCacheItemPoolInterface Mongodb() Mongodb($config = []) Return a driver "Mongodb" instance
* @method static ExtendedCacheItemPoolInterface Predis() Predis($config = []) Return a driver "Predis" instance
* @method static ExtendedCacheItemPoolInterface Redis() Redis($config = []) Return a driver "Pedis" instance
* @method static ExtendedCacheItemPoolInterface Sqlite() Sqlite($config = []) Return a driver "Sqlite" instance
* @method static ExtendedCacheItemPoolInterface Ssdb() Ssdb($config = []) Return a driver "Ssdb" instance
* @method static ExtendedCacheItemPoolInterface Wincache() Wincache($config = []) Return a driver "Wincache" instance
* @method static ExtendedCacheItemPoolInterface Zenddisk() Zenddisk($config = []) Return a driver "Zend disk cache" instance
* @method static ExtendedCacheItemPoolInterface Zendshm() Zendshm($config = []) Return a driver "Zend memory cache" instance
*
*/
class CacheManager
{
public const CORE_DRIVER_NAMESPACE = 'Phpfastcache\Drivers\\';
use ClassNamespaceResolverTrait;
/**
* @var ConfigurationOption
*/
protected static $config;
/**
* @var string
*/
protected static $namespacePath;
/**
* @var ExtendedCacheItemPoolInterface[]
*/
protected static $instances = [];
/**
* @var array
*/
protected static $driverOverrides = [];
/**
* @var array
*/
protected static $driverCustoms = [];
/**
* @var array
*/
protected static $badPracticeOmeter = [];
/**
* CacheManager constructor.
*/
final protected function __construct()
{
// The cache manager is not meant to be instantiated
}
/**
* @param string $instanceId
* @return ExtendedCacheItemPoolInterface
* @throws PhpfastcacheInstanceNotFoundException
*/
public static function getInstanceById(string $instanceId): ExtendedCacheItemPoolInterface
{
if (isset(self::$instances[$instanceId])) {
return self::$instances[$instanceId];
}
throw new PhpfastcacheInstanceNotFoundException(sprintf('Instance ID %s not found', $instanceId));
}
/**
* Return the list of instances
*
* @return ExtendedCacheItemPoolInterface[]
*/
public static function getInstances(): array
{
return self::$instances;
}
/**
* This method is intended for internal
* use only and should not be used for
* any external development use the
* getInstances() method instead
*
* @return ExtendedCacheItemPoolInterface[]
* @internal
* @todo Use a proper way to passe them as a reference ?
*/
public static function &getInternalInstances(): array
{
return self::$instances;
}
/**
* @param string $name
* @param array $arguments
* @return ExtendedCacheItemPoolInterface
* @throws PhpfastcacheDriverCheckException
* @throws PhpfastcacheDriverException
* @throws PhpfastcacheDriverNotFoundException
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheInvalidConfigurationException
* @throws PhpfastcacheLogicException
* @throws \ReflectionException
*/
public static function __callStatic(string $name, array $arguments): ExtendedCacheItemPoolInterface
{
$options = (\array_key_exists(0, $arguments) && \is_array($arguments) ? $arguments[0] : []);
return self::getInstance($name, $options);
}
/**
* @param string $driver
* @param ConfigurationOptionInterface $config
* @param string|null $instanceId
* @return ExtendedCacheItemPoolInterface|AggregatablePoolInterface
* @throws PhpfastcacheDriverCheckException
* @throws PhpfastcacheDriverException
* @throws PhpfastcacheDriverNotFoundException
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheInvalidConfigurationException
* @throws PhpfastcacheLogicException
* @throws \ReflectionException
*/
public static function getInstance(string $driver, ?ConfigurationOptionInterface $config = null, ?string $instanceId = null): ExtendedCacheItemPoolInterface
{
$config = self::validateConfig($config);
$driver = self::standardizeDriverName($driver);
$instanceId = $instanceId ?: md5($driver . \serialize(\array_filter($config->toArray(), static function ($val){
return !\is_callable($val);
})));
if (!isset(self::$instances[$instanceId])) {
self::$badPracticeOmeter[$driver] = 1;
$driverClass = self::validateDriverClass(self::getDriverClass($driver));
if (\class_exists($driverClass)) {
$configClass = $driverClass::getConfigClass();
self::$instances[$instanceId] = new $driverClass(new $configClass($config->toArray()), $instanceId);
self::$instances[$instanceId]->setEventManager(EventManager::getInstance());
} else {
throw new PhpfastcacheDriverNotFoundException(sprintf('The driver "%s" does not exists', $driver));
}
} else {
if (self::$badPracticeOmeter[$driver] >= 2) {
\trigger_error(
'[' . $driver . '] Calling many times CacheManager::getInstance() for already instanced drivers is a bad practice and have a significant impact on performances.
See https://github.com/PHPSocialNetwork/phpfastcache/wiki/[V5]-Why-calling-getInstance%28%29-each-time-is-a-bad-practice-%3F'
);
}
}
self::$badPracticeOmeter[$driver]++;
return self::$instances[$instanceId];
}
/**
* @param ConfigurationOptionInterface|null $config
* @return ConfigurationOption
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheInvalidConfigurationException
* @throws \ReflectionException
*/
protected static function validateConfig(?ConfigurationOptionInterface $config): ConfigurationOption
{
if ($config === null) {
$config = self::getDefaultConfig();
} else {
if (!($config instanceof ConfigurationOption)) {
throw new PhpfastcacheInvalidArgumentException(\sprintf('Unsupported config type: %s', \gettype($config)));
}
}
return $config;
}
/**
* @return ConfigurationOptionInterface
* @throws PhpfastcacheInvalidConfigurationException
* @throws \ReflectionException
*/
public static function getDefaultConfig(): ConfigurationOptionInterface
{
return self::$config ?: self::$config = new ConfigurationOption();
}
/**
* @param string $driverName
* @return string
*/
public static function standardizeDriverName(string $driverName): string
{
return \ucfirst(\strtolower(\trim($driverName)));
}
/**
* @param string $driverClass
* @return string|ExtendedCacheItemPoolInterface
* @throws PhpfastcacheDriverException
*/
protected static function validateDriverClass(string $driverClass): string
{
if (!\is_a($driverClass, ExtendedCacheItemPoolInterface::class, true)) {
throw new PhpfastcacheDriverException(
\sprintf(
'Class "%s" does not implement "%s"',
$driverClass,
ExtendedCacheItemPoolInterface::class
)
);
}
return $driverClass;
}
/**
* @param string $driverName
* @return string
*/
public static function getDriverClass(string $driverName): string
{
if (!empty(self::$driverCustoms[$driverName])) {
$driverClass = self::$driverCustoms[$driverName];
} else {
if (!empty(self::$driverOverrides[$driverName])) {
$driverClass = self::$driverOverrides[$driverName];
} else {
$driverClass = self::getNamespacePath() . $driverName . '\Driver';
}
}
return $driverClass;
}
/**
* @return string
*/
public static function getNamespacePath(): string
{
return self::$namespacePath ?: self::getDefaultNamespacePath();
}
/**
* @return string
*/
public static function getDefaultNamespacePath(): string
{
return self::CORE_DRIVER_NAMESPACE;
}
/**
* @return bool
*/
public static function clearInstances(): bool
{
self::$instances = [];
\gc_collect_cycles();
return !\count(self::$instances);
}
/**
* @param ExtendedCacheItemPoolInterface $cachePoolInstance
* @return bool
* @since 7.0.4
*/
public static function clearInstance(ExtendedCacheItemPoolInterface $cachePoolInstance): bool
{
$found = false;
self::$instances = \array_filter(
\array_map(
static function (ExtendedCacheItemPoolInterface $cachePool) use ($cachePoolInstance, &$found) {
if (\spl_object_hash($cachePool) === \spl_object_hash($cachePoolInstance)) {
$found = true;
return null;
}
return $cachePool;
},
self::$instances
)
);
return $found;
}
/**
* @param ConfigurationOption $config
*/
public static function setDefaultConfig(ConfigurationOption $config): void
{
self::$config = $config;
}
/**
* @param string $driverName
* @param string $className
* @return void
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheUnsupportedOperationException
* @throws PhpfastcacheInvalidArgumentException
*/
public static function addCustomDriver(string $driverName, string $className): void
{
$driverName = self::standardizeDriverName($driverName);
if (empty($driverName)) {
throw new PhpfastcacheInvalidArgumentException("Can't add a custom driver because its name is empty");
}
if (!\class_exists($className)) {
throw new PhpfastcacheInvalidArgumentException(
\sprintf("Can't add '%s' because the class '%s' does not exists", $driverName, $className)
);
}
if (!empty(self::$driverCustoms[$driverName])) {
throw new PhpfastcacheLogicException(\sprintf("Driver '%s' has been already added", $driverName));
}
if (\in_array($driverName, self::getDriverList(), true)) {
throw new PhpfastcacheLogicException(\sprintf("Driver '%s' is already a part of the PhpFastCache core", $driverName));
}
self::$driverCustoms[$driverName] = $className;
}
/**
* Return the list of available drivers Capitalized
* with optional FQCN as key
*
* @param bool $FQCNAsKey Describe keys with Full Qualified Class Name
* @return string[]
* @throws PhpfastcacheUnsupportedOperationException
*/
public static function getDriverList(bool $FQCNAsKey = false): array
{
static $driverList;
if (self::getDefaultNamespacePath() === self::getNamespacePath()) {
if ($driverList === null) {
$prefix = self::CORE_DRIVER_NAMESPACE;
$classMap = self::createClassMap(__DIR__ . '/Drivers');
$driverList = [];
foreach ($classMap as $class => $file) {
$driverList[] = \str_replace($prefix, '', \substr($class, 0, \strrpos($class, '\\')));
}
$driverList = \array_values(\array_unique($driverList));
}
$driverList = \array_merge($driverList, \array_keys(self::$driverCustoms));
if ($FQCNAsKey) {
$realDriverList = [];
foreach ($driverList as $driverName) {
$realDriverList[self::getDriverClass($driverName)] = $driverName;
}
$driverList = $realDriverList;
}
\asort($driverList);
return $driverList;
}
throw new PhpfastcacheUnsupportedOperationException('Cannot get the driver list if the default namespace path has changed.');
}
/**
* @param string $driverName
* @return void
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheInvalidArgumentException
*/
public static function removeCustomDriver(string $driverName): void
{
$driverName = self::standardizeDriverName($driverName);
if (empty($driverName)) {
throw new PhpfastcacheInvalidArgumentException("Can't remove a custom driver because its name is empty");
}
if (!isset(self::$driverCustoms[$driverName])) {
throw new PhpfastcacheLogicException(\sprintf("Driver '%s' does not exists", $driverName));
}
unset(self::$driverCustoms[$driverName]);
}
/**
* @param string $driverName
* @param string $className
* @return void
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheUnsupportedOperationException
* @throws PhpfastcacheInvalidArgumentException
*/
public static function addCoreDriverOverride(string $driverName, string $className): void
{
$driverName = self::standardizeDriverName($driverName);
if (empty($driverName)) {
throw new PhpfastcacheInvalidArgumentException("Can't add a core driver override because its name is empty");
}
if (!\class_exists($className)) {
throw new PhpfastcacheInvalidArgumentException(
\sprintf("Can't override '%s' because the class '%s' does not exists", $driverName, $className)
);
}
if (!empty(self::$driverOverrides[$driverName])) {
throw new PhpfastcacheLogicException(\sprintf("Driver '%s' has been already overridden", $driverName));
}
if (!\in_array($driverName, self::getDriverList(), true)) {
throw new PhpfastcacheLogicException(\sprintf("Driver '%s' can't be overridden since its not a part of the PhpFastCache core", $driverName));
}
if (!\is_subclass_of($className, self::CORE_DRIVER_NAMESPACE . $driverName . '\\Driver', true)) {
throw new PhpfastcacheLogicException(
\sprintf(
"Can't override '%s' because the class '%s' MUST extend '%s'",
$driverName,
$className,
self::CORE_DRIVER_NAMESPACE . $driverName . '\\Driver'
)
);
}
self::$driverOverrides[$driverName] = $className;
}
/**
* @param string $driverName
* @return void
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheInvalidArgumentException
*/
public static function removeCoreDriverOverride(string $driverName): void
{
$driverName = self::standardizeDriverName($driverName);
if (empty($driverName)) {
throw new PhpfastcacheInvalidArgumentException("Can't remove a core driver override because its name is empty");
}
if (!isset(self::$driverOverrides[$driverName])) {
throw new PhpfastcacheLogicException(\sprintf("Driver '%s' were not overridden", $driverName));
}
unset(self::$driverOverrides[$driverName]);
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Psr\Cache\CacheItemPoolInterface;
/**
* Interface ClusterInterface Aggregatable
*
* @package Phpfastcache\Cluster
*/
interface AggregatablePoolInterface extends CacheItemPoolInterface
{
}

View File

@ -0,0 +1,105 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Phpfastcache\Config\ConfigurationOption;
/**
* Interface AggregatorInterface
*
* @package Phpfastcache\Cluster
*/
interface AggregatorInterface
{
/**
* Full replication mechanism
*
* Read on first working (and synchronize if needed, no failure allowed),
* Write on all (no failure allowed),
* Delete on all (no failure allowed)
*
* Conflict on multiple reads: Keep first found item (but sync the others)
* Cluster size: 2 minimum, unlimited
*/
public const STRATEGY_FULL_REPLICATION = 1;
/**
* Semi replication mechanism
*
* Read first working (but do not synchronize, with partial failure allowed),
* Write on all (with partial failure allowed)
* Delete on all (with partial failure allowed)
*
* Conflict on multiple reads: Keep first found item
* Cluster size: 2 minimum, unlimited
*/
public const STRATEGY_SEMI_REPLICATION = 2;
/**
* First pool is master, second is slave
*
* Read from master (but do not synchronize, with master failure only allowed)
* Write on all (with master failure only allowed)
* Delete on all (with master failure only allowed)
*
* Conflict on multiple reads: No, master is exclusive source except if it fails
* Cluster size: 2 exactly: Master & Slave (Exception if more or less)
*/
public const STRATEGY_MASTER_SLAVE = 4;
/**
* Mostly used for development testing
*
* CRUD operations are made on a random-chosen backend from a given cluster.
* This means you have 1 chance out of (n count of pools) to find an existing cache item
* but also to write/delete an non-existing item.
*/
public const STRATEGY_RANDOM_REPLICATION = 8;
/**
* AggregatorInterface constructor.
*
* @param string $clusterAggregatorName
* @param AggregatablePoolInterface ...$driverPools
*/
public function __construct(string $clusterAggregatorName, AggregatablePoolInterface ...$driverPools);
/**
* @param int $strategy
*
* @return ClusterPoolInterface
*/
public function getCluster(int $strategy): ClusterPoolInterface;
/**
* @param string $driverName
* @param ConfigurationOption|NULL $driverConfig
*
* @return void
*/
public function aggregateNewDriver(string $driverName, ConfigurationOption $driverConfig = null): void;
/**
* @param AggregatablePoolInterface $driverPool
*/
public function aggregateDriver(AggregatablePoolInterface $driverPool): void;
/**
* @param AggregatablePoolInterface $driverPool
*/
public function disaggregateDriver(AggregatablePoolInterface $driverPool): void;
}

View File

@ -0,0 +1,174 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Exception;
use Phpfastcache\CacheManager;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
use Phpfastcache\Exceptions\PhpfastcacheDriverException;
use Phpfastcache\Exceptions\PhpfastcacheDriverNotFoundException;
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
use Phpfastcache\Exceptions\PhpfastcacheLogicException;
use ReflectionException;
use stdClass;
/**
* Class ClusterAggregator
*
* @package Phpfastcache\Cluster
*/
class ClusterAggregator implements AggregatorInterface
{
protected $driverPools;
/**
* @var ClusterPoolInterface
*/
protected $cluster;
/**
* @var string
*/
protected $clusterAggregatorName;
/**
* ClusterAggregator constructor.
* @param string $clusterAggregatorName
* @param AggregatablePoolInterface ...$driverPools
* @throws PhpfastcacheLogicException
*/
public function __construct(string $clusterAggregatorName = '', AggregatablePoolInterface ...$driverPools)
{
$clusterAggregatorName = trim($clusterAggregatorName);
if (empty($clusterAggregatorName)) {
try {
$clusterAggregatorName = 'cluster_' . \bin2hex(\random_bytes(15));
} catch (Exception $e) {
$clusterAggregatorName = 'cluster_' . \str_shuffle(\spl_object_hash(new stdClass()));
}
}
$this->clusterAggregatorName = $clusterAggregatorName;
foreach ($driverPools as $driverPool) {
$this->aggregateDriver($driverPool);
}
}
/**
* @param AggregatablePoolInterface $driverPool
*
* @throws PhpfastcacheLogicException
*/
public function aggregateDriver(AggregatablePoolInterface $driverPool): void
{
if ($this->cluster) {
throw new PhpfastcacheLogicException('The cluster has been already build, cannot aggregate more pools.');
}
$splHash = \spl_object_hash($driverPool);
if (!isset($this->driverPools[$splHash])) {
if ($driverPool instanceof ClusterPoolInterface) {
throw new PhpfastcacheLogicException('Recursive cluster aggregation is not allowed !');
}
$this->driverPools[$splHash] = $driverPool;
} else {
throw new PhpfastcacheLogicException('This pool has been already aggregated !');
}
}
/**
* @param string $driverName
* @param ConfigurationOption|null $driverConfig
* @throws PhpfastcacheDriverCheckException
* @throws PhpfastcacheDriverException
* @throws PhpfastcacheDriverNotFoundException
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheInvalidConfigurationException
* @throws PhpfastcacheLogicException
* @throws ReflectionException
*/
public function aggregateNewDriver(string $driverName, ConfigurationOption $driverConfig = null): void
{
if ($this->cluster) {
throw new PhpfastcacheLogicException('The cluster has been already build, cannot aggregate more pools.');
}
$this->aggregateDriver(
CacheManager::getInstance($driverName, $driverConfig)
);
}
/**
* @param AggregatablePoolInterface $driverPool
*
* @throws PhpfastcacheLogicException
*/
public function disaggregateDriver(AggregatablePoolInterface $driverPool): void
{
if ($this->cluster) {
throw new PhpfastcacheLogicException('The cluster has been already build, cannot disaggregate pools.');
}
$splHash = \spl_object_hash($driverPool);
if (isset($this->driverPools[$splHash])) {
unset($this->driverPools[$splHash]);
} else {
throw new PhpfastcacheLogicException('This pool was not aggregated !');
}
}
/**
* @param int $strategy
*
* @return ClusterPoolInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function getCluster(int $strategy = AggregatorInterface::STRATEGY_FULL_REPLICATION): ClusterPoolInterface
{
if (isset(ClusterPoolAbstract::STRATEGY[$strategy])) {
if (!$this->cluster) {
$clusterClass = ClusterPoolAbstract::STRATEGY[$strategy];
$this->cluster = new $clusterClass(
$this->getClusterAggregatorName(),
...\array_values($this->driverPools)
);
/**
* @eventName CacheClusterBuilt
* @param $clusterAggregator AggregatorInterface
* @param $cluster ClusterPoolInterface
*/
$this->cluster->getEventManager()->dispatch('CacheClusterBuilt', $this, $this->cluster);
}
} else {
throw new PhpfastcacheInvalidArgumentException('Unknown cluster strategy');
}
return $this->cluster;
}
/**
* @return string
*/
public function getClusterAggregatorName(): string
{
return $this->clusterAggregatorName;
}
}

View File

@ -0,0 +1,234 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Phpfastcache\Cluster\Drivers\{FullReplication\FullReplicationCluster,
MasterSlaveReplication\MasterSlaveReplicationCluster,
RandomReplication\RandomReplicationCluster,
SemiReplication\SemiReplicationCluster
};
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Core\{Item\ExtendedCacheItemInterface, Pool\DriverBaseTrait, Pool\ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverIO;
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\EventManager;
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
use Phpfastcache\Exceptions\PhpfastcacheDriverConnectException;
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
use Psr\Cache\{CacheItemInterface, InvalidArgumentException};
use ReflectionException;
/**
* Class ClusterAbstract
*
* @package Phpfastcache\Cluster
*/
abstract class ClusterPoolAbstract implements ClusterPoolInterface
{
use DriverBaseTrait;
use ClusterPoolTrait {
DriverBaseTrait::__construct as private __parentConstruct;
}
public const STRATEGY = [
AggregatorInterface::STRATEGY_FULL_REPLICATION => FullReplicationCluster::class,
AggregatorInterface::STRATEGY_SEMI_REPLICATION => SemiReplicationCluster::class,
AggregatorInterface::STRATEGY_MASTER_SLAVE => MasterSlaveReplicationCluster::class,
AggregatorInterface::STRATEGY_RANDOM_REPLICATION => RandomReplicationCluster::class,
];
/**
* @var ExtendedCacheItemPoolInterface[]
*/
protected $clusterPools;
/**
* ClusterPoolAbstract constructor.
* @param string $clusterName
* @param ExtendedCacheItemPoolInterface ...$driverPools
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheDriverCheckException
* @throws PhpfastcacheDriverConnectException
* @throws PhpfastcacheInvalidConfigurationException
* @throws ReflectionException
*/
public function __construct(string $clusterName, ExtendedCacheItemPoolInterface ...$driverPools)
{
if (count($driverPools) < 2) {
throw new PhpfastcacheInvalidArgumentException('A cluster requires at least two pools to be working.');
}
$this->clusterPools = $driverPools;
$this->__parentConstruct(new ConfigurationOption(), $clusterName);
$this->setEventManager(EventManager::getInstance());
}
/**
* @inheritDoc
*/
public function getIO(): DriverIO
{
$IO = new DriverIO();
foreach ($this->clusterPools as $clusterPool) {
$IO->setReadHit($IO->getReadHit() + $clusterPool->getIO()->getReadHit())
->setReadMiss($IO->getReadMiss() + $clusterPool->getIO()->getReadMiss())
->setWriteHit($IO->getWriteHit() + $clusterPool->getIO()->getWriteHit());
}
return $IO;
}
/**
* @inheritDoc
*/
public function getClusterPools(): array
{
return $this->clusterPools;
}
/**
* @inheritDoc
*/
public function getItems(array $keys = [])
{
$items = [];
foreach ($keys as $key) {
$items[$key] = $this->getItem($key);
}
return $items;
}
/**
* Shared method used by All Clusters
*/
/**
* @inheritDoc
*/
public function deleteItems(array $keys)
{
$hasDeletedOnce = false;
foreach ($this->clusterPools as $driverPool) {
if ($result = $driverPool->deleteItems($keys)) {
$hasDeletedOnce = $result;
}
}
// Return true only if at least one backend confirmed the "clear" operation
return $hasDeletedOnce;
}
/**
* @inheritDoc
*/
public function saveDeferred(CacheItemInterface $item)
{
/** @var ExtendedCacheItemInterface $item */
$hasSavedOnce = false;
foreach ($this->clusterPools as $driverPool) {
$poolItem = $this->getStandardizedItem($item, $driverPool);
if ($result = $driverPool->saveDeferred($poolItem)) {
$hasSavedOnce = $result;
}
}
// Return true only if at least one backend confirmed the "commit" operation
return $hasSavedOnce;
}
/**
* @param ExtendedCacheItemInterface $item
* @param ExtendedCacheItemPoolInterface $driverPool
* @return CacheItemInterface
* @throws InvalidArgumentException
*/
protected function getStandardizedItem(ExtendedCacheItemInterface $item, ExtendedCacheItemPoolInterface $driverPool): CacheItemInterface
{
if (!$item->doesItemBelongToThatDriverBackend($driverPool)) {
/**
* Avoid infinite loop
*/
if ($driverPool === $this) {
/** @var ExtendedCacheItemInterface $itemPool */
$itemClass = $driverPool->getClassNamespace() . '\\' . 'Item';
$itemPool = new $itemClass($this, $item->getKey());
$itemPool->setEventManager($this->getEventManager())
->set($item->get())
->setHit($item->isHit())
->setTags($item->getTags())
->expiresAt($item->getExpirationDate())
->setDriver($driverPool);
return $itemPool;
}
return $driverPool->getItem($item->getKey())
->setEventManager($this->getEventManager())
->set($item->get())
->setHit($item->isHit())
->setTags($item->getTags())
->expiresAt($item->getExpirationDate())
->setDriver($driverPool);
}
return $item->setEventManager($this->getEventManager());
}
/**
* Interfaced methods that needs to be faked
*/
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stats = new DriverStatistic();
$stats->setInfo(
sprintf(
'Using %d pool(s): %s',
\count($this->clusterPools),
\implode(
', ',
\array_map(
static function (ExtendedCacheItemPoolInterface $pool) {
return \get_class($pool);
},
$this->clusterPools
)
)
)
);
$stats->setSize(
(int)\array_sum(
\array_map(
static function (ExtendedCacheItemPoolInterface $pool) {
return $pool->getStats()->getSize();
},
$this->clusterPools
)
)
);
$stats->setData(
(int)\array_map(
static function (ExtendedCacheItemPoolInterface $pool) {
return $pool->getStats()->getData();
},
$this->clusterPools
)
);
return $stats;
}
}

View File

@ -0,0 +1,31 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
/**
* Interface ClusterInterface
*
* @package Phpfastcache\Cluster
*/
interface ClusterPoolInterface extends ExtendedCacheItemPoolInterface
{
/**
* @return ExtendedCacheItemPoolInterface[]
*/
public function getClusterPools(): array;
}

View File

@ -0,0 +1,72 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Psr\Cache\CacheItemInterface;
trait ClusterPoolTrait
{
/**
* @return bool
*/
protected function driverCheck(): bool
{
return true;
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return null
*/
protected function driverRead(CacheItemInterface $item)
{
return null;
}
/**
* @param CacheItemInterface $item
* @return bool
*/
protected function driverWrite(CacheItemInterface $item): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return bool
*/
protected function driverDelete(CacheItemInterface $item): bool
{
return true;
}
/**
* @return bool
*/
protected function driverClear(): bool
{
return true;
}
}

View File

@ -0,0 +1,176 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\FullReplication;
use Phpfastcache\Cluster\ClusterPoolAbstract;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Psr\Cache\CacheItemInterface;
/**
* Class FullReplicationCluster
* @package Phpfastcache\Cluster\Drivers\FullReplication
*/
class FullReplicationCluster extends ClusterPoolAbstract
{
/**
* @inheritDoc
*/
public function getItem($key)
{
/** @var ExtendedCacheItemPoolInterface[] $poolsToResync */
$poolsToResync = [];
/** @var ExtendedCacheItemInterface $item */
$item = null;
foreach ($this->clusterPools as $driverPool) {
$poolItem = $driverPool->getItem($key);
if ($poolItem->isHit()) {
if (!$item) {
$item = $poolItem;
continue;
}
$itemData = $item->get();
$poolItemData = $poolItem->get();
if (\is_object($itemData)
) {
if ($item->get() != $poolItemData) {
$poolsToResync[] = $driverPool;
}
} else {
if ($item->get() !== $poolItemData) {
$poolsToResync[] = $driverPool;
}
}
} else {
$poolsToResync[] = $driverPool;
}
}
if ($item && $item->isHit() && \count($poolsToResync) < \count($this->clusterPools)) {
foreach ($poolsToResync as $poolToResync) {
$poolItem = $poolToResync->getItem($key);
$poolItem->setEventManager($this->getEventManager())
->set($item->get())
->setHit($item->isHit())
->setTags($item->getTags())
->expiresAt($item->getExpirationDate())
->setDriver($poolToResync);
$poolToResync->save($poolItem);
}
}
return $this->getStandardizedItem($item ?? new Item($this, $key), $this);
}
/**
* @inheritDoc
*/
public function hasItem($key)
{
foreach ($this->clusterPools as $driverPool) {
$poolItem = $driverPool->getItem($key);
if ($poolItem->isHit()) {
return true;
}
}
return false;
}
/**
* @inheritDoc
*/
public function clear()
{
$hasClearedOnce = false;
foreach ($this->clusterPools as $driverPool) {
if ($result = $driverPool->clear()) {
$hasClearedOnce = $result;
}
}
// Return true only if at least one backend confirmed the "clear" operation
return $hasClearedOnce;
}
/**
* @inheritDoc
*/
public function deleteItem($key)
{
$hasDeletedOnce = false;
foreach ($this->clusterPools as $driverPool) {
if ($result = $driverPool->deleteItem($key)) {
$hasDeletedOnce = $result;
}
}
// Return true only if at least one backend confirmed the "clear" operation
return $hasDeletedOnce;
}
/**
* @inheritDoc
*/
public function save(CacheItemInterface $item)
{
/** @var ExtendedCacheItemInterface $item */
$hasSavedOnce = false;
foreach ($this->clusterPools as $driverPool) {
$poolItem = $this->getStandardizedItem($item, $driverPool);
if ($result = $driverPool->save($poolItem)) {
$hasSavedOnce = $result;
}
}
// Return true only if at least one backend confirmed the "commit" operation
return $hasSavedOnce;
}
/**
* @inheritDoc
*/
public function saveDeferred(CacheItemInterface $item)
{
/** @var ExtendedCacheItemInterface $item */
$hasSavedOnce = false;
foreach ($this->clusterPools as $driverPool) {
$poolItem = $this->getStandardizedItem($item, $driverPool);
if ($result = $driverPool->saveDeferred($poolItem)) {
$hasSavedOnce = $result;
}
}
// Return true only if at least one backend confirmed the "commit" operation
return $hasSavedOnce;
}
/**
* @inheritDoc
*/
public function commit()
{
$hasCommitOnce = false;
foreach ($this->clusterPools as $driverPool) {
if ($result = $driverPool->commit()) {
$hasCommitOnce = $result;
}
}
// Return true only if at least one backend confirmed the "commit" operation
return $hasCommitOnce;
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\FullReplication;
use Phpfastcache\Cluster\ItemAbstract;
/**
* Class ClusterItem
* @package Phpfastcache\Cluster
*/
class Item extends ItemAbstract
{
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\MasterSlaveReplication;
use Phpfastcache\Cluster\ItemAbstract;
/**
* Class ClusterItem
* @package Phpfastcache\Cluster
*/
class Item extends ItemAbstract
{
}

View File

@ -0,0 +1,170 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\MasterSlaveReplication;
use Phpfastcache\Cluster\ClusterPoolAbstract;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
use Phpfastcache\Exceptions\PhpfastcacheDriverConnectException;
use Phpfastcache\Exceptions\PhpfastcacheExceptionInterface;
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
use Phpfastcache\Exceptions\PhpfastcacheReplicationException;
use Psr\Cache\CacheItemInterface;
use ReflectionException;
/**
* Class MasterSlaveReplicationCluster
* @package Phpfastcache\Cluster\Drivers\MasterSlaveReplication
*/
class MasterSlaveReplicationCluster extends ClusterPoolAbstract
{
/**
* MasterSlaveReplicationCluster constructor.
* @param string $clusterName
* @param ExtendedCacheItemPoolInterface ...$driverPools
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheDriverCheckException
* @throws PhpfastcacheDriverConnectException
* @throws PhpfastcacheInvalidConfigurationException
* @throws ReflectionException
*/
public function __construct(string $clusterName, ExtendedCacheItemPoolInterface ...$driverPools)
{
if (\count($driverPools) !== 2) {
throw new PhpfastcacheInvalidArgumentException('A "master/slave" cluster requires exactly two pools to be working.');
}
parent::__construct($clusterName, ...$driverPools);
}
/**
* @inheritDoc
*/
public function getItem($key)
{
return $this->getStandardizedItem(
$this->makeOperation(
static function (ExtendedCacheItemPoolInterface $pool) use ($key) {
return $pool->getItem($key);
}
) ?? new Item($this, $key),
$this
);
}
/**
* @param callable $operation
* @return mixed
* @throws PhpfastcacheReplicationException
*/
protected function makeOperation(callable $operation)
{
try {
return $operation($this->getMasterPool());
} catch (PhpfastcacheExceptionInterface $e) {
try {
$this->eventManager->dispatch(
'CacheReplicationSlaveFallback',
$this,
\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function']
);
return $operation($this->getSlavePool());
} catch (PhpfastcacheExceptionInterface $e) {
throw new PhpfastcacheReplicationException('Master and Slave thrown an exception !');
}
}
}
/**
* @return ExtendedCacheItemPoolInterface
*/
protected function getMasterPool(): ExtendedCacheItemPoolInterface
{
return $this->clusterPools[0];
}
/**
* @return ExtendedCacheItemPoolInterface
*/
protected function getSlavePool(): ExtendedCacheItemPoolInterface
{
return $this->clusterPools[1];
}
/**
* @inheritDoc
*/
public function hasItem($key)
{
return $this->makeOperation(
static function (ExtendedCacheItemPoolInterface $pool) use ($key) {
return $pool->hasItem($key);
}
);
}
/**
* @inheritDoc
*/
public function clear()
{
return $this->makeOperation(
static function (ExtendedCacheItemPoolInterface $pool) {
return $pool->clear();
}
);
}
/**
* @inheritDoc
*/
public function deleteItem($key)
{
return $this->makeOperation(
static function (ExtendedCacheItemPoolInterface $pool) use ($key) {
return $pool->deleteItem($key);
}
);
}
/**
* @inheritDoc
*/
public function save(CacheItemInterface $item)
{
return $this->makeOperation(
function (ExtendedCacheItemPoolInterface $pool) use ($item) {
$item->setHit(true);
return $pool->save($this->getStandardizedItem($item, $pool));
}
);
}
/**
* @inheritDoc
*/
public function commit()
{
return $this->makeOperation(
static function (ExtendedCacheItemPoolInterface $pool) {
return $pool->commit();
}
);
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\RandomReplication;
use Phpfastcache\Cluster\ItemAbstract;
/**
* Class ClusterItem
* @package Phpfastcache\Cluster
*/
class Item extends ItemAbstract
{
}

View File

@ -0,0 +1,59 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\RandomReplication;
use Phpfastcache\Cluster\Drivers\MasterSlaveReplication\MasterSlaveReplicationCluster;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use ReflectionException;
use ReflectionMethod;
/**
* Class MasterSlaveReplicationCluster
* @package Phpfastcache\Cluster\Drivers\MasterSlaveReplication
*/
class RandomReplicationCluster extends MasterSlaveReplicationCluster
{
/**
* RandomReplicationCluster constructor.
* @param string $clusterName
* @param ExtendedCacheItemPoolInterface ...$driverPools
* @throws ReflectionException
*/
public function __construct(string $clusterName, ExtendedCacheItemPoolInterface ...$driverPools)
{
(new ReflectionMethod(\get_parent_class(\get_parent_class($this)), __FUNCTION__))
->invoke($this, $clusterName, ...$driverPools);
$randomPool = $driverPools[\random_int(0, \count($driverPools) - 1)];
$this->eventManager->dispatch(
'CacheReplicationRandomPoolChosen',
$this,
$randomPool
);
$this->clusterPools = [$randomPool];
}
/**
* @param callable $operation
* @return mixed
*/
protected function makeOperation(callable $operation)
{
return $operation($this->getMasterPool());
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\SemiReplication;
use Phpfastcache\Cluster\ItemAbstract;
/**
* Class ClusterItem
* @package Phpfastcache\Cluster
*/
class Item extends ItemAbstract
{
}

View File

@ -0,0 +1,203 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster\Drivers\SemiReplication;
use Phpfastcache\Cluster\ClusterPoolAbstract;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Exceptions\PhpfastcacheExceptionInterface;
use Phpfastcache\Exceptions\PhpfastcacheReplicationException;
use Psr\Cache\CacheItemInterface;
/**
* Class FullReplicationCluster
* @package Phpfastcache\Cluster\Drivers\FullReplication
*/
class SemiReplicationCluster extends ClusterPoolAbstract
{
/**
* @inheritDoc
*/
public function getItem($key)
{
/** @var ExtendedCacheItemInterface $item */
$item = null;
$eCount = 0;
foreach ($this->clusterPools as $driverPool) {
try {
$poolItem = $driverPool->getItem($key);
if ($poolItem->isHit()) {
if (!$item) {
$item = $poolItem;
break;
}
}
} catch (PhpfastcacheExceptionInterface $e) {
$eCount++;
}
}
if (\count($this->clusterPools) <= $eCount) {
throw new PhpfastcacheReplicationException('Every pools thrown an exception');
}
return $this->getStandardizedItem($item ?? new Item($this, $key), $this);
}
/**
* @inheritDoc
*/
public function hasItem($key)
{
$eCount = 0;
foreach ($this->clusterPools as $driverPool) {
try {
$poolItem = $driverPool->getItem($key);
if ($poolItem->isHit()) {
return true;
}
} catch (PhpfastcacheExceptionInterface $e) {
$eCount++;
}
}
if (\count($this->clusterPools) <= $eCount) {
throw new PhpfastcacheReplicationException('Every pools thrown an exception');
}
return false;
}
/**
* @inheritDoc
*/
public function clear()
{
$hasClearedOnce = false;
$eCount = 0;
foreach ($this->clusterPools as $driverPool) {
try {
if ($result = $driverPool->clear()) {
$hasClearedOnce = $result;
}
} catch (PhpfastcacheExceptionInterface $e) {
$eCount++;
}
}
if (\count($this->clusterPools) <= $eCount) {
throw new PhpfastcacheReplicationException('Every pools thrown an exception');
}
// Return true only if at least one backend confirmed the "clear" operation
return $hasClearedOnce;
}
/**
* @inheritDoc
*/
public function deleteItem($key)
{
$hasDeletedOnce = false;
$eCount = 0;
foreach ($this->clusterPools as $driverPool) {
try {
if ($result = $driverPool->deleteItem($key)) {
$hasDeletedOnce = $result;
}
} catch (PhpfastcacheExceptionInterface $e) {
$eCount++;
}
}
if (\count($this->clusterPools) <= $eCount) {
throw new PhpfastcacheReplicationException('Every pools thrown an exception');
}
// Return true only if at least one backend confirmed the "clear" operation
return $hasDeletedOnce;
}
/**
* @inheritDoc
*/
public function save(CacheItemInterface $item)
{
/** @var ExtendedCacheItemInterface $item */
$hasSavedOnce = false;
$eCount = 0;
foreach ($this->clusterPools as $driverPool) {
try {
$poolItem = $this->getStandardizedItem($item, $driverPool);
if ($result = $driverPool->save($poolItem)) {
$hasSavedOnce = $result;
}
} catch (PhpfastcacheExceptionInterface $e) {
$eCount++;
}
}
if (\count($this->clusterPools) <= $eCount) {
throw new PhpfastcacheReplicationException('Every pools thrown an exception');
}
// Return true only if at least one backend confirmed the "commit" operation
return $hasSavedOnce;
}
/**
* @inheritDoc
*/
public function saveDeferred(CacheItemInterface $item)
{
/** @var ExtendedCacheItemInterface $item */
$hasSavedOnce = false;
foreach ($this->clusterPools as $driverPool) {
$poolItem = $this->getStandardizedItem($item, $driverPool);
if ($result = $driverPool->saveDeferred($poolItem)) {
$hasSavedOnce = $result;
}
}
// Return true only if at least one backend confirmed the "commit" operation
return $hasSavedOnce;
}
/**
* @inheritDoc
*/
public function commit()
{
$hasCommitOnce = false;
$eCount = 0;
foreach ($this->clusterPools as $driverPool) {
try {
if ($result = $driverPool->commit()) {
$hasCommitOnce = $result;
}
} catch (PhpfastcacheExceptionInterface $e) {
$eCount++;
}
}
if (\count($this->clusterPools) <= $eCount) {
throw new PhpfastcacheReplicationException('Every pools thrown an exception');
}
// Return true only if at least one backend confirmed the "commit" operation
return $hasCommitOnce;
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class ClusterItem
* @package Phpfastcache\Cluster
*/
abstract class ItemAbstract implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof ClusterPoolInterface) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Config;
/**
* Class Config
* Alias of ConfigurationOption
* @package phpFastCache\Config
* @see ConfigurationOption
*/
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,389 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Config;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
use Phpfastcache\Util\ArrayObject;
use ReflectionException;
use ReflectionMethod;
use ReflectionParameter;
use TypeError;
/**
* Class ConfigurationOption
* @package Phpfastcache\Config
*/
class ConfigurationOption extends ArrayObject implements ConfigurationOptionInterface
{
/**
* @var bool
*/
protected $itemDetailedDate = false;
/**
* @var bool
*/
protected $autoTmpFallback = false;
/**
* @var int
*/
protected $defaultTtl = 900;
/**
* @var string|Callable
*/
protected $defaultKeyHashFunction = 'md5';
/**
* @var string|Callable
*/
protected $defaultFileNameHashFunction = 'md5';
/**
* @var int
*/
protected $defaultChmod = 0777;
/**
* @var string
*/
protected $path = '';
/**
* @var int
*/
protected $limitedMemoryByObject = 4096;
/**
* @var bool
*/
protected $compressData = false;
/**
* @var bool
*/
protected $preventCacheSlams = false;
/**
* @var int
*/
protected $cacheSlamsTimeout = 15;
/**
* @var bool
*/
protected $useStaticItemCaching = true;
/**
* @param $args
* ArrayObject constructor.
* @throws PhpfastcacheInvalidConfigurationException
* @throws ReflectionException
*/
public function __construct(...$args)
{
parent::__construct(...$args);
$array =& $this->getArray();
/**
* Detect unwanted keys and throw an exception.
* No more kidding now, it's 21th century.
*/
if (\array_diff_key($array, \get_object_vars($this))) {
throw new PhpfastcacheInvalidConfigurationException(
sprintf(
'Invalid option(s) for the config %s: %s',
static::class,
\implode(', ', \array_keys(\array_diff_key($array, \get_object_vars($this))))
)
);
}
foreach (\get_object_vars($this) as $property => $value) {
if (\array_key_exists($property, $array)) {
$this->$property = &$array[$property];
} else {
$array[$property] = &$this->$property;
}
}
foreach (\get_class_methods($this) as $method) {
if (\strpos($method, 'set') === 0) {
$value = null;
try {
/**
* We use property instead of getter
* because of is/get conditions and
* to allow us to retrieve the value
* in catch statement bloc
*/
$value = $this->{\lcfirst(\substr($method, 3))};
$this->{$method}($value);
} catch (TypeError $e) {
$typeHintGot = \is_object($value) ? \get_class($value) : \gettype($value);
$reflectionMethod = new ReflectionMethod($this, $method);
$parameter = $reflectionMethod->getParameters()[0] ?? null;
$typeHintExpected = ($parameter instanceof ReflectionParameter ? ($parameter->getType()->getName() === 'object' ? $parameter->getClass() : $parameter->getType(
)->getName()) : 'Unknown type');
throw new PhpfastcacheInvalidConfigurationException(
\sprintf(
'Invalid type hint found for "%s", expected "%s" got "%s"',
\lcfirst(\substr($method, 3)),
$typeHintExpected,
$typeHintGot
)
);
}
}
}
}
/**
* @param string $optionName
* @return mixed|null
*/
public function isValidOption(string $optionName)
{
return property_exists($this, $optionName);
}
/**
* @return bool
*/
public function isItemDetailedDate(): bool
{
return $this->itemDetailedDate;
}
/**
* @param bool $itemDetailedDate
* @return ConfigurationOption
*/
public function setItemDetailedDate(bool $itemDetailedDate): self
{
$this->itemDetailedDate = $itemDetailedDate;
return $this;
}
/**
* @return bool
*/
public function isAutoTmpFallback(): bool
{
return $this->autoTmpFallback;
}
/**
* @param bool $autoTmpFallback
* @return ConfigurationOption
*/
public function setAutoTmpFallback(bool $autoTmpFallback): self
{
$this->autoTmpFallback = $autoTmpFallback;
return $this;
}
/**
* @return int
*/
public function getDefaultTtl(): int
{
return $this->defaultTtl;
}
/**
* @param int $defaultTtl
* @return ConfigurationOption
*/
public function setDefaultTtl(int $defaultTtl): self
{
$this->defaultTtl = $defaultTtl;
return $this;
}
/**
* @return Callable|string
*/
public function getDefaultKeyHashFunction()
{
return $this->defaultKeyHashFunction;
}
/**
* @param Callable|string $defaultKeyHashFunction
* @return ConfigurationOption
* @throws PhpfastcacheInvalidConfigurationException
*/
public function setDefaultKeyHashFunction($defaultKeyHashFunction): self
{
if ($defaultKeyHashFunction && !\is_callable($defaultKeyHashFunction) && (\is_string($defaultKeyHashFunction) && !\function_exists($defaultKeyHashFunction))) {
throw new PhpfastcacheInvalidConfigurationException('defaultKeyHashFunction must be a valid function name string');
}
$this->defaultKeyHashFunction = $defaultKeyHashFunction;
return $this;
}
/**
* @return Callable|string
*/
public function getDefaultFileNameHashFunction()
{
return $this->defaultFileNameHashFunction;
}
/**
* @param Callable|string $defaultFileNameHashFunction
* @return ConfigurationOption
* @throws PhpfastcacheInvalidConfigurationException
*/
public function setDefaultFileNameHashFunction($defaultFileNameHashFunction): self
{
if (!\is_callable($defaultFileNameHashFunction) && (\is_string($defaultFileNameHashFunction) && !\function_exists($defaultFileNameHashFunction))) {
throw new PhpfastcacheInvalidConfigurationException('defaultFileNameHashFunction must be a valid function name string');
}
$this->defaultFileNameHashFunction = $defaultFileNameHashFunction;
return $this;
}
/**
* @return int
*/
public function getDefaultChmod(): int
{
return $this->defaultChmod;
}
/**
* @param int $defaultChmod
* @return ConfigurationOption
*/
public function setDefaultChmod(int $defaultChmod): self
{
$this->defaultChmod = $defaultChmod;
return $this;
}
/**
* @return string
*/
public function getPath(): string
{
return $this->path;
}
/**
* @param string $path
* @return ConfigurationOption
*/
public function setPath(string $path): self
{
$this->path = $path;
return $this;
}
/**
* @return int
*/
public function getLimitedMemoryByObject(): int
{
return $this->limitedMemoryByObject;
}
/**
* @param int $limitedMemoryByObject
* @return ConfigurationOption
*/
public function setLimitedMemoryByObject(int $limitedMemoryByObject): self
{
$this->limitedMemoryByObject = $limitedMemoryByObject;
return $this;
}
/**
* @return bool
*/
public function isCompressData(): bool
{
return $this->compressData;
}
/**
* @param bool $compressData
* @return ConfigurationOption
*/
public function setCompressData(bool $compressData): self
{
$this->compressData = $compressData;
return $this;
}
/**
* @return bool
*/
public function isPreventCacheSlams(): bool
{
return $this->preventCacheSlams;
}
/**
* @param bool $preventCacheSlams
* @return ConfigurationOption
*/
public function setPreventCacheSlams(bool $preventCacheSlams): self
{
$this->preventCacheSlams = $preventCacheSlams;
return $this;
}
/**
* @return int
*/
public function getCacheSlamsTimeout(): int
{
return $this->cacheSlamsTimeout;
}
/**
* @param int $cacheSlamsTimeout
* @return ConfigurationOption
*/
public function setCacheSlamsTimeout(int $cacheSlamsTimeout): self
{
$this->cacheSlamsTimeout = $cacheSlamsTimeout;
return $this;
}
/**
* @return bool
*/
public function isUseStaticItemCaching(): bool
{
return $this->useStaticItemCaching;
}
/**
* @param bool $useStaticItemCaching
* @return ConfigurationOption
*/
public function setUseStaticItemCaching(bool $useStaticItemCaching): self
{
$this->useStaticItemCaching = $useStaticItemCaching;
return $this;
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Config;
interface ConfigurationOptionInterface
{
/**
* @param $args
* ArrayObject constructor.
*/
public function __construct(...$args);
/**
* @param string $optionName
* @return mixed|null
*/
public function isValidOption(string $optionName);
}

View File

@ -0,0 +1,135 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Config;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
const SAFE_FILE_EXTENSIONS = 'txt|cache|db|pfc';
trait IOConfigurationOptionTrait
{
/**
* @var boolean
*/
protected $secureFileManipulation = false;
/**
* @var bool
*/
protected $htaccess = true;
/**
* @var string
*/
protected $securityKey = '';
/**
* @var string
*/
protected $cacheFileExtension = 'txt';
/**
* @return string
*/
public function getSecurityKey(): string
{
return $this->securityKey;
}
/**
* @param string $securityKey
* @return Config
*/
public function setSecurityKey(string $securityKey): self
{
$this->securityKey = $securityKey;
return $this;
}
/**
* @return bool
*/
public function getHtaccess(): bool
{
return $this->htaccess;
}
/**
* @param bool $htaccess
* @return Config
*/
public function setHtaccess(bool $htaccess): ConfigurationOptionInterface
{
$this->htaccess = $htaccess;
return $this;
}
/**
* @return bool
*/
public function isSecureFileManipulation(): bool
{
return $this->secureFileManipulation;
}
/**
* @param bool $secureFileManipulation
* @return self
*/
public function setSecureFileManipulation(bool $secureFileManipulation): self
{
$this->secureFileManipulation = $secureFileManipulation;
return $this;
}
/**
* @return string
*/
public function getCacheFileExtension(): string
{
return $this->cacheFileExtension;
}
/**
* @param string $cacheFileExtension
* @return self
* @throws PhpfastcacheInvalidConfigurationException
*/
public function setCacheFileExtension(string $cacheFileExtension): self
{
/**
* Feel free to propose your own one
* by opening a pull request :)
*/
$safeFileExtensions = \explode('|', SAFE_FILE_EXTENSIONS);
if (\strpos($cacheFileExtension, '.') !== false) {
throw new PhpfastcacheInvalidConfigurationException('cacheFileExtension cannot contain a dot "."');
}
if (!\in_array($cacheFileExtension, $safeFileExtensions, true)) {
throw new PhpfastcacheInvalidConfigurationException(
"Extension \"{$cacheFileExtension}\" is not safe, currently allowed extension names: " . \implode(', ', $safeFileExtensions)
);
}
$this->cacheFileExtension = $cacheFileExtension;
return $this;
}
}

View File

@ -0,0 +1,186 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Item;
use DateTimeInterface;
use JsonSerializable;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Event\EventManagerDispatcherInterface;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Phpfastcache\Util\ClassNamespaceResolverInterface;
use Psr\Cache\CacheItemInterface;
/**
* Interface ExtendedCacheItemInterface
*
* @package phpFastCache\Cache
*/
interface ExtendedCacheItemInterface extends CacheItemInterface, EventManagerDispatcherInterface, ClassNamespaceResolverInterface, JsonSerializable, TaggableCacheItemInterface
{
/**
* Returns the encoded key for the current cache item.
* Is a MD5 (default),SHA1,SHA256 hash if "defaultKeyHashFunction" config option is configured
* Else return the plain cache item key "defaultKeyHashFunction" config option is emptied
*
* @return string
* The encoded key string for this cache item.
*/
public function getEncodedKey(): string;
/**
* @return DateTimeInterface
*/
public function getExpirationDate(): DateTimeInterface;
/**
* Alias of expireAt() with forced $expiration param
*
* @param DateTimeInterface $expiration
* The point in time after which the item MUST be considered expired.
* If null is passed explicitly, a default value MAY be used. If none is set,
* the value should be stored permanently or for as long as the
* implementation allows.
*
* @return ExtendedCacheItemInterface
* The called object.
*/
public function setExpirationDate(DateTimeInterface $expiration): ExtendedCacheItemInterface;
/**
* @return DateTimeInterface
* @throws PhpfastcacheLogicException
*/
public function getCreationDate(): DateTimeInterface;
/**
* @return DateTimeInterface
* @throws PhpfastcacheLogicException
*/
public function getModificationDate(): DateTimeInterface;
/**
* @param $date DateTimeInterface
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheLogicException
*/
public function setCreationDate(DateTimeInterface $date): ExtendedCacheItemInterface;
/**
* @param $date DateTimeInterface
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheLogicException
*/
public function setModificationDate(DateTimeInterface $date): ExtendedCacheItemInterface;
/**
* @return int
*/
public function getTtl(): int;
/**
* @return bool
*/
public function isExpired(): bool;
/**
* @return bool
*/
public function isNull(): bool;
/**
* @return bool
*/
public function isEmpty(): bool;
/**
* Return the data length:
* - Either the number of char if it's a string (binary mode)
* - or the number of element if it's an array
* - or the number returned by count() if it's an object implementing \Countable interface
* - or -1 for anything else
*
* @return int
*/
public function getLength(): int;
/**
* @param ExtendedCacheItemPoolInterface $driver
*
* @return mixed
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver);
/**
* @param bool $isHit
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function setHit($isHit): ExtendedCacheItemInterface;
/**
* @param int $step
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function increment($step = 1): ExtendedCacheItemInterface;
/**
* @param int $step
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function decrement($step = 1): ExtendedCacheItemInterface;
/**
* @param array|string $data
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function append($data): ExtendedCacheItemInterface;
/**
* @param array|string $data
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function prepend($data): ExtendedCacheItemInterface;
/**
* Return the data as a well-formatted string.
* Any scalar value will be casted to an array
*
* @param int $option \json_encode() options
* @param int $depth \json_encode() depth
*
* @return string
*/
public function getDataAsJsonString(int $option = 0, int $depth = 512): string;
/**
* @param ExtendedCacheItemPoolInterface $driverPool
* @return bool
*/
public function doesItemBelongToThatDriverBackend(ExtendedCacheItemPoolInterface $driverPool): bool;
}

View File

@ -0,0 +1,214 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Item;
use DateInterval;
use DateTime;
use DateTimeInterface;
use Phpfastcache\Event\EventManagerDispatcherTrait;
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
/**
* Trait ItemBaseTrait
* @package phpFastCache\Core\Item
*/
trait ItemBaseTrait
{
use ItemExtendedTrait;
use EventManagerDispatcherTrait;
/**
* @var bool
*/
protected $fetched = false;
/**
* @var string
*/
protected $key;
/**
* @var mixed
*/
protected $data;
/**
* @var DateTimeInterface
*/
protected $expirationDate;
/**
* @var DateTimeInterface
*/
protected $creationDate;
/**
* @var DateTimeInterface
*/
protected $modificationDate;
/**
* @var array
*/
protected $tags = [];
/**
* @var array
*/
protected $removedTags = [];
/**
* @var bool
*/
protected $isHit = false;
/********************
*
* PSR-6 Methods
*
*******************/
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @return mixed
*/
public function get()
{
return $this->data;
}
/**
* @param mixed $value
* @return $this
*/
public function set($value)
{
/**
* The user set a value,
* therefore there is no need to
* fetch from source anymore
*/
$this->fetched = true;
$this->data = $value;
/**
* @eventName CacheSaveDeferredItem
* @param ExtendedCacheItemInterface $this
* @param mixed $value
*
*/
$this->eventManager->dispatch('CacheItemSet', $this, $value);
return $this;
}
/**
* @return bool
*/
public function isHit(): bool
{
return $this->isHit;
}
/**
* @param bool $isHit
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function setHit($isHit): ExtendedCacheItemInterface
{
if (\is_bool($isHit)) {
$this->isHit = $isHit;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('$isHit must be a boolean');
}
/**
* @param DateTimeInterface $expiration
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function expiresAt($expiration): ExtendedCacheItemInterface
{
if ($expiration instanceof DateTimeInterface) {
/**
* @eventName CacheItemExpireAt
* @param ExtendedCacheItemInterface $this
* @param DateTimeInterface $expiration
*/
$this->eventManager->dispatch('CacheItemExpireAt', $this, $expiration);
$this->expirationDate = $expiration;
} else {
throw new PhpfastcacheInvalidArgumentException('$expiration must be an object implementing the DateTimeInterface got: ' . \gettype($expiration));
}
return $this;
}
/**
* @param DateInterval|int $time
* @return $this
* @throws PhpfastcacheInvalidArgumentException
*/
public function expiresAfter($time)
{
if (\is_numeric($time)) {
if ($time <= 0) {
/**
* 5 years, however memcached or memory cached will gone when u restart it
* just recommended for sqlite. files
*/
$time = 30 * 24 * 3600 * 5;
}
/**
* @eventName CacheItemExpireAt
* @param ExtendedCacheItemInterface $this
* @param DateTimeInterface $expiration
*/
$this->eventManager->dispatch('CacheItemExpireAfter', $this, $time);
$this->expirationDate = (new DateTime())->add(new DateInterval(\sprintf('PT%dS', $time)));
} else {
if ($time instanceof DateInterval) {
/**
* @eventName CacheItemExpireAt
* @param ExtendedCacheItemInterface $this
* @param DateTimeInterface $expiration
*/
$this->eventManager->dispatch('CacheItemExpireAfter', $this, $time);
$this->expirationDate = (new DateTime())->add($time);
} else {
throw new PhpfastcacheInvalidArgumentException(\sprintf('Invalid date format, got "%s"', \gettype($time)));
}
}
return $this;
}
}

View File

@ -0,0 +1,367 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Item;
use Countable;
use DateTime;
use DateTimeInterface;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException, PhpfastcacheInvalidArgumentTypeException, PhpfastcacheLogicException};
use Phpfastcache\Util\ClassNamespaceResolverTrait;
/**
* Class ItemExtendedTrait
* @package phpFastCache\Core\Item
* @property DateTimeInterface $expirationDate Expiration date of the item
* @property DateTimeInterface $creationDate Creation date of the item
* @property DateTimeInterface $modificationDate Modification date of the item
* @property mixed $data Data of the item
* @property bool $fetched Fetch flag status
* @property string $key The item key
*/
trait ItemExtendedTrait
{
use ClassNamespaceResolverTrait;
use TaggableCacheItemTrait;
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @var ExtendedCacheItemPoolInterface
*/
protected $driver;
/**
* @var string
*/
protected $encodedKey;
/**
* Item constructor.
* @param ExtendedCacheItemPoolInterface $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(ExtendedCacheItemPoolInterface $driver, $key)
{
if (\is_string($key)) {
$this->key = $key;
$this->driver = $driver;
if($driver->getConfig()->isUseStaticItemCaching()){
$this->driver->setItem($this);
}
$this->expirationDate = new DateTime();
if ($this->driver->getConfig()->isItemDetailedDate()) {
$this->creationDate = new DateTime();
$this->modificationDate = new DateTime();
}
} else {
throw new PhpfastcacheInvalidArgumentTypeException('string', $key);
}
}
/**
* @return string
*/
public function getEncodedKey(): string
{
if (!$this->encodedKey) {
$keyHashFunction = $this->driver->getConfig()->getDefaultKeyHashFunction();
if ($keyHashFunction) {
$this->encodedKey = $keyHashFunction($this->getKey());
} else {
$this->encodedKey = $this->getKey();
}
}
return $this->encodedKey;
}
/**
* @return DateTimeInterface
*/
public function getExpirationDate(): DateTimeInterface
{
return $this->expirationDate;
}
/**
* Alias of expireAt() with forced $expiration param
*
* @param DateTimeInterface $expiration
* The point in time after which the item MUST be considered expired.
* If null is passed explicitly, a default value MAY be used. If none is set,
* the value should be stored permanently or for as long as the
* implementation allows.
*
* @return ExtendedCacheItemInterface
* The called object.
*/
public function setExpirationDate(DateTimeInterface $expiration): ExtendedCacheItemInterface
{
return $this->expiresAt($expiration);
}
/**
* @return DateTimeInterface
* @throws PhpfastcacheLogicException
*/
public function getCreationDate(): DateTimeInterface
{
if ($this->driver->getConfig()->isItemDetailedDate()) {
return $this->creationDate;
}
throw new PhpfastcacheLogicException('Cannot access to the creation date when the "itemDetailedDate" configuration is disabled.');
}
/**
* @param DateTimeInterface $date
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheLogicException
*/
public function setCreationDate(DateTimeInterface $date): ExtendedCacheItemInterface
{
if ($this->driver->getConfig()->isItemDetailedDate()) {
$this->creationDate = $date;
return $this;
}
throw new PhpfastcacheLogicException('Cannot access to the creation date when the "itemDetailedDate" configuration is disabled.');
}
/**
* @return DateTimeInterface
* @throws PhpfastcacheLogicException
*/
public function getModificationDate(): DateTimeInterface
{
if ($this->driver->getConfig()->isItemDetailedDate()) {
return $this->modificationDate;
}
throw new PhpfastcacheLogicException('Cannot access to the modification date when the "itemDetailedDate" configuration is disabled.');
}
/**
* @param DateTimeInterface $date
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheLogicException
*/
public function setModificationDate(DateTimeInterface $date): ExtendedCacheItemInterface
{
if ($this->driver->getConfig()->isItemDetailedDate()) {
$this->modificationDate = $date;
return $this;
}
throw new PhpfastcacheLogicException('Cannot access to the modification date when the "itemDetailedDate" configuration is disabled.');
}
/**
* @return int
*/
public function getTtl(): int
{
return \max(0, $this->expirationDate->getTimestamp() - \time());
}
/**
* @return bool
*/
public function isExpired(): bool
{
return $this->expirationDate->getTimestamp() < (new DateTime())->getTimestamp();
}
/**
* @return bool
*/
public function isNull(): bool
{
return $this->data === null;
}
/**
* @return bool
*/
public function isEmpty(): bool
{
return empty($this->data);
}
/**
* Return the data length:
* Either the string length if it's a string (binary mode)
* # or the number of element (count) if it's an array
* # or the number returned by count() if it's an object implementing \Countable interface
* # -1 for anything else
* @return int
*/
public function getLength(): int
{
switch (\gettype($this->data)) {
case 'array':
case 'object':
if (\is_array($this->data) || $this->data instanceof Countable) {
return \count($this->data);
}
break;
case 'string':
return \strlen($this->data);
break;
}
return -1;
}
/**
* @param int $step
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function increment($step = 1): ExtendedCacheItemInterface
{
if (\is_int($step)) {
$this->fetched = true;
$this->data += $step;
} else {
throw new PhpfastcacheInvalidArgumentException('$step must be numeric.');
}
return $this;
}
/**
* @param int $step
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function decrement($step = 1): ExtendedCacheItemInterface
{
if (\is_int($step)) {
$this->fetched = true;
$this->data -= $step;
} else {
throw new PhpfastcacheInvalidArgumentException('$step must be numeric.');
}
return $this;
}
/**
* @param array|string $data
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function append($data): ExtendedCacheItemInterface
{
if (\is_array($this->data)) {
$this->data[] = $data;
} else {
if (\is_string($data)) {
$this->data .= (string)$data;
} else {
throw new PhpfastcacheInvalidArgumentException('$data must be either array nor string.');
}
}
return $this;
}
/**
* @param array|string $data
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function prepend($data): ExtendedCacheItemInterface
{
if (\is_array($this->data)) {
\array_unshift($this->data, $data);
} else {
if (\is_string($data)) {
$this->data = (string)$data . $this->data;
} else {
throw new PhpfastcacheInvalidArgumentException('$data must be either array nor string.');
}
}
return $this;
}
/**
* Return the data as a well-formatted string.
* Any scalar value will be casted to an array
* @param int $option \json_encode() options
* @param int $depth \json_encode() depth
* @return string
*/
public function getDataAsJsonString(int $option = 0, int $depth = 512): string
{
$data = $this->get();
if (\is_object($data) || \is_array($data)) {
$data = \json_encode($data, $option, $depth);
} else {
$data = \json_encode([$data], $option, $depth);
}
return \json_encode($data, $option, $depth);
}
/**
* Implements \JsonSerializable interface
* @return mixed
*/
public function jsonSerialize()
{
return $this->get();
}
/**
* @param ExtendedCacheItemPoolInterface $driverPool
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
public function doesItemBelongToThatDriverBackend(ExtendedCacheItemPoolInterface $driverPool): bool
{
return $driverPool->getClassNamespace() === $this->getClassNamespace();
}
/**
* @return array
* @todo Is it still useful ??
*
* Prevent recursions for Debug (php 5.6+)
*/
final public function __debugInfo()
{
$info = \get_object_vars($this);
$info['driver'] = 'object(' . \get_class($info['driver']) . ')';
return $info;
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Item;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Interface TaggableCacheItemInterface
* @package Phpfastcache\Core\Item
*/
interface TaggableCacheItemInterface
{
/**
* @param string $tagName
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function addTag(string $tagName): ExtendedCacheItemInterface;
/**
* @param array $tagNames
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function addTags(array $tagNames): ExtendedCacheItemInterface;
/**
* @param array $tags
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function setTags(array $tags): ExtendedCacheItemInterface;
/**
* @return array
*/
public function getTags(): array;
/**
* @param string $separator
*
* @return string
*/
public function getTagsAsString(string $separator = ', '): string;
/**
* @param string $tagName
*
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function removeTag(string $tagName): ExtendedCacheItemInterface;
/**
* @param array $tagNames
*
* @return ExtendedCacheItemInterface
*/
public function removeTags(array $tagNames): ExtendedCacheItemInterface;
/**
* @return array
*/
public function getRemovedTags(): array;
}

View File

@ -0,0 +1,128 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Item;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Trait TaggableCacheItemTrait
* @package Phpfastcache\Core\Item
* @property array $tags The tags array
* @property array $removedTags The removed tags array
*/
trait TaggableCacheItemTrait
{
/**
* @param array $tagNames
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function addTags(array $tagNames): ExtendedCacheItemInterface
{
foreach ($tagNames as $tagName) {
$this->addTag($tagName);
}
return $this;
}
/**
* @param $tagName
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function addTag(string $tagName): ExtendedCacheItemInterface
{
if (\is_string($tagName)) {
$this->tags = \array_unique(\array_merge($this->tags, [$tagName]));
return $this;
}
throw new PhpfastcacheInvalidArgumentException('$tagName must be a string');
}
/**
* @param array $tags
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function setTags(array $tags): ExtendedCacheItemInterface
{
if (\count($tags)) {
if (\array_filter($tags, 'is_string')) {
$this->tags = $tags;
} else {
throw new PhpfastcacheInvalidArgumentException('$tagName must be an array of string');
}
}
return $this;
}
/**
* @return array
*/
public function getTags(): array
{
return $this->tags;
}
/**
* @param string $separator
* @return string
*/
public function getTagsAsString(string $separator = ', '): string
{
return \implode($separator, $this->tags);
}
/**
* @param array $tagNames
* @return ExtendedCacheItemInterface
*/
public function removeTags(array $tagNames): ExtendedCacheItemInterface
{
foreach ($tagNames as $tagName) {
$this->removeTag($tagName);
}
return $this;
}
/**
* @param $tagName
* @return ExtendedCacheItemInterface
*/
public function removeTag(string $tagName): ExtendedCacheItemInterface
{
if (($key = \array_search($tagName, $this->tags, true)) !== false) {
unset($this->tags[$key]);
$this->removedTags[] = $tagName;
}
return $this;
}
/**
* @return array
*/
public function getRemovedTags(): array
{
return \array_diff($this->removedTags, $this->tags);
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool;
use Psr\Cache\CacheItemInterface;
/**
* Trait AbstractCacheItemPoolTrait
* @package Phpfastcache\Core\Pool
*/
trait AbstractDriverPoolTrait
{
/**
* @return bool
*/
abstract protected function driverCheck(): bool;
/**
* @return bool
*/
abstract protected function driverConnect(): bool;
/**
* @param CacheItemInterface $item
* @return null|array [
* 'd' => 'THE ITEM DATA'
* 't' => 'THE ITEM DATE EXPIRATION'
* 'g' => 'THE ITEM TAGS'
* ]
*
*/
abstract protected function driverRead(CacheItemInterface $item);
/**
* @param CacheItemInterface $item
* @return bool
*/
abstract protected function driverWrite(CacheItemInterface $item): bool;
/**
* @param CacheItemInterface $item
* @return bool
*/
abstract protected function driverDelete(CacheItemInterface $item): bool;
/**
* @return bool
*/
abstract protected function driverClear(): bool;
}

View File

@ -0,0 +1,451 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool;
use DateTime;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Entities\DriverIO;
use Phpfastcache\Entities\ItemBatch;
use Phpfastcache\Event\EventManagerDispatcherTrait;
use Phpfastcache\Exceptions\{PhpfastcacheCoreException, PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Phpfastcache\Util\ClassNamespaceResolverTrait;
use Psr\Cache\CacheItemInterface;
use ReflectionClass;
use ReflectionObject;
use RuntimeException;
/**
* Trait StandardPsr6StructureTrait
* @package phpFastCache\Core
* @property ConfigurationOption $config The config array
* @method ConfigurationOption getConfig() Return the config object
* @method DriverIO getIO() Return the IO object
*/
trait CacheItemPoolTrait
{
use ClassNamespaceResolverTrait;
use EventManagerDispatcherTrait;
use TaggableCacheItemPoolTrait;
/**
* @var string
*/
protected static $unsupportedKeyChars = '{}()/\@:';
/**
* @var array
*/
protected $deferredList = [];
/**
* @var ExtendedCacheItemInterface[]
*/
protected $itemInstances = [];
/**CacheItemPoolTrait
* @param CacheItemInterface $item
* @return $this
* @throws PhpfastcacheInvalidArgumentException
*/
public function setItem(CacheItemInterface $item)
{
if ($this->getClassNamespace() . '\\Item' === \get_class($item)) {
if(!$this->getConfig()->isUseStaticItemCaching()){
throw new PhpfastcacheLogicException(
'The static item caching option (useStaticItemCaching) is disabled so you cannot attach an item.'
);
}
$this->itemInstances[$item->getKey()] = $item;
return $this;
}
throw new PhpfastcacheInvalidArgumentException(
\sprintf(
'Invalid Item Class "%s" for this driver "%s".',
get_class($item),
get_class($this)
)
);
}
/**
* @param array $keys
* @return array
* @throws PhpfastcacheCoreException
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheLogicException
*/
public function getItems(array $keys = [])
{
$collection = [];
foreach ($keys as $key) {
$collection[$key] = $this->getItem($key);
}
return $collection;
}
/**
* @param string $key
* @return ExtendedCacheItemInterface
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheLogicException
* @throws PhpfastcacheCoreException
*/
public function getItem($key)
{
if (\is_string($key)) {
$item = null;
/**
* Replace array_key_exists by isset
* due to performance issue on huge
* loop dispatching operations
*/
if (!isset($this->itemInstances[$key]) || !$this->getConfig()->isUseStaticItemCaching()) {
if (\preg_match('~([' . \preg_quote(self::$unsupportedKeyChars, '~') . ']+)~', $key, $matches)) {
throw new PhpfastcacheInvalidArgumentException(
'Unsupported key character detected: "' . $matches[1] . '". Please check: https://github.com/PHPSocialNetwork/phpfastcache/wiki/%5BV6%5D-Unsupported-characters-in-key-identifiers'
);
}
$cacheSlamsSpendSeconds = 0;
$class = $this->getClassNamespace() . '\Item';
/** @var $item ExtendedCacheItemInterface */
$item = new $class($this, $key);
$item->setEventManager($this->eventManager);
getItemDriverRead:
{
$driverArray = $this->driverRead($item);
if ($driverArray) {
if (!\is_array($driverArray)) {
throw new PhpfastcacheCoreException(
sprintf(
'The driverRead method returned an unexpected variable type: %s',
\gettype($driverArray)
)
);
}
$driverData = $this->driverUnwrapData($driverArray);
if ($this->getConfig()['preventCacheSlams']) {
while ($driverData instanceof ItemBatch) {
if ($driverData->getItemDate()->getTimestamp() + $this->getConfig()->getCacheSlamsTimeout() < \time()) {
/**
* The timeout has been reached
* Consider that the batch has
* failed and serve an empty item
* to avoid to get stuck with a
* batch item stored in driver
*/
goto getItemDriverExpired;
}
/**
* @eventName CacheGetItem
* @param $this ExtendedCacheItemPoolInterface
* @param $driverData ItemBatch
* @param $cacheSlamsSpendSeconds int
*/
$this->eventManager->dispatch('CacheGetItemInSlamBatch', $this, $driverData, $cacheSlamsSpendSeconds);
/**
* Wait for a second before
* attempting to get exit
* the current batch process
*/
\sleep(1);
$cacheSlamsSpendSeconds++;
goto getItemDriverRead;
}
}
$item->set($driverData);
$item->expiresAt($this->driverUnwrapEdate($driverArray));
if ($this->getConfig()->isItemDetailedDate()) {
/**
* If the itemDetailedDate has been
* set after caching, we MUST inject
* a new DateTime object on the fly
*/
$item->setCreationDate($this->driverUnwrapCdate($driverArray) ?: new DateTime());
$item->setModificationDate($this->driverUnwrapMdate($driverArray) ?: new DateTime());
}
$item->setTags($this->driverUnwrapTags($driverArray));
getItemDriverExpired:
if ($item->isExpired()) {
/**
* Using driverDelete() instead of delete()
* to avoid infinite loop caused by
* getItem() call in delete() method
* As we MUST return an item in any
* way, we do not de-register here
*/
$this->driverDelete($item);
/**
* Reset the Item
*/
$item->set(null)
->expiresAfter(abs((int)$this->getConfig()['defaultTtl']))
->setHit(false)
->setTags([]);
if ($this->getConfig()->isItemDetailedDate()) {
/**
* If the itemDetailedDate has been
* set after caching, we MUST inject
* a new DateTime object on the fly
*/
$item->setCreationDate(new DateTime());
$item->setModificationDate(new DateTime());
}
} else {
$item->setHit(true);
}
} else {
$item->expiresAfter(abs((int)$this->getConfig()['defaultTtl']));
}
}
}else{
$item = $this->itemInstances[$key];
}
if($item !== null){
/**
* @eventName CacheGetItem
* @param $this ExtendedCacheItemPoolInterface
* @param $this ExtendedCacheItemInterface
*/
$this->eventManager->dispatch('CacheGetItem', $this, $item);
$item->isHit() ? $this->getIO()->incReadHit() : $this->getIO()->incReadMiss();
return $item;
}
throw new PhpfastcacheInvalidArgumentException(\sprintf('Item %s was not build due to an unknown error', \gettype($key)));
}
throw new PhpfastcacheInvalidArgumentException(\sprintf('$key must be a string, got type "%s" instead.', \gettype($key)));
}
/**
* @param string $key
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
public function hasItem($key)
{
return $this->getItem($key)->isHit();
}
/**
* @return bool
*/
public function clear()
{
/**
* @eventName CacheClearItem
* @param $this ExtendedCacheItemPoolInterface
* @param $itemInstances ExtendedCacheItemInterface[]
*/
$this->eventManager->dispatch('CacheClearItem', $this, $this->itemInstances);
$this->getIO()->incWriteHit();
// Faster than detachAllItems()
$this->itemInstances = [];
return $this->driverClear();
}
/**
* @param array $keys
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
public function deleteItems(array $keys)
{
$return = null;
foreach ($keys as $key) {
$result = $this->deleteItem($key);
if ($result !== false) {
$return = $result;
}
}
return (bool)$return;
}
/**
* @param string $key
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
public function deleteItem($key)
{
$item = $this->getItem($key);
if ($item->isHit() && $this->driverDelete($item)) {
$item->setHit(false);
$this->getIO()->incWriteHit();
/**
* @eventName CacheCommitItem
* @param $this ExtendedCacheItemPoolInterface
* @param $item ExtendedCacheItemInterface
*/
$this->eventManager->dispatch('CacheDeleteItem', $this, $item);
/**
* De-register the item instance
* then collect gc cycles
*/
$this->deregisterItem($key);
/**
* Perform a tag cleanup to avoid memory leaks
*/
if (\strpos($key, self::DRIVER_TAGS_KEY_PREFIX) !== 0) {
$this->cleanItemTags($item);
}
return true;
}
return false;
}
/**
* @param CacheItemInterface $item
* @return CacheItemInterface
* @throws RuntimeException
*/
public function saveDeferred(CacheItemInterface $item)
{
if (!\array_key_exists($item->getKey(), $this->itemInstances)) {
$this->itemInstances[$item->getKey()] = $item;
} else {
if (\spl_object_hash($item) !== \spl_object_hash($this->itemInstances[$item->getKey()])) {
throw new RuntimeException('Spl object hash mismatches ! You probably tried to save a detached item which has been already retrieved from cache.');
}
}
/**
* @eventName CacheSaveDeferredItem
* @param $this ExtendedCacheItemPoolInterface
* @param $this ExtendedCacheItemInterface
*/
$this->eventManager->dispatch('CacheSaveDeferredItem', $this, $item);
return $this->deferredList[$item->getKey()] = $item;
}
/**
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
public function commit()
{
/**
* @eventName CacheCommitItem
* @param $this ExtendedCacheItemPoolInterface
* @param $deferredList ExtendedCacheItemInterface[]
*/
$this->eventManager->dispatch('CacheCommitItem', $this, $this->deferredList);
$return = null;
foreach ($this->deferredList as $key => $item) {
$result = $this->save($item);
if ($return !== false) {
unset($this->deferredList[$key]);
$return = $result;
}
}
return (bool)$return;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheLogicException
* @throws \ReflectionException
*/
public function save(CacheItemInterface $item)
{
/**
* @var ExtendedCacheItemInterface $item
*
* Replace array_key_exists by isset
* due to performance issue on huge
* loop dispatching operations
*/
if (!isset($this->itemInstances[$item->getKey()])) {
if($this->getConfig()->isUseStaticItemCaching()){
$this->itemInstances[$item->getKey()] = $item;
}
} else {
if (\spl_object_hash($item) !== \spl_object_hash($this->itemInstances[$item->getKey()])) {
throw new RuntimeException('Spl object hash mismatches ! You probably tried to save a detached item which has been already retrieved from cache.');
}
}
/**
* @eventName CacheSaveItem
* @param $this ExtendedCacheItemPoolInterface
* @param $this ExtendedCacheItemInterface
*/
$this->eventManager->dispatch('CacheSaveItem', $this, $item);
if ($this->getConfig()->isPreventCacheSlams()) {
/**
* @var $itemBatch ExtendedCacheItemInterface
*/
$class = new ReflectionClass((new ReflectionObject($this))->getNamespaceName() . '\Item');
$itemBatch = $class->newInstanceArgs([$this, $item->getKey()]);
$itemBatch->setEventManager($this->eventManager)
->set(new ItemBatch($item->getKey(), new DateTime()))
->expiresAfter($this->getConfig()->getCacheSlamsTimeout());
/**
* To avoid SPL mismatches
* we have to re-attach the
* original item to the pool
*/
$this->driverWrite($itemBatch);
$this->detachItem($itemBatch);
$this->attachItem($item);
}
if ($this->driverWrite($item) && $this->driverWriteTags($item)) {
$item->setHit(true);
$this->getIO()->incWriteHit();
return true;
}
return false;
}
}

View File

@ -0,0 +1,248 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool;
use DateTime;
use Exception;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Entities\DriverIO;
use Phpfastcache\Exceptions\{PhpfastcacheDriverCheckException, PhpfastcacheDriverConnectException};
use ReflectionObject;
/**
* Class DriverBaseTrait
* @package phpFastCache\Cache
*/
trait DriverBaseTrait
{
use ExtendedCacheItemPoolTrait;
/**
* @var ConfigurationOption the options
*/
protected $config;
/**
* @var bool
*/
protected $fallback = false;
/**
* @var object Instance of driver service
*/
protected $instance;
/**
* @var string
*/
protected $driverName;
/**
* @internal This variable is read-access only
* @var string
*/
protected $instanceId;
/**
* Driver constructor.
* @param ConfigurationOption $config
* @param string $instanceId
* @throws PhpfastcacheDriverCheckException
* @throws PhpfastcacheDriverConnectException
*/
public function __construct(ConfigurationOption $config, $instanceId)
{
$this->setConfig($config);
$this->instanceId = $instanceId;
$this->IO = new DriverIO();
if (!$this->driverCheck()) {
throw new PhpfastcacheDriverCheckException(\sprintf(self::DRIVER_CHECK_FAILURE, $this->getDriverName()));
}
try {
$this->driverConnect();
} catch (Exception $e) {
throw new PhpfastcacheDriverConnectException(
sprintf(
self::DRIVER_CONNECT_FAILURE,
$this->getDriverName(),
$e->getMessage(),
$e->getLine() ?: 'unknown line',
$e->getFile() ?: 'unknown file'
)
);
}
}
/**
* @return string
*/
public function getDriverName(): string
{
if (!$this->driverName) {
$this->driverName = \ucfirst(\substr(\strrchr((new ReflectionObject($this))->getNamespaceName(), '\\'), 1));
}
return $this->driverName;
}
/**
* @return ConfigurationOption
*/
public function getDefaultConfig(): ConfigurationOption
{
$className = self::getConfigClass();
return new $className;
}
/**
* @return string
*/
public static function getConfigClass(): string
{
$localConfigClass = \substr(static::class, 0, \strrpos(static::class, '\\')) . '\Config';
if (\class_exists($localConfigClass) && \is_a($localConfigClass, ConfigurationOption::class, true)) {
return $localConfigClass;
}
return ConfigurationOption::class;
}
/**
* @param ExtendedCacheItemInterface $item
* @return array
*/
public function driverPreWrap(ExtendedCacheItemInterface $item): array
{
$wrap = [
self::DRIVER_KEY_WRAPPER_INDEX => $item->getKey(), // Stored but not really used, allow you to quickly identify the cache key
self::DRIVER_DATA_WRAPPER_INDEX => $item->get(),
self::DRIVER_TAGS_WRAPPER_INDEX => $item->getTags(),
self::DRIVER_EDATE_WRAPPER_INDEX => $item->getExpirationDate(),
];
if ($this->getConfig()->isItemDetailedDate()) {
$wrap[self::DRIVER_MDATE_WRAPPER_INDEX] = new DateTime();
/**
* If the creation date exists
* reuse it else set a new Date
*/
$wrap[self::DRIVER_CDATE_WRAPPER_INDEX] = $item->getCreationDate() ?: new DateTime();
} else {
$wrap[self::DRIVER_MDATE_WRAPPER_INDEX] = null;
$wrap[self::DRIVER_CDATE_WRAPPER_INDEX] = null;
}
return $wrap;
}
/**
* @return ConfigurationOption
*/
public function getConfig(): ConfigurationOption
{
return $this->config;
}
/**
* @param ConfigurationOption $config
*/
public function setConfig(ConfigurationOption $config)
{
$this->config = $config;
}
/**
* @param array $wrapper
* @return mixed
*/
public function driverUnwrapData(array $wrapper)
{
return $wrapper[self::DRIVER_DATA_WRAPPER_INDEX];
}
/**
* @param array $wrapper
* @return DateTime
*/
public function driverUnwrapEdate(array $wrapper)
{
return $wrapper[self::DRIVER_EDATE_WRAPPER_INDEX];
}
/**
* @param array $wrapper
* @return DateTime
*/
public function driverUnwrapCdate(array $wrapper)
{
return $wrapper[self::DRIVER_CDATE_WRAPPER_INDEX];
}
/**
* @param array $wrapper
* @return DateTime
*/
public function driverUnwrapMdate(array $wrapper)
{
return $wrapper[self::DRIVER_MDATE_WRAPPER_INDEX];
}
/**
* @return string
*/
public function getInstanceId(): string
{
return $this->instanceId;
}
/**
* Encode data types such as object/array
* for driver that does not support
* non-scalar value
* @param $data
* @return string
*/
protected function encode($data): string
{
return \serialize($data);
}
/**
* Decode data types such as object/array
* for driver that does not support
* non-scalar value
* @param string|null $value
* @return mixed
*/
protected function decode($value)
{
return \unserialize((string)$value, ['allowed_classes' => true]);
}
/**
* Check if phpModule or CGI
* @return bool
*/
protected function isPHPModule(): bool
{
return (\PHP_SAPI === 'apache2handler' || \strpos(\PHP_SAPI, 'handler') !== false);
}
}

View File

@ -0,0 +1,211 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool;
use InvalidArgumentException;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Entities\DriverIO;
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Event\EventManagerDispatcherInterface;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Phpfastcache\Util\ClassNamespaceResolverInterface;
use Psr\Cache\{CacheItemInterface, CacheItemPoolInterface};
/**
* Interface ExtendedCacheItemPoolInterface
*
* IMPORTANT NOTICE
*
* If you modify this file please make sure that
* the ActOnAll helper will also get those modifications
* since it does no longer implements this interface
* @see \Phpfastcache\Helper\ActOnAll
*
* @package phpFastCache\Core\Pool
*/
interface ExtendedCacheItemPoolInterface extends CacheItemPoolInterface, EventManagerDispatcherInterface, ClassNamespaceResolverInterface, TaggableCacheItemPoolInterface
{
public const DRIVER_CHECK_FAILURE = '%s is not installed or is misconfigured, cannot continue.
Also, please verify the suggested dependencies in composer because as of the V6, 3rd party libraries are no longer required.';
public const DRIVER_CONNECT_FAILURE = '%s failed to connect with the following error message: "%s" line %d in %s';
public const DRIVER_KEY_WRAPPER_INDEX = 'k';
public const DRIVER_DATA_WRAPPER_INDEX = 'd';
/**
* Expiration date Index
*/
public const DRIVER_EDATE_WRAPPER_INDEX = 'e';
/**
* Creation date Index
*/
public const DRIVER_CDATE_WRAPPER_INDEX = 'c';
/**
* Modification date Index
*/
public const DRIVER_MDATE_WRAPPER_INDEX = 'm';
/**
* Return the config class name
* @return string
*/
public static function getConfigClass(): string;
/**
* @return ConfigurationOption
*/
public function getConfig(): ConfigurationOption;
/**
* @return ConfigurationOption
*/
public function getDefaultConfig(): ConfigurationOption;
/**
* @return string
*/
public function getDriverName(): string;
/**
* @return mixed
*/
public function getInstanceId(): string;
/**
* [phpFastCache phpDoc Override]
* Returns a Cache Item representing the specified key.
*
* This method must always return a CacheItemInterface object, even in case of
* a cache miss. It MUST NOT return null.
*
* @param string $key
* The key for which to return the corresponding Cache Item.
*
* @return ExtendedCacheItemInterface
* The corresponding Cache Item.
* @throws PhpfastcacheInvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function getItem($key);
/**
* [phpFastCache phpDoc Override]
* Returns a traversable set of cache items.
*
* @param array $keys
* An indexed array of keys of items to retrieve.
*
* @return ExtendedCacheItemInterface[]
* A traversable collection of Cache Items keyed by the cache keys of
* each item. A Cache item will be returned for each key, even if that
* key is not found. However, if no keys are specified then an empty
* traversable MUST be returned instead.
* @throws InvalidArgumentException
* If any of the keys in $keys are not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function getItems(array $keys = []);
/**
* Returns A json string that represents an array of items.
*
* @param array $keys
* An indexed array of keys of items to retrieve.
* @param int $option \json_encode() options
* @param int $depth \json_encode() depth
*
* @return string
* @throws InvalidArgumentException
* If any of the keys in $keys are not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function getItemsAsJsonString(array $keys = [], int $option = 0, int $depth = 512): string;
/**
* @param CacheItemInterface $item
* @return mixed
*/
public function setItem(CacheItemInterface $item);
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic;
/**
* Get a quick help guide
* about the current driver
*
* @return string
*/
public function getHelp(): string;
/**
* @param CacheItemInterface $item
* @return void
*/
public function detachItem(CacheItemInterface $item);
/**
* @return void
*/
public function detachAllItems();
/**
* @param CacheItemInterface $item
* @return void
* @throws PhpfastcacheLogicException
*/
public function attachItem(CacheItemInterface $item);
/**
* Returns true if the item exists, is attached and the Spl Hash matches
* Returns false if the item exists, is attached and the Spl Hash mismatches
* Returns null if the item does not exists
*
* @param CacheItemInterface $item
* @return bool|null
* @throws PhpfastcacheLogicException
*/
public function isAttached(CacheItemInterface $item);
/**
* Save multiple items, possible uses:
* saveMultiple([$item1, $item2, $item3]);
* saveMultiple($item1, $item2, $item3);
*
* @param ExtendedCacheItemInterface[] $items
* @return bool
*/
public function saveMultiple(...$items): bool;
/**
* @return DriverIO
*/
public function getIO(): DriverIO;
}

View File

@ -0,0 +1,155 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool;
use Phpfastcache\Entities\DriverIO;
use Phpfastcache\Exceptions\{PhpfastcacheLogicException};
use Psr\Cache\CacheItemInterface;
/**
* Trait ExtendedCacheItemPoolTrait
* @package Phpfastcache\Core\Pool
*/
trait ExtendedCacheItemPoolTrait
{
use CacheItemPoolTrait;
use AbstractDriverPoolTrait;
/**
* @var DriverIO
*/
protected $IO;
/**
* @inheritdoc
*/
public function getItemsAsJsonString(array $keys = [], int $option = 0, int $depth = 512): string
{
$callback = static function (CacheItemInterface $item) {
return $item->get();
};
return \json_encode(\array_map($callback, \array_values($this->getItems($keys))), $option, $depth);
}
/**
* @inheritdoc
*/
public function detachAllItems()
{
foreach ($this->itemInstances as $item) {
$this->detachItem($item);
}
}
/**
* @param CacheItemInterface $item
* @return void
*/
public function detachItem(CacheItemInterface $item)
{
if (isset($this->itemInstances[$item->getKey()])) {
$this->deregisterItem($item->getKey());
}
}
/**
* @param string $item
* @internal This method de-register an item from $this->itemInstances
*/
protected function deregisterItem(string $item)
{
unset($this->itemInstances[$item]);
if (\gc_enabled()) {
\gc_collect_cycles();
}
}
/**
* @inheritdoc
*/
public function attachItem(CacheItemInterface $item)
{
if (isset($this->itemInstances[$item->getKey()]) && \spl_object_hash($item) !== \spl_object_hash($this->itemInstances[$item->getKey()])) {
throw new PhpfastcacheLogicException(
'The item already exists and cannot be overwritten because the Spl object hash mismatches ! You probably tried to re-attach a detached item which has been already retrieved from cache.'
);
}
if(!$this->getConfig()->isUseStaticItemCaching()){
throw new PhpfastcacheLogicException(
'The static item caching option (useStaticItemCaching) is disabled so you cannot attach an item.'
);
}
$this->itemInstances[$item->getKey()] = $item;
}
/**
* Returns true if the item exists, is attached and the Spl Hash matches
* Returns false if the item exists, is attached and the Spl Hash mismatches
* Returns null if the item does not exists
*
* @param CacheItemInterface $item
* @return bool|null
*/
public function isAttached(CacheItemInterface $item)
{
if (isset($this->itemInstances[$item->getKey()])) {
return \spl_object_hash($item) === \spl_object_hash($this->itemInstances[$item->getKey()]);
}
return null;
}
/**
* @inheritdoc
*/
public function saveMultiple(...$items): bool
{
if (isset($items[0]) && \is_array($items[0])) {
foreach ($items[0] as $item) {
$this->save($item);
}
return true;
}
if (\is_array($items)) {
foreach ($items as $item) {
$this->save($item);
}
return true;
}
return false;
}
/**
* @return DriverIO
*/
public function getIO(): DriverIO
{
return $this->IO;
}
/**
* @return string
*/
public function getHelp(): string
{
return '';
}
}

View File

@ -0,0 +1,364 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool\IO;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Files\Config;
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Event\EventManagerInterface;
use Phpfastcache\Exceptions\PhpfastcacheIOException;
use Phpfastcache\Util\Directory;
/**
* Trait IOHelperTrait
* @package phpFastCache\Core\Pool\IO
* @property array $config The configuration array passed via DriverBaseTrait
* @property ExtendedCacheItemInterface[] $itemInstances The item instance passed via CacheItemPoolTrait
* @property EventManagerInterface $eventManager The event manager passed via CacheItemPoolTrait
* @method Config getConfig() Return the config object
* @method bool isPHPModule() Return true if is a php module
* @method string getDriverName() Get the driver name
*/
trait IOHelperTrait
{
/**
* @var array
*/
public $tmp = [];
/**
* Provide a generic getStats() method
* for files-based drivers
* @return DriverStatistic
* @throws PhpfastcacheIOException
*/
public function getStats(): DriverStatistic
{
$stat = new DriverStatistic();
$path = $this->getFilePath(false);
if (!is_dir($path)) {
throw new PhpfastcacheIOException("Can't read PATH:" . $path);
}
$stat->setRawData(
[
'tmp' => $this->tmp,
]
)
->setSize(Directory::dirSize($path))
->setInfo('Number of files used to build the cache: ' . Directory::getFileCount($path));
if($this->getConfig()->isUseStaticItemCaching()){
$stat->setData(implode(', ', \array_keys($this->itemInstances)));
}else{
$stat->setData('No data available since static item caching option (useStaticItemCaching) is disabled.');
}
return $stat;
}
/**
* @param $keyword
* @param bool $skip
* @return string
* @throws PhpfastcacheIOException
*/
protected function getFilePath($keyword, $skip = false): string
{
$path = $this->getPath();
if ($keyword === false) {
return $path;
}
$filename = $this->encodeFilename($keyword);
$folder = \substr($filename, 0, 2) . DIRECTORY_SEPARATOR . \substr($filename, 2, 2);
$path = \rtrim($path, '/\\') . DIRECTORY_SEPARATOR . $folder;
/**
* Skip Create Sub Folders;
*/
if (!$skip && !\is_dir($path) && @!\mkdir($path, $this->getDefaultChmod(), true) && !\is_dir($path)) {
throw new PhpfastcacheIOException(
'Path "' . $path . '" is not writable, please set a chmod 0777 or any writable permission and make sure to make use of an absolute path !'
);
}
return $path . \DIRECTORY_SEPARATOR . $filename . '.' . $this->getConfig()->getCacheFileExtension();
}
/**
* @param bool $readonly
* @return string
* @throws PhpfastcacheIOException
*/
public function getPath($readonly = false): string
{
/**
* Get the base system temporary directory
*/
$tmp_dir = \rtrim(\ini_get('upload_tmp_dir') ?: \sys_get_temp_dir(), '\\/') . DIRECTORY_SEPARATOR . 'phpfastcache';
/**
* Calculate the security key
*/
{
$securityKey = $this->getConfig()->getSecurityKey();
if (!$securityKey || \strtolower($securityKey) === 'auto') { // Changed by Observium developers (not required mb_* here)
if (isset($_SERVER['HTTP_HOST'])) {
$securityKey = \preg_replace('/^www./', '', \strtolower(\str_replace(':', '_', $_SERVER['HTTP_HOST'])));
} else {
$securityKey = ($this->isPHPModule() ? 'web' : 'cli');
}
}
if ($securityKey !== '') {
$securityKey .= '/';
}
$securityKey = static::cleanFileName($securityKey);
}
/**
* Extends the temporary directory
* with the security key and the driver name
*/
$tmp_dir = \rtrim($tmp_dir, '/') . DIRECTORY_SEPARATOR;
if (empty($this->getConfig()->getPath())) {
$path = $tmp_dir;
} else {
$path = \rtrim($this->getConfig()->getPath(), '/') . DIRECTORY_SEPARATOR;
}
$path_suffix = $securityKey . DIRECTORY_SEPARATOR . $this->getDriverName();
$full_path = Directory::getAbsolutePath($path . $path_suffix);
$full_path_tmp = Directory::getAbsolutePath($tmp_dir . $path_suffix);
$full_path_hash = $this->getConfig()->getDefaultFileNameHashFunction()($full_path);
/**
* In readonly mode we only attempt
* to verify if the directory exists
* or not, if it does not then we
* return the temp dir
*/
if ($readonly === true) {
if ($this->getConfig()->isAutoTmpFallback() && (!@\file_exists($full_path) || !@\is_writable($full_path))) {
return $full_path_tmp;
}
return $full_path;
}
if (!isset($this->tmp[$full_path_hash]) || (!@\file_exists($full_path) || !@\is_writable($full_path))) {
if (!@\file_exists($full_path)) {
if (@mkdir($full_path, $this->getDefaultChmod(), true) === false && !\is_dir($full_path)) {
throw new PhpfastcacheIOException('The directory ' . $full_path . ' could not be created.');
}
} else {
if (!@\is_writable($full_path)) {
if (!@\chmod($full_path, $this->getDefaultChmod()) && $this->getConfig()->isAutoTmpFallback()) {
/**
* Switch back to tmp dir
* again if the path is not writable
*/
$full_path = $full_path_tmp;
if (!@\file_exists($full_path)) {
if (@\mkdir($full_path, $this->getDefaultChmod(), true) && !\is_dir($full_path)) {
throw new PhpfastcacheIOException('The directory ' . $full_path . ' could not be created.');
}
}
}
}
}
/**
* In case there is no directory
* writable including the temporary
* one, we must throw an exception
*/
if (!@\file_exists($full_path) || !@\is_writable($full_path)) {
throw new PhpfastcacheIOException(
'Path "' . $full_path . '" is not writable, please set a chmod 0777 or any writable permission and make sure to make use of an absolute path !'
);
}
$this->tmp[$full_path_hash] = $full_path;
$this->htaccessGen($full_path, $this->getConfig()->isValidOption('htaccess') ? $this->getConfig()->getHtaccess() : false);
}
return realpath($full_path);
}
/**
* @param $filename
* @return string
*/
protected static function cleanFileName($filename): string
{
$regex = [
'/[\?\[\]\/\\\=\<\>\:\;\,\'\"\&\$\#\*\(\)\|\~\`\!\{\}]/',
'/\.$/',
'/^\./',
];
$replace = ['-', '', ''];
return \trim(\preg_replace($regex, $replace, \trim($filename)), '-');
}
/**
* @return int
*/
protected function getDefaultChmod(): int
{
if (!$this->getConfig()->getDefaultChmod()) {
return 0777;
}
return $this->getConfig()->getDefaultChmod();
}
/**
* @param $path
* @param bool $create
* @throws PhpfastcacheIOException
*/
protected function htaccessGen($path, $create = true)
{
if ($create === true) {
if (!\is_writable($path)) {
try {
if (!\chmod($path, 0777)) {
throw new PhpfastcacheIOException('Chmod failed on : ' . $path);
}
} catch (PhpfastcacheIOException $e) {
throw new PhpfastcacheIOException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!', 0, $e);
}
}
if (!\file_exists($path . '/.htaccess')) {
$file = @\fopen($path . '/.htaccess', 'w+b');
if (!$file) {
throw new PhpfastcacheIOException('PLEASE CHMOD ' . $path . ' - 0777 OR ANY WRITABLE PERMISSION!');
}
\fwrite(
$file,
<<<HTACCESS
### This .htaccess is auto-generated by PhpFastCache ###
<IfModule mod_authz_host>
Require all denied
</IfModule>
<IfModule !mod_authz_host>
Order Allow,Deny
Deny from all
</IfModule>
HTACCESS
);
\fclose($file);
}
}
}
/**
* @param $keyword
* @return string
*/
protected function encodeFilename($keyword): string
{
return $this->getConfig()->getDefaultFileNameHashFunction()($keyword);
}
/**
* @param $file
* @return string
* @throws PhpfastcacheIOException
*/
protected function readFile($file): string
{
if (!\is_readable($file)) {
throw new PhpfastcacheIOException("Cannot read file located at: {$file}");
}
if (\function_exists('file_get_contents')) {
return (string)\file_get_contents($file);
}
$string = '';
$file_handle = @\fopen($file, 'rb');
while (!\feof($file_handle)) {
$line = \fgets($file_handle);
$string .= $line;
}
\fclose($file_handle);
return $string;
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @param string $file
* @param string $data
* @param bool $secureFileManipulation
* @return bool
* @throws PhpfastcacheIOException
*/
protected function writefile(string $file, string $data, bool $secureFileManipulation = false): bool
{
/**
* @eventName CacheWriteFileOnDisk
* @param ExtendedCacheItemPoolInterface $this
* @param string $file
* @param bool $secureFileManipulation
*
*/
$this->eventManager->dispatch('CacheWriteFileOnDisk', $this, $file, $secureFileManipulation);
if ($secureFileManipulation) {
$tmpFilename = Directory::getAbsolutePath(
dirname($file) . \DIRECTORY_SEPARATOR . 'tmp_' . $this->getConfig()->getDefaultFileNameHashFunction()(
\bin2hex(\random_bytes(16))
)
) . '.' . $this->getConfig()->getCacheFileExtension() . \random_int(1000, 9999);
$handle = \fopen($tmpFilename, 'w+b');
if (\is_resource($handle)) {
\flock($handle, \LOCK_EX);
$octetWritten = fwrite($handle, $data);
\flock($handle, \LOCK_UN);
\fclose($handle);
}
if (!\rename($tmpFilename, $file)) {
throw new PhpfastcacheIOException(\sprintf('Failed to rename %s to %s', $tmpFilename, $file));
}
} else {
$handle = \fopen($file, 'w+b');
if (\is_resource($handle)) {
$octetWritten = \fwrite($handle, $data);
\fclose($handle);
}
}
return (bool)($octetWritten ?? false);
}
}

View File

@ -0,0 +1,281 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool;
use InvalidArgumentException;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
/**
* Interface TaggableCacheItemPoolInterface
* @package Phpfastcache\Core\Pool
*/
interface TaggableCacheItemPoolInterface
{
public const DRIVER_TAGS_KEY_PREFIX = '_TAG_';
public const DRIVER_TAGS_WRAPPER_INDEX = 'g';
public const TAG_STRATEGY_ONE = 1;
public const TAG_STRATEGY_ALL = 2;
public const TAG_STRATEGY_ONLY = 4;
/**
* Returns a traversable set of cache items by a tag name.
*
* @param string $tagName
* An indexed array of keys of items to retrieve.
*
* @param int $strategy
*
* @return ExtendedCacheItemInterface[]
* A traversable collection of Cache Items keyed by the cache keys of
* each item. A Cache item will be returned for each key, even if that
* key is not found. However, if no keys are specified then an empty
* traversable MUST be returned instead.
* @throws InvalidArgumentException
* If any of the keys in $keys are not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function getItemsByTag(string $tagName, int $strategy = self::TAG_STRATEGY_ONE): array;
/**
* Returns a traversable set of cache items by one of multiple tag names.
*
* @param string[] $tagNames
* An indexed array of keys of items to retrieve.
*
* @param int $strategy
*
* @return ExtendedCacheItemInterface[]
* A traversable collection of Cache Items keyed by the cache keys of
* each item. A Cache item will be returned for each key, even if that
* key is not found. However, if no keys are specified then an empty
* traversable MUST be returned instead.
* @throws InvalidArgumentException
* If any of the keys in $keys are not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function getItemsByTags(array $tagNames, int $strategy = self::TAG_STRATEGY_ONE): array;
/**
* Returns A json string that represents an array of items by tags-based.
*
* @param string[] $tagNames
* An indexed array of keys of items to retrieve.
* @param int $option \json_encode() options
* @param int $depth \json_encode() depth
* @param int $strategy
*
* @return string
* @throws InvalidArgumentException
* If any of the keys in $keys are not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function getItemsByTagsAsJsonString(array $tagNames, int $option = 0, int $depth = 512, int $strategy = self::TAG_STRATEGY_ONE): string;
/**
* Removes the item from the pool by tag.
*
* @param string $tagName
* The tag for which to delete
*
* @param int $strategy
*
* @return bool
* True if the item was successfully removed. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function deleteItemsByTag(string $tagName, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Removes the item from the pool by one of multiple tag names.
*
* @param string[] $tagNames
* The tag for which to delete
*
* @param int $strategy
*
* @return bool
* True if the items were successfully removed. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function deleteItemsByTags(array $tagNames, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Increment the items from the pool by tag.
*
* @param string $tagName
* The tag for which to increment
*
* @param int $step
*
* @param int $strategy
*
* @return bool
* True if the item was successfully incremented. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function incrementItemsByTag(string $tagName, int $step = 1, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Increment the items from the pool by one of multiple tag names.
*
* @param string[] $tagNames
* The tag for which to increment
*
* @param int $step
*
* @param int $strategy
*
* @return bool
* True if the items were successfully incremented. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function incrementItemsByTags(array $tagNames, int $step = 1, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Decrement the items from the pool by tag.
*
* @param string $tagName
* The tag for which to decrement
*
* @param int $step
*
* @param int $strategy
*
* @return bool
* True if the item was successfully decremented. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function decrementItemsByTag(string $tagName, int $step = 1, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Decrement the items from the pool by one of multiple tag names.
*
* @param string[] $tagNames
* The tag for which to decrement
*
* @param int $step
*
* @param int $strategy
*
* @return bool
* True if the item was successfully decremented. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function decrementItemsByTags(array $tagNames, int $step = 1, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Decrement the items from the pool by tag.
*
* @param string $tagName
* The tag for which to append
*
* @param array|string $data
*
* @param int $strategy
*
* @return bool
* True if the item was successfully appended. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function appendItemsByTag(string $tagName, $data, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Append the items from the pool by one of multiple tag names.
*
* @param string[] $tagNames
* The tag for which to append
*
* @param array|string $data
*
* @param int $strategy
*
* @return bool
* True if the items were successfully appended. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function appendItemsByTags(array $tagNames, $data, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Prepend the items from the pool by tag.
*
* @param string $tagName
* The tag for which to prepend
*
* @param array|string $data
*
* @param int $strategy
*
* @return bool
* True if the item was successfully prepended. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function prependItemsByTag(string $tagName, $data, int $strategy = self::TAG_STRATEGY_ONE): bool;
/**
* Prepend the items from the pool by one of multiple tag names.
*
* @param string[] $tagNames
* The tag for which to prepend
*
* @param array|string $data
*
* @param int $strategy
*
* @return bool
* True if the item was successfully prepended. False if there was an error.
* @throws InvalidArgumentException
* If the $key string is not a legal value a phpfastcacheInvalidArgumentException
* MUST be thrown.
*
*/
public function prependItemsByTags(array $tagNames, $data, int $strategy = self::TAG_STRATEGY_ONE): bool;
}

View File

@ -0,0 +1,415 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Core\Pool;
use DateTime;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Psr\Cache\{CacheItemInterface};
/**
* Trait TaggableCacheItemPoolTrait
* @package Phpfastcache\Core\Pool
* @method ExtendedCacheItemInterface getItem(string $key) Return the config object
* @method ExtendedCacheItemInterface[] getItems(array $keys) Return the config object
*/
trait TaggableCacheItemPoolTrait
{
/**
* @inheritdoc
*/
public function getItemsByTagsAsJsonString(array $tagNames, int $option = 0, int $depth = 512, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): string
{
$callback = static function (CacheItemInterface $item) {
return $item->get();
};
return \json_encode(\array_map($callback, \array_values($this->getItemsByTags($tagNames, $strategy))), $option, $depth);
}
/**
* @inheritdoc
*/
public function getItemsByTags(array $tagNames, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): array
{
$items = [];
foreach (\array_unique($tagNames) as $tagName) {
if (\is_string($tagName)) {
$items[] = $this->fetchItemsByTagFromBackend($tagName);
} else {
throw new PhpfastcacheInvalidArgumentException('$tagName must be a a string');
}
}
$items = \array_merge([], ...$items);
switch ($strategy) {
case TaggableCacheItemPoolInterface::TAG_STRATEGY_ALL:
foreach ($items as $key => $item) {
if (\array_diff($tagNames, $item->getTags())) {
unset($items[$key]);
}
}
break;
case TaggableCacheItemPoolInterface::TAG_STRATEGY_ONLY:
foreach ($items as $key => $item) {
if (\array_diff($tagNames, $item->getTags()) || \array_diff($item->getTags(), $tagNames)) {
unset($items[$key]);
}
}
break;
}
return $items;
}
/**
* @param string $tagName
* @return array
* @throws PhpfastcacheInvalidArgumentException
*/
protected function fetchItemsByTagFromBackend(string $tagName): array
{
if (\is_string($tagName)) {
$driverResponse = $this->getItem($this->getTagKey($tagName));
if ($driverResponse->isHit()) {
$tagsItems = (array)$driverResponse->get();
/**
* getItems() may provides expired item(s)
* themselves provided by a cache of item
* keys based stored the tag item.
* Therefore we pass a filter callback
* to remove the expired Item(s) provided by
* the item keys passed through getItems()
*
* #headache
*/
return \array_filter(
$this->getItems(\array_unique(\array_keys($tagsItems))),
static function (ExtendedCacheItemInterface $item) {
return $item->isHit();
}
);
}
return [];
}
throw new PhpfastcacheInvalidArgumentException('$tagName must be a string');
}
/**
* @param string $key
* @return string
*/
protected function getTagKey(string $key): string
{
return self::DRIVER_TAGS_KEY_PREFIX . $key;
}
/**
* @inheritdoc
*/
public function deleteItemsByTags(array $tagNames, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
$return = null;
foreach ($this->getItemsByTags($tagNames, $strategy) as $item) {
$result = $this->deleteItem($item->getKey());
if ($return !== false) {
$return = $result;
}
}
return (bool)$return;
}
/**
* @inheritdoc
*/
public function deleteItemsByTag(string $tagName, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
if (\is_string($tagName)) {
$return = null;
foreach ($this->getItemsByTag($tagName, $strategy) as $item) {
$result = $this->deleteItem($item->getKey());
if ($return !== false) {
$return = $result;
}
}
return (bool)$return;
}
throw new PhpfastcacheInvalidArgumentException('$tagName must be a string');
}
/**
* @inheritdoc
*/
public function getItemsByTag(string $tagName, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): array
{
$items = $this->fetchItemsByTagFromBackend($tagName);
if ($strategy === TaggableCacheItemPoolInterface::TAG_STRATEGY_ONLY) {
foreach ($items as $key => $item) {
if (\array_diff($item->getTags(), $tagName)) {
unset($items[$key]);
}
}
}
return $items;
}
/**
* @inheritdoc
*/
public function incrementItemsByTags(array $tagNames, int $step = 1, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
$return = null;
foreach ($tagNames as $tagName) {
$result = $this->incrementItemsByTag($tagName, $step, $strategy);
if ($return !== false) {
$return = $result;
}
}
return (bool)$return;
}
/**
* @inheritdoc
*/
public function incrementItemsByTag(string $tagName, int $step = 1, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
if (\is_string($tagName) && \is_int($step)) {
foreach ($this->getItemsByTag($tagName, $strategy) as $item) {
$item->increment($step);
$this->saveDeferred($item);
}
return (bool)$this->commit();
}
throw new PhpfastcacheInvalidArgumentException('$tagName must be a string and $step an integer');
}
/**
* @inheritdoc
*/
public function decrementItemsByTags(array $tagNames, int $step = 1, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
$return = null;
foreach ($tagNames as $tagName) {
$result = $this->decrementItemsByTag($tagName, $step, $strategy);
if ($return !== false) {
$return = $result;
}
}
return (bool)$return;
}
/**
* @inheritdoc
*/
public function decrementItemsByTag(string $tagName, int $step = 1, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
if (\is_string($tagName) && \is_int($step)) {
foreach ($this->getItemsByTag($tagName, $strategy) as $item) {
$item->decrement($step);
$this->saveDeferred($item);
}
return (bool)$this->commit();
}
throw new PhpfastcacheInvalidArgumentException('$tagName must be a string and $step an integer');
}
/**
* @inheritdoc
*/
public function appendItemsByTags(array $tagNames, $data, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
$return = null;
foreach ($tagNames as $tagName) {
$result = $this->appendItemsByTag($tagName, $data, $strategy);
if ($return !== false) {
$return = $result;
}
}
return (bool)$return;
}
/**
* @inheritdoc
*/
public function appendItemsByTag(string $tagName, $data, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
if (\is_string($tagName)) {
foreach ($this->getItemsByTag($tagName, $strategy) as $item) {
$item->append($data);
$this->saveDeferred($item);
}
return (bool)$this->commit();
}
throw new PhpfastcacheInvalidArgumentException('$tagName must be a string');
}
/**
* @inheritdoc
*/
public function prependItemsByTags(array $tagNames, $data, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
$return = null;
foreach ($tagNames as $tagName) {
$result = $this->prependItemsByTag($tagName, $data, $strategy);
if ($return !== false) {
$return = $result;
}
}
return (bool)$return;
}
/**
* @inheritdoc
*/
public function prependItemsByTag(string $tagName, $data, int $strategy = TaggableCacheItemPoolInterface::TAG_STRATEGY_ONE): bool
{
if (\is_string($tagName)) {
foreach ($this->getItemsByTag($tagName, $strategy) as $item) {
$item->prepend($data);
$this->saveDeferred($item);
}
return (bool)$this->commit();
}
throw new PhpfastcacheInvalidArgumentException('$tagName must be a string');
}
/**
* @param array $wrapper
* @return mixed
*/
protected function driverUnwrapTags(array $wrapper)
{
return $wrapper[self::DRIVER_TAGS_WRAPPER_INDEX];
}
/**
* @param ExtendedCacheItemInterface $item
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheLogicException
*/
protected function cleanItemTags(ExtendedCacheItemInterface $item)
{
$this->driverWriteTags($item->removeTags($item->getTags()));
}
/**
* @param ExtendedCacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheLogicException
*/
protected function driverWriteTags(ExtendedCacheItemInterface $item): bool
{
/**
* Do not attempt to write tags
* on tags item, it can leads
* to an infinite recursive calls
*/
if (\strpos($item->getKey(), self::DRIVER_TAGS_KEY_PREFIX) === 0) {
throw new PhpfastcacheLogicException('Trying to set tag(s) to an Tag item index: ' . $item->getKey());
}
if (!$item->getTags() && !$item->getRemovedTags()) {
return true;
}
/**
* @var $tagsItems ExtendedCacheItemInterface[]
*/
$tagsItems = $this->getItems($this->getTagKeys($item->getTags()));
foreach ($tagsItems as $tagsItem) {
$data = $tagsItem->get();
$expTimestamp = $item->getExpirationDate()->getTimestamp();
/**
* Using the key will
* avoid to use array_unique
* that has slow performances
*/
$tagsItem->set(\array_merge((array)$data, [$item->getKey() => $expTimestamp]))
->expiresAt($item->getExpirationDate());
$this->driverWrite($tagsItem);
$tagsItem->setHit(true);
}
/**
* Also update removed tags to
* keep the index up to date
*/
$tagsItems = $this->getItems($this->getTagKeys($item->getRemovedTags()));
foreach ($tagsItems as $tagsItem) {
$data = (array)$tagsItem->get();
unset($data[$item->getKey()]);
$tagsItem->set($data);
/**
* Recalculate the expiration date
*
* If the $tagsItem does not have
* any cache item references left
* then remove it from tagsItems index
*/
if (\count($data)) {
$tagsItem->expiresAt((new DateTime())->setTimestamp(max($data)));
$this->driverWrite($tagsItem);
$tagsItem->setHit(true);
} else {
$this->deleteItem($tagsItem->getKey());
}
}
return true;
}
/**
* @param array $keys
* @return array
*/
protected function getTagKeys(array $keys): array
{
return \array_map(
function (string $key) {
return $this->getTagKey($key);
},
$keys
);
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Apcu;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,136 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Apcu;
use DateTime;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('apcu') && ini_get('apc.enabled');
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stats = (array)apcu_cache_info();
$date = (new DateTime())->setTimestamp($stats['start_time']);
return (new DriverStatistic())
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo(
sprintf(
"The APCU cache is up since %s, and have %d item(s) in cache.\n For more information see RawData.",
$date->format(DATE_RFC2822),
$stats['num_entries']
)
)
->setRawData($stats)
->setSize((int)$stats['mem_size']);
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)apcu_store($item->getKey(), $this->driverPreWrap($item), $item->getTtl());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$data = apcu_fetch($item->getKey(), $success);
if ($success === false) {
return null;
}
return $data;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)apcu_delete($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
return @apcu_clear_cache();
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Apcu;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Apcu\Driver as ApcuDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Apcu
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(ApcuDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof ApcuDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,177 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Cassandra;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 9042;
/**
* @var int
*/
protected $timeout = 2;
/**
* @var string
*/
protected $username = '';
/**
* @var string
*/
protected $password = '';
/**
* @var bool
*/
protected $sslEnabled = false;
/**
* @var bool
*/
protected $sslVerify = false;
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return self
*/
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return self
*/
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
/**
* @return int
*/
public function getTimeout(): int
{
return $this->timeout;
}
/**
* @param int $timeout
* @return self
*/
public function setTimeout(int $timeout): self
{
$this->timeout = $timeout;
return $this;
}
/**
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* @param string $username
* @return self
*/
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
/**
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @param string $password
* @return self
*/
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @return bool
*/
public function isSslEnabled(): bool
{
return $this->sslEnabled;
}
/**
* @param bool $sslEnabled
* @return self
*/
public function setSslEnabled(bool $sslEnabled): self
{
$this->sslEnabled = $sslEnabled;
return $this;
}
/**
* @return bool
*/
public function isSslVerify(): bool
{
return $this->sslVerify;
}
/**
* @param bool $sslVerify
* @return self
*/
public function setSslVerify(bool $sslVerify): self
{
$this->sslVerify = $sslVerify;
return $this;
}
}

View File

@ -0,0 +1,323 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Cassandra;
use Cassandra;
use Cassandra\Exception;
use Cassandra\Exception\InvalidArgumentException;
use Cassandra\Session as CassandraSession;
use DateTime;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property CassandraSession $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
protected const CASSANDRA_KEY_SPACE = 'phpfastcache';
protected const CASSANDRA_TABLE = 'cacheItems';
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('Cassandra') && class_exists(Cassandra::class);
}
/**
* @return string
*/
public function getHelp(): string
{
return <<<HELP
<p>
To install the php Cassandra extension via Pecl:
<code>sudo pecl install cassandra</code>
More information on: https://github.com/datastax/php-driver
Please not that this repository only provide php stubs and C/C++ sources, it does NOT provide php client.
</p>
HELP;
}
/**
* @return DriverStatistic
* @throws Exception
*/
public function getStats(): DriverStatistic
{
$result = $this->instance->execute(
new Cassandra\SimpleStatement(
sprintf(
'SELECT SUM(cache_length) as cache_size FROM %s.%s',
self::CASSANDRA_KEY_SPACE,
self::CASSANDRA_TABLE
)
)
);
return (new DriverStatistic())
->setSize($result->first()['cache_size'])
->setRawData([])
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo('The cache size represents only the cache data itself without counting data structures associated to the cache entries.');
}
/**
* @return bool
* @throws PhpfastcacheLogicException
* @throws Exception
*/
protected function driverConnect(): bool
{
if ($this->instance instanceof CassandraSession) {
throw new PhpfastcacheLogicException('Already connected to Couchbase server');
}
$clientConfig = $this->getConfig();
$clusterBuilder = Cassandra::cluster()
->withContactPoints($clientConfig->getHost())
->withPort($clientConfig->getPort());
if (!empty($clientConfig->isSslEnabled())) {
if (!empty($clientConfig->isSslVerify())) {
$sslBuilder = Cassandra::ssl()->withVerifyFlags(Cassandra::VERIFY_PEER_CERT);
} else {
$sslBuilder = Cassandra::ssl()->withVerifyFlags(Cassandra::VERIFY_NONE);
}
$clusterBuilder->withSSL($sslBuilder->build());
}
$clusterBuilder->withConnectTimeout($clientConfig->getTimeout());
if ($clientConfig->getUsername()) {
$clusterBuilder->withCredentials($clientConfig->getUsername(), $clientConfig->getPassword());
}
$this->instance = $clusterBuilder->build()->connect();
/**
* In case of emergency:
* $this->instance->execute(
* new Cassandra\SimpleStatement(\sprintf("DROP KEYSPACE %s;", self::CASSANDRA_KEY_SPACE))
* );
*/
$this->instance->execute(
new Cassandra\SimpleStatement(
sprintf(
"CREATE KEYSPACE IF NOT EXISTS %s WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };",
self::CASSANDRA_KEY_SPACE
)
)
);
$this->instance->execute(new Cassandra\SimpleStatement(sprintf('USE %s;', self::CASSANDRA_KEY_SPACE)));
$this->instance->execute(
new Cassandra\SimpleStatement(
sprintf(
'
CREATE TABLE IF NOT EXISTS %s (
cache_uuid uuid,
cache_id varchar,
cache_data text,
cache_creation_date timestamp,
cache_expiration_date timestamp,
cache_length int,
PRIMARY KEY (cache_id)
);',
self::CASSANDRA_TABLE
)
)
);
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
try {
$options = new Cassandra\ExecutionOptions(
[
'arguments' => ['cache_id' => $item->getKey()],
'page_size' => 1,
]
);
$query = sprintf(
'SELECT cache_data FROM %s.%s WHERE cache_id = :cache_id;',
self::CASSANDRA_KEY_SPACE,
self::CASSANDRA_TABLE
);
$results = $this->instance->execute(new Cassandra\SimpleStatement($query), $options);
if ($results instanceof Cassandra\Rows && $results->count() === 1) {
return $this->decode($results->first()['cache_data']);
}
return null;
} catch (Exception $e) {
return null;
}
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$cacheData = $this->encode($this->driverPreWrap($item));
$options = new Cassandra\ExecutionOptions(
[
'arguments' => [
'cache_uuid' => new Cassandra\Uuid(),
'cache_id' => $item->getKey(),
'cache_data' => $cacheData,
'cache_creation_date' => new Cassandra\Timestamp((new DateTime())->getTimestamp()),
'cache_expiration_date' => new Cassandra\Timestamp($item->getExpirationDate()->getTimestamp()),
'cache_length' => strlen($cacheData),
],
'consistency' => Cassandra::CONSISTENCY_ALL,
'serial_consistency' => Cassandra::CONSISTENCY_SERIAL,
]
);
$query = sprintf(
'INSERT INTO %s.%s
(
cache_uuid,
cache_id,
cache_data,
cache_creation_date,
cache_expiration_date,
cache_length
)
VALUES (:cache_uuid, :cache_id, :cache_data, :cache_creation_date, :cache_expiration_date, :cache_length);
',
self::CASSANDRA_KEY_SPACE,
self::CASSANDRA_TABLE
);
$result = $this->instance->execute(new Cassandra\SimpleStatement($query), $options);
/**
* There's no real way atm
* to know if the item has
* been really upserted
*/
return $result instanceof Cassandra\Rows;
} catch (InvalidArgumentException $e) {
throw new PhpfastcacheInvalidArgumentException($e, 0, $e);
}
} else {
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$options = new Cassandra\ExecutionOptions(
[
'arguments' => [
'cache_id' => $item->getKey(),
],
]
);
$result = $this->instance->execute(
new Cassandra\SimpleStatement(
sprintf(
'DELETE FROM %s.%s WHERE cache_id = :cache_id;',
self::CASSANDRA_KEY_SPACE,
self::CASSANDRA_TABLE
)
),
$options
);
/**
* There's no real way atm
* to know if the item has
* been really deleted
*/
return $result instanceof Cassandra\Rows;
} catch (Exception $e) {
return false;
}
} else {
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
}
/**
* @return bool
*/
protected function driverClear(): bool
{
try {
$this->instance->execute(
new Cassandra\SimpleStatement(
sprintf(
'TRUNCATE %s.%s;',
self::CASSANDRA_KEY_SPACE,
self::CASSANDRA_TABLE
)
)
);
return true;
} catch (Exception $e) {
return false;
}
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Cassandra;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Core\Item\ItemBaseTrait;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Cassandra\Driver as CassandraDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Cassandra
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(CassandraDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof CassandraDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Cookie;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
protected $awareOfUntrustableData = false;
/**
* @return bool
*/
public function isAwareOfUntrustableData(): bool
{
return $this->awareOfUntrustableData;
}
/**
* @param bool $awareOfUntrustableData
* @return Config
*/
public function setAwareOfUntrustableData(bool $awareOfUntrustableData): Config
{
$this->awareOfUntrustableData = $awareOfUntrustableData;
return $this;
}
}

View File

@ -0,0 +1,186 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Cookie;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface
{
use DriverBaseTrait;
protected const PREFIX = 'PFC_';
/**
* @return bool
*/
public function driverCheck(): bool
{
if (!$this->getConfig()->isAwareOfUntrustableData()) {
throw new PhpfastcacheDriverException(
'You have to setup the config "awareOfUntrustableData" to "TRUE" to confirm that you are aware that this driver does not use reliable storage as it may be corrupted by end-user.'
);
}
return function_exists('setcookie');
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$size = 0;
$stat = new DriverStatistic();
$stat->setData($_COOKIE);
/**
* Only count PFC Cookie
*/
foreach ($_COOKIE as $key => $value) {
if (strpos($key, self::PREFIX) === 0) {
$size += strlen($value);
}
}
$stat->setSize($size);
return $stat;
}
/**
* @param CacheItemInterface $item
* @return null|array
* @throws PhpfastcacheDriverException
*/
protected function driverRead(CacheItemInterface $item)
{
$this->driverConnect();
$keyword = self::PREFIX . $item->getKey();
$x = isset($_COOKIE[$keyword]) ? json_decode($_COOKIE[$keyword], true) : false;
if ($x == false) {
return null;
}
if (!is_scalar($this->driverUnwrapData($x)) && !is_null($this->driverUnwrapData($x))) {
throw new PhpfastcacheDriverException('Hacking attempt: The decoding returned a non-scalar value, Cookie driver does not allow this.');
}
return $x;
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return !(!array_key_exists('_pfc', $_COOKIE) && !@setcookie('_pfc', '1', 10));
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$this->driverConnect();
$keyword = self::PREFIX . $item->getKey();
$v = json_encode($this->driverPreWrap($item));
if ($this->getConfig()->getLimitedMemoryByObject() !== null && strlen($v) > $this->getConfig()->getLimitedMemoryByObject()) {
return false;
}
return setcookie($keyword, $v, $item->getExpirationDate()->getTimestamp(), '/');
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param string $key
* @return int
*/
protected function driverReadExpirationDate($key): int
{
$this->driverConnect();
$keyword = self::PREFIX . $key;
$x = isset($_COOKIE[$keyword]) ? $this->decode(json_decode($_COOKIE[$keyword])->t) : 0;
return $x ? $x - time() : $x;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$this->driverConnect();
$keyword = self::PREFIX . $item->getKey();
$_COOKIE[$keyword] = null;
return @setcookie($keyword, null, -10);
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
$return = null;
$this->driverConnect();
foreach ($_COOKIE as $keyword => $value) {
if (strpos($keyword, self::PREFIX) !== false) {
$_COOKIE[$keyword] = null;
$result = @setcookie($keyword, null, -10);
if ($return !== false) {
$return = $result;
}
}
}
return $return;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Cookie;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Cookie\Driver as CookieDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Cookie
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(CookieDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof CookieDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,138 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchbase;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
protected const DEFAULT_VALUE = '_default';
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 8091;// SSL: 18091
/**
* @var string
*/
protected $username = '';
/**
* @var string
*/
protected $password = '';
/**
* @var string
*/
protected $bucketName = self::DEFAULT_VALUE;
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return Config
*/
public function setHost(string $host): Config
{
$this->host = $host;
return $this;
}
/**
* @return int|null
*/
public function getPort()
{
return $this->port;
}
/**
* @param int $port
* @return Config
*/
public function setPort(int $port = null): Config
{
$this->port = $port;
return $this;
}
/**
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* @param string $username
* @return Config
*/
public function setUsername(string $username): Config
{
$this->username = $username;
return $this;
}
/**
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @param string $password
* @return Config
*/
public function setPassword(string $password): Config
{
$this->password = $password;
return $this;
}
/**
* @return string
*/
public function getBucketName(): string
{
return $this->bucketName;
}
/**
* @param string $bucketName
* @return Config
*/
public function setBucketName(string $bucketName): Config
{
$this->bucketName = $bucketName;
return $this;
}
}

View File

@ -0,0 +1,258 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchbase;
use Couchbase\Exception as CouchbaseException;
use Couchbase\PasswordAuthenticator;
use Couchbase\Bucket as CouchbaseBucket;
use Couchbase\Cluster as CouchbaseClient;
use DateTime;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverCheckException, PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property CouchbaseClient $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait {
__construct as __baseConstruct;
}
/**
* @var CouchbaseBucket[]
*/
protected $bucketInstances = [];
/**
* @var CouchbaseBucket
*/
protected $bucketInstance;
/**
* @var string
*/
protected $currentBucket = '';
public function __construct(ConfigurationOption $config, $instanceId)
{
// @todo Deprecation to enable in v8.1
// \trigger_error('Couchbase driver is now deprecated and will be removed in the V9, use Couchbasev3 instead which will support SDK 3.', \E_USER_DEPRECATED);
$this->__baseConstruct($config, $instanceId);
}
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('couchbase');
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$info = $this->getBucket()->manager()->info();
return (new DriverStatistic())
->setSize($info['basicStats']['diskUsed'])
->setRawData($info)
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo(
'CouchBase version ' . $info['nodes'][0]['version'] . ', Uptime (in days): ' . round(
$info['nodes'][0]['uptime'] / 86400,
1
) . "\n For more information see RawData."
);
}
/**
* @return bool
* @throws PhpfastcacheLogicException
*/
protected function driverConnect(): bool
{
if (\class_exists(\Couchbase\ClusterOptions::class)) {
throw new PhpfastcacheDriverCheckException('You are using the Couchbase PHP SDK 3.x so please use driver Couchbasev3');
}
if ($this->instance instanceof CouchbaseClient) {
throw new PhpfastcacheLogicException('Already connected to Couchbase server');
}
$clientConfig = $this->getConfig();
$authenticator = new PasswordAuthenticator();
$authenticator->username($clientConfig->getUsername())->password($clientConfig->getPassword());
$this->instance = new CouchbaseClient(
'couchbase://' . $clientConfig->getHost() . ($clientConfig->getPort() ? ":{$clientConfig->getPort()}" : '')
);
$this->instance->authenticate($authenticator);
$this->setBucket($this->instance->openBucket($clientConfig->getBucketName()));
return true;
}
/**
* @param CouchbaseBucket $CouchbaseBucket
*/
protected function setBucket(CouchbaseBucket $CouchbaseBucket)
{
$this->bucketInstance = $CouchbaseBucket;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
try {
/**
* CouchbaseBucket::get() returns a CouchbaseMetaDoc object
*/
return $this->decodeDocument((array) $this->getBucket()->get($item->getEncodedKey())->value);
} catch (CouchbaseException $e) {
return null;
}
}
/**
* @return CouchbaseBucket
*/
protected function getBucket(): CouchbaseBucket
{
return $this->bucketInstance;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
return (bool)$this->getBucket()->upsert(
$item->getEncodedKey(),
$this->encodeDocument($this->driverPreWrap($item)),
['expiry' => $item->getTtl()]
);
} catch (CouchbaseException $e) {
return false;
}
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
return (bool)$this->getBucket()->remove($item->getEncodedKey());
} catch (Exception $e) {
return $e->getCode() === COUCHBASE_KEY_ENOENT;
}
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param array $data
* @return array
*/
protected function encodeDocument(array $data): array
{
$data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX] = $this->encode($data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX]);
$data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX] = $data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX]->format(\DateTime::ATOM);
if($this->getConfig()->isItemDetailedDate()){
$data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX] = $data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX]->format(\DateTime::ATOM);
$data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX] = $data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX]->format(\DateTime::ATOM);
}
return $data;
}
/**
* @param array $data
* @return array
*/
protected function decodeDocument(array $data): array
{
$data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX] = $this->decode($data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX]);
$data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX] = \DateTime::createFromFormat(
\DateTime::ATOM,
$data[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX]
);
if($this->getConfig()->isItemDetailedDate()){
$data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX] = \DateTime::createFromFormat(
\DateTime::ATOM,
$data[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX]
);
$data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX] = \DateTime::createFromFormat(
\DateTime::ATOM,
$data[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX]
);
}
return $data;
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
$this->getBucket()->manager()->flush();
return true;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchbase;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Couchbase\Driver as CouchbaseDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Couchbase
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(CouchbaseDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof CouchbaseDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchbasev3;
use Phpfastcache\Drivers\Couchbase\Config as CoubaseV2Config;
class Config extends CoubaseV2Config
{
/**
* @var string
*/
protected $bucketName = 'phpfastcache';
protected $scopeName = self::DEFAULT_VALUE;
protected $collectionName = self::DEFAULT_VALUE;
/**
* @return string
*/
public function getScopeName(): string
{
return $this->scopeName;
}
/**
* @param string $scopeName
* @return Config
*/
public function setScopeName(string $scopeName): Config
{
$this->scopeName = $scopeName;
return $this;
}
/**
* @return string
*/
public function getCollectionName(): string
{
return $this->collectionName;
}
/**
* @param string $collectionName
* @return Config
*/
public function setCollectionName(string $collectionName): Config
{
$this->collectionName = $collectionName;
return $this;
}
}

View File

@ -0,0 +1,202 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchbasev3;
use Couchbase\{BaseException as CouchbaseException, Cluster, ClusterOptions, Collection, DocumentNotFoundException, Scope, UpsertOptions};
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Drivers\Couchbase\Driver as CoubaseV2Driver;
use Phpfastcache\Drivers\Couchbase\Item;
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverCheckException, PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Cluster $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver extends CoubaseV2Driver
{
/**
* @var Scope
*/
protected $scope;
/**
* @var Collection
*/
protected $collection;
public function __construct(ConfigurationOption $config, $instanceId)
{
$this->__baseConstruct($config, $instanceId);
}
/**
* @return bool
* @throws PhpfastcacheLogicException
*/
protected function driverConnect(): bool
{
if (!\class_exists(ClusterOptions::class)) {
throw new PhpfastcacheDriverCheckException('You are using the Couchbase PHP SDK 2.x so please use driver Couchbasev3');
}
$connectionString = "couchbase://{$this->getConfig()->getHost()}:{$this->getConfig()->getPort()}";
$options = new ClusterOptions();
$options->credentials($this->getConfig()->getUsername(), $this->getConfig()->getPassword());
$this->instance = new Cluster($connectionString, $options);
$this->setBucket($this->instance->bucket($this->getConfig()->getBucketName()));
$this->setScope($this->getBucket()->scope($this->getConfig()->getScopeName()));
$this->setCollection($this->getScope()->collection($this->getConfig()->getCollectionName()));
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
try {
/**
* CouchbaseBucket::get() returns a GetResult interface
*/
return $this->decodeDocument((array)$this->getCollection()->get($item->getEncodedKey())->content());
} catch (DocumentNotFoundException $e) {
return null;
}
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$this->getCollection()->upsert(
$item->getEncodedKey(),
$this->encodeDocument($this->driverPreWrap($item)),
(new UpsertOptions())->expiry($item->getTtl())
);
return true;
} catch (CouchbaseException $e) {
return false;
}
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$this->getCollection()->remove($item->getEncodedKey());
return true;
} catch (DocumentNotFoundException $e) {
return true;
} catch (CouchbaseException $e) {
return false;
}
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
$this->instance->buckets()->flush($this->getConfig()->getBucketName());
return true;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
/**
* Between SDK 2 and 3 we lost a lot of useful information :(
* @see https://docs.couchbase.com/java-sdk/current/project-docs/migrating-sdk-code-to-3.n.html#management-apis
*/
$info = $this->getBucket()->diagnostics(\bin2hex(\random_bytes(16)));
return (new DriverStatistic())
->setSize(0)
->setRawData($info)
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo( $info['sdk'] . "\n For more information see RawData.");
}
/**
* @return Collection
*/
public function getCollection(): Collection
{
return $this->collection;
}
/**
* @param Collection $collection
* @return Driver
*/
public function setCollection(Collection $collection): Driver
{
$this->collection = $collection;
return $this;
}
/**
* @return Scope
*/
public function getScope(): Scope
{
return $this->scope;
}
/**
* @param Scope $scope
* @return Driver
*/
public function setScope(Scope $scope): Driver
{
$this->scope = $scope;
return $this;
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchbasev3;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Couchbase\Item as CoubaseV2Item;
use Phpfastcache\Drivers\Couchbasev3\Driver as CouchbaseDriver;
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
/**
* Class Item
* @package phpFastCache\Drivers\Couchbase
*/
class Item extends CoubaseV2Item
{
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(CouchbaseDriver $driver, $key)
{
parent::__construct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof CouchbaseDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchdb;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
class Config extends ConfigurationOption
{
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 5984;
/**
* @var string
*/
protected $username = '';
/**
* @var string
*/
protected $password = '';
/**
* @var bool
*/
protected $ssl = false;
/**
* @var int
*/
protected $timeout = 10;
/**
* @var string
*/
protected $database = Driver::COUCHDB_DEFAULT_DB_NAME;
/**
* @return string
*/
public function getDatabase(): string
{
return $this->database;
}
/**
* @param string $database
* @return Config
*/
public function setDatabase(string $database): Config
{
/** @see https://docs.couchdb.org/en/latest/api/database/common.html#put--db */
if(\preg_match('#^[a-z][a-z0-9_\-+\$()/]+$#', $database)){
$this->database = $database;
return $this;
}
throw new PhpfastcacheInvalidArgumentException(sprintf(
"Error: illegal_database_name Name: '%s'. Only lowercase characters (a-z), digits (0-9), and any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter.",
$database
));
}
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return self
*/
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return self
*/
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
/**
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* @param string $username
* @return self
*/
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
/**
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @param string $password
* @return self
*/
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @return bool
*/
public function isSsl(): bool
{
return $this->ssl;
}
/**
* @param bool $ssl
* @return self
*/
public function setSsl(bool $ssl): self
{
$this->ssl = $ssl;
return $this;
}
/**
* @return int
*/
public function getTimeout(): int
{
return $this->timeout;
}
/**
* @param int $timeout
* @return self
*/
public function setTimeout(int $timeout): self
{
$this->timeout = $timeout;
return $this;
}
}

View File

@ -0,0 +1,298 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchdb;
use Doctrine\CouchDB\{CouchDBClient, CouchDBException, HTTP\HTTPException};
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property CouchdbClient $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
public const COUCHDB_DEFAULT_DB_NAME = 'phpfastcache'; // Public because used in config
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return class_exists(CouchDBClient::class);
}
/**
* @return string
*/
public function getHelp(): string
{
return <<<HELP
<p>
To install the Couchdb HTTP client library via Composer:
<code>composer require "doctrine/couchdb" "@dev"</code>
</p>
HELP;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$info = $this->instance->getDatabaseInfo();
return (new DriverStatistic())
->setSize($info['sizes']['active'] ?? 0)
->setRawData($info)
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo('Couchdb version ' . $this->instance->getVersion() . "\n For more information see RawData.");
}
/**
* @return bool
* @throws PhpfastcacheLogicException
*/
protected function driverConnect(): bool
{
if ($this->instance instanceof CouchDBClient) {
throw new PhpfastcacheLogicException('Already connected to Couchdb server');
}
$clientConfig = $this->getConfig();
$url = ($clientConfig->isSsl() ? 'https://' : 'http://');
if ($clientConfig->getUsername()) {
$url .= $clientConfig->getUsername();
if ($clientConfig->getPassword()) {
$url .= ":{$clientConfig->getPassword()}";
}
$url .= '@';
}
$url .= $clientConfig->getHost();
$url .= ":{$clientConfig->getPort()}";
$url .= '/' . \urlencode($this->getDatabaseName());
$this->instance = CouchDBClient::create(
[
'dbname' => $this->getDatabaseName(),
'url' => $url,
'timeout' => $clientConfig->getTimeout(),
]
);
$this->createDatabase();
return true;
}
/**
* @return string
*/
protected function getDatabaseName(): string
{
return $this->getConfig()->getDatabase() ?: self::COUCHDB_DEFAULT_DB_NAME;
}
/**
* @return void
*/
protected function createDatabase()
{
try{
$this->instance->getDatabaseInfo($this->getDatabaseName());
} catch(HTTPException $e){
$this->instance->createDatabase($this->getDatabaseName());
}
}
protected function getCouchDbItemKey(CacheItemInterface $item)
{
return 'pfc_' . $item->getEncodedKey();
}
/**
* @param CacheItemInterface $item
* @return null|array
* @throws PhpfastcacheDriverException
*/
protected function driverRead(CacheItemInterface $item)
{
try {
$response = $this->instance->findDocument($this->getCouchDbItemKey($item));
} catch (CouchDBException $e) {
throw new PhpfastcacheDriverException('Got error while trying to get a document: ' . $e->getMessage(), 0, $e);
}
if ($response->status === 404 || empty($response->body[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX])) {
return null;
}
if ($response->status === 200) {
return $this->decode($response->body);
}
throw new PhpfastcacheDriverException('Got unexpected HTTP status: ' . $response->status);
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheDriverException
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$this->instance->putDocument(
$this->encodeDocument($this->driverPreWrap($item)),
$this->getCouchDbItemKey($item),
$this->getLatestDocumentRevision($this->getCouchDbItemKey($item))
);
} catch (CouchDBException $e) {
throw new PhpfastcacheDriverException('Got error while trying to upsert a document: ' . $e->getMessage(), 0, $e);
}
return true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return string|null
*/
protected function getLatestDocumentRevision($docId)
{
$path = '/' . \urlencode($this->getDatabaseName()) . '/' . urlencode($docId);
$response = $this->instance->getHttpClient()->request(
'HEAD',
$path,
null,
false
);
if (!empty($response->headers['etag'])) {
return trim($response->headers['etag'], " '\"\t\n\r\0\x0B");
}
return null;
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheDriverException
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$this->instance->deleteDocument($this->getCouchDbItemKey($item), $this->getLatestDocumentRevision($this->getCouchDbItemKey($item)));
} catch (CouchDBException $e) {
throw new PhpfastcacheDriverException('Got error while trying to delete a document: ' . $e->getMessage(), 0, $e);
}
return true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
* @throws PhpfastcacheDriverException
*/
protected function driverClear(): bool
{
try {
$this->instance->deleteDatabase($this->getDatabaseName());
$this->createDatabase();
} catch (CouchDBException $e) {
throw new PhpfastcacheDriverException('Got error while trying to delete and recreate the database: ' . $e->getMessage(), 0, $e);
}
return true;
}
/**
* @param array $data
* @return array
*/
protected function encodeDocument(array $data): array
{
$data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX] = $this->encode($data[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX]);
return $data;
}
/**
* Specific document decoder for Couchdb
* since we dont store encoded version
* for performance purposes
*
* @param $value
* @return mixed
* @throws \Exception
*/
protected function decode($value)
{
$value[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX] = \unserialize($value[ExtendedCacheItemPoolInterface::DRIVER_DATA_WRAPPER_INDEX], ['allowed_classes' => true]);
$value[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX] = new \DateTime(
$value[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX]['date'],
new \DateTimeZone($value[ExtendedCacheItemPoolInterface::DRIVER_EDATE_WRAPPER_INDEX]['timezone'])
);
if(isset($value[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX])){
$value[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX] = new \DateTime(
$value[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX]['date'],
new \DateTimeZone($value[ExtendedCacheItemPoolInterface::DRIVER_CDATE_WRAPPER_INDEX]['timezone'])
);
}
if(isset($value[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX])){
$value[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX] = new \DateTime(
$value[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX]['date'],
new \DateTimeZone($value[ExtendedCacheItemPoolInterface::DRIVER_MDATE_WRAPPER_INDEX]['timezone'])
);
}
return $value;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Couchdb;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Core\Item\ItemBaseTrait;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Couchdb\Driver as CouchdbDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Couchdb
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(CouchdbDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof CouchdbDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devfalse;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,126 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devfalse;
use DateTime;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return true;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stat = new DriverStatistic();
$stat->setInfo('[Devfalse] A void info string')
->setSize(0)
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData(false);
return $stat;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return array
*/
protected function driverRead(CacheItemInterface $item): array
{
return [
self::DRIVER_DATA_WRAPPER_INDEX => false,
self::DRIVER_TAGS_WRAPPER_INDEX => [],
self::DRIVER_EDATE_WRAPPER_INDEX => new DateTime(),
];
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
return true;
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devfalse;
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
use Phpfastcache\Core\Item\ItemBaseTrait;
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Devfalse\Driver as DevfalseDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Devfalse
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(DevfalseDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof DevfalseDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devnull;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,121 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devnull;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return true;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stat = new DriverStatistic();
$stat->setInfo('[Devnull] A void info string')
->setSize(0)
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData(null);
return $stat;
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return null
*/
protected function driverRead(CacheItemInterface $item)
{
return null;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
return true;
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devnull;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Devnull\Driver as DevnullDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Devnull
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(DevnullDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof DevnullDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devtrue;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,126 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devtrue;
use DateTime;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return true;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stat = new DriverStatistic();
$stat->setInfo('[Devtrue] A void info string')
->setSize(0)
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData(true);
return $stat;
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return false;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return array
*/
protected function driverRead(CacheItemInterface $item): array
{
return [
self::DRIVER_DATA_WRAPPER_INDEX => true,
self::DRIVER_TAGS_WRAPPER_INDEX => [],
self::DRIVER_EDATE_WRAPPER_INDEX => new DateTime(),
];
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return false;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
return false;
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverConnect(): bool
{
return false;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Devtrue;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Devtrue\Driver as DevtrueDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Devtrue
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(DevtrueDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof DevtrueDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Files;
use Phpfastcache\Config\{ConfigurationOption, IOConfigurationOptionTrait};
class Config extends ConfigurationOption
{
use IOConfigurationOptionTrait;
}

View File

@ -0,0 +1,150 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Files;
use Exception;
use FilesystemIterator;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface, IO\IOHelperTrait};
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException, PhpfastcacheIOException};
use Phpfastcache\Util\Directory;
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*
* Important NOTE:
* We are using getKey instead of getEncodedKey since this backend create filename that are
* managed by defaultFileNameHashFunction and not defaultKeyHashFunction
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use IOHelperTrait;
use DriverBaseTrait {
DriverBaseTrait::__construct as private __parentConstruct;
}
/**
* Driver constructor.
* @param Config $config
* @param string $instanceId
*/
public function __construct(Config $config, string $instanceId)
{
$this->__parentConstruct($config, $instanceId);
}
/**
* @return bool
*/
public function driverCheck(): bool
{
return is_writable($this->getPath()) || mkdir($concurrentDirectory = $this->getPath(), $this->getDefaultChmod(), true) || is_dir($concurrentDirectory);
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$file_path = $this->getFilePath($item->getKey(), true);
try{
$content = $this->readFile($file_path);
}catch (PhpfastcacheIOException $e){
return null;
}
return $this->decode($content);
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$file_path = $this->getFilePath($item->getKey());
$data = $this->encode($this->driverPreWrap($item));
/**
* Force write
*/
try {
return $this->writefile($file_path, $data, $this->getConfig()->isSecureFileManipulation());
} catch (Exception $e) {
return false;
}
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$file_path = $this->getFilePath($item->getKey(), true);
if (\file_exists($file_path) && @\unlink($file_path)) {
\clearstatcache(true, $file_path);
$dir = \dirname($file_path);
if (!(new FilesystemIterator($dir))->valid()) {
\rmdir($dir);
}
return true;
}
return false;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
* @throws \Phpfastcache\Exceptions\PhpfastcacheIOException
*/
protected function driverClear(): bool
{
return Directory::rrmdir($this->getPath(true));
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Files;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Files\Driver as FilesDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Files
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(FilesDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof FilesDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Leveldb;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
/**
* @var string
*/
protected $htaccess = true;
/**
* @return string
*/
public function getHtaccess(): string
{
return $this->htaccess;
}
/**
* @param string $htaccess
* @return self
*/
public function setHtaccess(string $htaccess): self
{
$this->htaccess = $htaccess;
return $this;
}
}

View File

@ -0,0 +1,145 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Leveldb;
use LevelDB as LeveldbClient;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface, IO\IOHelperTrait};
use Phpfastcache\Exceptions\{PhpfastcacheCoreException, PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property LeveldbClient $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
use IOHelperTrait;
protected const LEVELDB_FILENAME = '.database';
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('Leveldb');
}
/**
* Close connection on destruct
*/
public function __destruct()
{
if ($this->instance instanceof LeveldbClient) {
$this->instance->close();
$this->instance = null;
}
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$val = $this->instance->get($item->getKey());
if ($val == false) {
return null;
}
return $this->decode($val);
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)$this->instance->set($item->getKey(), $this->encode($this->driverPreWrap($item)));
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return $this->instance->delete($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
if ($this->instance instanceof LeveldbClient) {
$this->instance->close();
$this->instance = null;
}
$result = (bool)LeveldbClient::destroy($this->getLeveldbFile());
$this->driverConnect();
return $result;
}
/**
* @return string
* @throws PhpfastcacheCoreException
*/
public function getLeveldbFile(): string
{
return $this->getPath() . '/' . self::LEVELDB_FILENAME;
}
/**
* @return bool
* @throws PhpfastcacheLogicException
*/
protected function driverConnect(): bool
{
if ($this->instance instanceof LeveldbClient) {
throw new PhpfastcacheLogicException('Already connected to Leveldb database');
}
$this->instance = $this->instance ?: new LeveldbClient($this->getLeveldbFile());
return true;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Leveldb;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Leveldb\Driver as LeveldbDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Leveldb
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(LeveldbDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof LeveldbDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,164 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memcache;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
class Config extends ConfigurationOption
{
/**
* @var array
*
* Multiple server can be added this way:
* $cfg->setServers([
* [
* 'host' => '127.0.0.1',
* 'port' => 11211,
* 'saslUser' => false,
* 'saslPassword' => false,
* ]
* ]);
*/
protected $servers = [];
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 11211;
/**
* @var string
*/
protected $saslUser = '';
/**
* @var string
*/
protected $saslPassword = '';
/**
* @return bool
*/
public function getSaslUser(): string
{
return $this->saslUser;
}
/**
* @param string $saslUser
* @return self
*/
public function setSaslUser(string $saslUser): self
{
$this->saslUser = $saslUser;
return $this;
}
/**
* @return string
*/
public function getSaslPassword(): string
{
return $this->saslPassword;
}
/**
* @param string $saslPassword
* @return self
*/
public function setSaslPassword(string $saslPassword): self
{
$this->saslPassword = $saslPassword;
return $this;
}
/**
* @return array
*/
public function getServers(): array
{
return $this->servers;
}
/**
* @param array $servers
* @return self
* @throws PhpfastcacheInvalidConfigurationException
*/
public function setServers(array $servers): self
{
foreach ($servers as $server) {
if ($diff = array_diff(['host', 'port', 'saslUser', 'saslPassword'], array_keys($server))) {
throw new PhpfastcacheInvalidConfigurationException('Missing keys for memcached server: ' . implode(', ', $diff));
}
if ($diff = array_diff(array_keys($server), ['host', 'port', 'saslUser', 'saslPassword'])) {
throw new PhpfastcacheInvalidConfigurationException('Unknown keys for memcached server: ' . implode(', ', $diff));
}
if (!is_string($server['host'])) {
throw new PhpfastcacheInvalidConfigurationException('Host must be a valid string in "$server" configuration array');
}
if (!is_int($server['port'])) {
throw new PhpfastcacheInvalidConfigurationException('Port must be a valid integer in "$server" configuration array');
}
}
$this->servers = $servers;
return $this;
}
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return self
*/
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return self
*/
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
}

View File

@ -0,0 +1,213 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memcache;
use DateTime;
use Exception;
use Memcache as MemcacheSoftware;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException};
use Phpfastcache\Util\{MemcacheDriverCollisionDetectorTrait};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property MemcacheSoftware $instance
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait {
__construct as protected __parentConstruct;
}
use MemcacheDriverCollisionDetectorTrait;
/**
* @var int
*/
protected $memcacheFlags = 0;
/**
* Driver constructor.
* @param ConfigurationOption $config
* @param string $instanceId
* @throws PhpfastcacheDriverException
*/
public function __construct(ConfigurationOption $config, string $instanceId)
{
self::checkCollision('Memcache');
$this->__parentConstruct($config, $instanceId);
}
/**
* @return bool
*/
public function driverCheck(): bool
{
return class_exists('Memcache');
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stats = (array)$this->instance->getstats();
$stats['uptime'] = (isset($stats['uptime']) ? $stats['uptime'] : 0);
$stats['version'] = (isset($stats['version']) ? $stats['version'] : 'UnknownVersion');
$stats['bytes'] = (isset($stats['bytes']) ? $stats['version'] : 0);
$date = (new DateTime())->setTimestamp(time() - $stats['uptime']);
return (new DriverStatistic())
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo(sprintf("The memcache daemon v%s is up since %s.\n For more information see RawData.", $stats['version'], $date->format(DATE_RFC2822)))
->setRawData($stats)
->setSize((int)$stats['bytes']);
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
$this->instance = new MemcacheSoftware();
$servers = $this->getConfig()->getServers();
if (count($servers) < 1) {
$servers = [
[
'host' => $this->getConfig()->getHost(),
'path' => $this->getConfig()->getPath(),
'port' => $this->getConfig()->getPort(),
'saslUser' => $this->getConfig()->getSaslUser() ?: false,
'saslPassword' => $this->getConfig()->getSaslPassword() ?: false,
],
];
}
foreach ($servers as $server) {
try {
/**
* If path is provided we consider it as an UNIX Socket
*/
if (!empty($server['path']) && !$this->instance->addServer($server['path'], 0)) {
$this->fallback = true;
} else {
if (!empty($server['host']) && !$this->instance->addServer($server['host'], $server['port'])) {
$this->fallback = true;
}
}
if (!empty($server['saslUser']) && !empty($server['saslPassword'])) {
throw new PhpfastcacheDriverException('Unlike Memcached, Memcache does not support SASL authentication');
}
} catch (Exception $e) {
$this->fallback = true;
}
/**
* Since Memcached does not throw
* any error if not connected ...
*/
if (!$this->instance->getServerStatus(
!empty($server['path']) ? $server['path'] : $server['host'],
!empty($server['port']) ? $server['port'] : 0
)) {
throw new PhpfastcacheDriverException('Memcache seems to not be connected');
}
}
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$val = $this->instance->get($item->getKey());
if ($val === false) {
return null;
}
return $val;
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$ttl = $item->getExpirationDate()->getTimestamp() - time();
// Memcache will only allow a expiration timer less than 2592000 seconds,
// otherwise, it will assume you're giving it a UNIX timestamp.
if ($ttl > 2592000) {
$ttl = time() + $ttl;
}
return $this->instance->set($item->getKey(), $this->driverPreWrap($item), $this->memcacheFlags, $ttl);
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return $this->instance->delete($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
return $this->instance->flush();
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memcache;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Memcache\Driver as MemcacheDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Memcache
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(MemcacheDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof MemcacheDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memcached;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
class Config extends ConfigurationOption
{
/**
* @var array
*
* Multiple server can be added this way:
* $cfg->setServers([
* [
* 'host' => '127.0.0.1',
* 'port' => 11211,
* 'saslUser' => false,
* 'saslPassword' => false,
* ]
* ]);
*/
protected $servers = [];
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 11211;
/**
* @var string
*/
protected $saslUser = '';
/**
* @var string
*/
protected $saslPassword = '';
/**
* @var string
*/
protected $optPrefix = '';
/**
* @return string
*/
public function getSaslUser(): string
{
return $this->saslUser;
}
/**
* @param string $saslUser
* @return self
*/
public function setSaslUser(string $saslUser): self
{
$this->saslUser = $saslUser;
return $this;
}
/**
* @return string
*/
public function getSaslPassword(): string
{
return $this->saslPassword;
}
/**
* @param string $saslPassword
* @return self
*/
public function setSaslPassword(string $saslPassword): self
{
$this->saslPassword = $saslPassword;
return $this;
}
/**
* @return array
*/
public function getServers(): array
{
return $this->servers;
}
/**
* @param array $servers
* @return self
* @throws PhpfastcacheInvalidConfigurationException
*/
public function setServers(array $servers): self
{
foreach ($servers as $server) {
if ($diff = array_diff(['host', 'port', 'saslUser', 'saslPassword'], array_keys($server))) {
throw new PhpfastcacheInvalidConfigurationException('Missing keys for memcached server: ' . implode(', ', $diff));
}
if ($diff = array_diff(array_keys($server), ['host', 'port', 'saslUser', 'saslPassword'])) {
throw new PhpfastcacheInvalidConfigurationException('Unknown keys for memcached server: ' . implode(', ', $diff));
}
if (!is_string($server['host'])) {
throw new PhpfastcacheInvalidConfigurationException('Host must be a valid string in "$server" configuration array');
}
if (!is_int($server['port'])) {
throw new PhpfastcacheInvalidConfigurationException('Port must be a valid integer in "$server" configuration array');
}
}
$this->servers = $servers;
return $this;
}
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return self
*/
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return Config
*/
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
/**
* @return string
* @since 8.0.2
*/
public function getOptPrefix(): string
{
return $this->optPrefix;
}
/**
* @param string $optPrefix
* @return Config
* @since 8.0.2
*/
public function setOptPrefix(string $optPrefix): Config
{
$this->optPrefix = trim($optPrefix);
return $this;
}
}

View File

@ -0,0 +1,213 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memcached;
use DateTime;
use Exception;
use Memcached as MemcachedSoftware;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException};
use Phpfastcache\Util\{MemcacheDriverCollisionDetectorTrait};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property MemcachedSoftware $instance
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait {
__construct as protected __parentConstruct;
}
use MemcacheDriverCollisionDetectorTrait;
/**
* Driver constructor.
* @param ConfigurationOption $config
* @param string $instanceId
* @throws PhpfastcacheDriverException
*/
public function __construct(ConfigurationOption $config, string $instanceId)
{
self::checkCollision('Memcached');
$this->__parentConstruct($config, $instanceId);
}
/**
* @return bool
*/
public function driverCheck(): bool
{
return class_exists('Memcached');
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stats = current($this->instance->getStats());
$stats['uptime'] = $stats['uptime'] ?? 0;
$stats['bytes'] = $stats['bytes'] ?? 0;
$stats['version'] = $stats['version'] ?? $this->instance->getVersion();
$date = (new DateTime())->setTimestamp(time() - $stats['uptime']);
return (new DriverStatistic())
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo(sprintf("The memcache daemon v%s is up since %s.\n For more information see RawData.", $stats['version'], $date->format(DATE_RFC2822)))
->setRawData($stats)
->setSize((int)$stats['bytes']);
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
$this->instance = new MemcachedSoftware();
$optPrefix = $this->getConfig()->getOptPrefix();
$this->instance->setOption(MemcachedSoftware::OPT_BINARY_PROTOCOL, true);
if ($optPrefix) {
$this->instance->setOption(MemcachedSoftware::OPT_PREFIX_KEY, $optPrefix);
}
$servers = $this->getConfig()->getServers();
if (count($servers) < 1) {
$servers = [
[
'host' => $this->getConfig()->getHost(),
'path' => $this->getConfig()->getPath(),
'port' => $this->getConfig()->getPort(),
'saslUser' => $this->getConfig()->getSaslUser() ?: false,
'saslPassword' => $this->getConfig()->getSaslPassword() ?: false,
],
];
}
foreach ($servers as $server) {
try {
/**
* If path is provided we consider it as an UNIX Socket
*/
if (!empty($server['path']) && !$this->instance->addServer($server['path'], 0)) {
$this->fallback = true;
} else {
if (!empty($server['host']) && !$this->instance->addServer($server['host'], $server['port'])) {
$this->fallback = true;
}
}
if (!empty($server['saslUser']) && !empty($server['saslPassword'])) {
$this->instance->setSaslAuthData($server['saslUser'], $server['saslPassword']);
}
} catch (Exception $e) {
$this->fallback = true;
}
}
/**
* Since Memcached does not throw
* any error if not connected ...
*/
$version = $this->instance->getVersion();
if (!$version || $this->instance->getResultCode() !== MemcachedSoftware::RES_SUCCESS) {
throw new PhpfastcacheDriverException('Memcached seems to not be connected');
}
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$val = $this->instance->get($item->getKey());
if ($val === false) {
return null;
}
return $val;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$ttl = $item->getExpirationDate()->getTimestamp() - time();
// Memcache will only allow a expiration timer less than 2592000 seconds,
// otherwise, it will assume you're giving it a UNIX timestamp.
if ($ttl > 2592000) {
$ttl = time() + $ttl;
}
return $this->instance->set($item->getKey(), $this->driverPreWrap($item), $ttl);
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return $this->instance->delete($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
return $this->instance->flush();
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memcached;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Memcached\Driver as MemcachedDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Memcached
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(MemcachedDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof MemcachedDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memstatic;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,138 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memstatic;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface
{
use DriverBaseTrait;
/**
* @var array
*/
protected $staticStack = [];
/**
* @return bool
*/
public function driverCheck(): bool
{
return true;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stat = new DriverStatistic();
$stat->setInfo('[Memstatic] A memory static driver')
->setSize(mb_strlen(serialize($this->staticStack)))
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData($this->staticStack);
return $stat;
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$key = md5($item->getKey());
if (isset($this->staticStack[$key])) {
return $this->staticStack[$key];
}
return null;
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$this->staticStack[md5($item->getKey())] = $this->driverPreWrap($item);
return true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$key = md5($item->getKey());
if (isset($this->staticStack[$key])) {
unset($this->staticStack[$key]);
return true;
}
return false;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
unset($this->staticStack);
$this->staticStack = [];
return true;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Memstatic;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Memstatic\Driver as MemstaticDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Devnull
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(MemstaticDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof MemstaticDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,276 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Mongodb;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 27017;
/**
* @var int
*/
protected $timeout = 3;
/**
* @var string
*/
protected $username = '';
/**
* @var string
*/
protected $password = '';
/**
* @var array
*/
protected $servers = [];
/**
* @var string
*/
protected $collectionName = 'phpfastcache';
/**
* @var string
*/
protected $databaseName = Driver::MONGODB_DEFAULT_DB_NAME;
/**
* @var array
*/
protected $options = [];
/**
* @var array
*/
protected $driverOptions = [];
/**
* @var string
*/
protected $protocol = 'mongodb';
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return self
*/
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return self
*/
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
/**
* @return int
*/
public function getTimeout(): int
{
return $this->timeout;
}
/**
* @param int $timeout
* @return self
*/
public function setTimeout(int $timeout): self
{
$this->timeout = $timeout;
return $this;
}
/**
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* @param string $username
* @return self
*/
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
/**
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @param string $password
* @return self
*/
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @return array
*/
public function getServers(): array
{
return $this->servers;
}
/**
* @param array $servers
* @return self
*/
public function setServers(array $servers): self
{
$this->servers = $servers;
return $this;
}
/**
* @return string
*/
public function getCollectionName(): string
{
return $this->collectionName;
}
/**
* @param string $collectionName
* @return self
*/
public function setCollectionName(string $collectionName): self
{
$this->collectionName = $collectionName;
return $this;
}
/**
* @return string
*/
public function getDatabaseName(): string
{
return $this->databaseName;
}
/**
* @param string $databaseName
* @return self
*/
public function setDatabaseName(string $databaseName): self
{
$this->databaseName = $databaseName;
return $this;
}
/**
* @return array
*/
public function getOptions(): array
{
return $this->options;
}
/**
* @see https://docs.mongodb.com/manual/reference/connection-string/#connections-connection-options
* @param array $options
* @return Config
*/
public function setOptions(array $options): self
{
$this->options = $options;
return $this;
}
/**
* @return array
*/
public function getDriverOptions(): array
{
return $this->driverOptions;
}
/**
* @param array $driverOptions
* @return self
*/
public function setDriverOptions(array $driverOptions): self
{
$this->driverOptions = $driverOptions;
return $this;
}
/**
* @return string
*/
public function getProtocol(): string
{
return $this->protocol;
}
/**
* @param string $protocol
* @return self
*/
public function setProtocol(string $protocol): self
{
$this->protocol = $protocol;
return $this;
}
}

View File

@ -0,0 +1,366 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
* @author Fabio Covolo Mazzo (fabiocmazzo) <fabiomazzo@gmail.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Mongodb;
use LogicException;
use MongoClient;
use MongoDB\{BSON\Binary, BSON\UTCDateTime, Client, Collection, Database, DeleteResult, Driver\Command, Driver\Exception\Exception as MongoDBException, Driver\Manager};
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Client $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
public const MONGODB_DEFAULT_DB_NAME = 'phpfastcache'; // Public because used in config
use DriverBaseTrait;
/**
* @var Collection
*/
public $collection;
/**
* @var Database
*/
public $database;
/**
* @return bool
*/
public function driverCheck(): bool
{
$mongoExtensionExists = class_exists(Manager::class);
if (!$mongoExtensionExists && class_exists(MongoClient::class)) {
trigger_error(
'This driver is used to support the pecl MongoDb extension with mongo-php-library.
For MongoDb with Mongo PECL support use Mongo Driver.',
E_USER_ERROR
);
}
return $mongoExtensionExists && class_exists(Collection::class);
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$serverStats = $this->instance->getManager()->executeCommand(
$this->getConfig()->getDatabaseName(),
new Command(
[
'serverStatus' => 1,
'recordStats' => 0,
'repl' => 0,
'metrics' => 0,
]
)
)->toArray()[0];
$collectionStats = $this->instance->getManager()->executeCommand(
$this->getConfig()->getDatabaseName(),
new Command(
[
'collStats' => $this->getConfig()->getCollectionName(),
'verbose' => true,
]
)
)->toArray()[0];
$array_filter_recursive = static function ($array, callable $callback = null) use (&$array_filter_recursive) {
$array = $callback($array);
if (\is_object($array) || \is_array($array)) {
foreach ($array as &$value) {
$value = $array_filter_recursive($value, $callback);
}
}
return $array;
};
$callback = static function ($item) {
/**
* Remove unserializable properties
*/
if ($item instanceof UTCDateTime) {
return (string)$item;
}
return $item;
};
$serverStats = $array_filter_recursive($serverStats, $callback);
$collectionStats = $array_filter_recursive($collectionStats, $callback);
$stats = (new DriverStatistic())
->setInfo(
'MongoDB version ' . $serverStats->version . ', Uptime (in days): ' . round(
$serverStats->uptime / 86400,
1
) . "\n For more information see RawData."
)
->setSize($collectionStats->size)
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData(
[
'serverStatus' => $serverStats,
'collStats' => $collectionStats,
]
);
return $stats;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$document = $this->getCollection()->findOne(['_id' => $this->getMongoDbItemKey($item)]);
if ($document) {
$return = [
self::DRIVER_DATA_WRAPPER_INDEX => $this->decode($document[self::DRIVER_DATA_WRAPPER_INDEX]->getData()),
self::DRIVER_TAGS_WRAPPER_INDEX => $document[self::DRIVER_TAGS_WRAPPER_INDEX]->jsonSerialize(),
self::DRIVER_EDATE_WRAPPER_INDEX => $document[self::DRIVER_EDATE_WRAPPER_INDEX]->toDateTime(),
];
if (!empty($this->getConfig()->isItemDetailedDate())) {
$return += [
self::DRIVER_MDATE_WRAPPER_INDEX => $document[self::DRIVER_MDATE_WRAPPER_INDEX]->toDateTime(),
self::DRIVER_CDATE_WRAPPER_INDEX => $document[self::DRIVER_CDATE_WRAPPER_INDEX]->toDateTime(),
];
}
return $return;
}
return null;
}
/**
* @return Collection
*/
protected function getCollection(): Collection
{
return $this->collection;
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
* @throws PhpfastcacheDriverException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$set = [
self::DRIVER_KEY_WRAPPER_INDEX => $item->getKey(),
self::DRIVER_DATA_WRAPPER_INDEX => new Binary($this->encode($item->get()), Binary::TYPE_GENERIC),
self::DRIVER_TAGS_WRAPPER_INDEX => $item->getTags(),
self::DRIVER_EDATE_WRAPPER_INDEX => new UTCDateTime($item->getExpirationDate()),
];
if (!empty($this->getConfig()->isItemDetailedDate())) {
$set += [
self::DRIVER_MDATE_WRAPPER_INDEX => new UTCDateTime($item->getModificationDate()),
self::DRIVER_CDATE_WRAPPER_INDEX => new UTCDateTime($item->getCreationDate()),
];
}
$result = (array)$this->getCollection()->updateOne(
['_id' => $this->getMongoDbItemKey($item)],
[
'$set' => $set,
],
['upsert' => true, 'multiple' => false]
);
} catch (MongoDBException $e) {
throw new PhpfastcacheDriverException('Got an exception while trying to write data to MongoDB server: ' . $e->getMessage(), 0, $e);
}
return isset($result['ok']) ? $result['ok'] == 1 : true;
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
/**
* @var DeleteResult $deletionResult
*/
$deletionResult = $this->getCollection()->deleteOne(['_id' => $this->getMongoDbItemKey($item)]);
return $deletionResult->isAcknowledged();
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
try {
return $this->collection->deleteMany([])->isAcknowledged();
} catch (MongoDBException $e) {
throw new PhpfastcacheDriverException('Got error while trying to empty the collection: ' . $e->getMessage(), 0, $e);
}
}
/**
* @return bool
* @throws MongodbException
* @throws LogicException
*/
protected function driverConnect(): bool
{
if ($this->instance instanceof Client) {
throw new LogicException('Already connected to Mongodb server');
}
$timeout = $this->getConfig()->getTimeout() * 1000;
$collectionName = $this->getConfig()->getCollectionName();
$databaseName = $this->getConfig()->getDatabaseName();
$driverOptions = $this->getConfig()->getDriverOptions();
$this->instance = $this->instance ?: new Client($this->buildConnectionURI($databaseName), ['connectTimeoutMS' => $timeout], $driverOptions);
$this->database = $this->database ?: $this->instance->selectDatabase($databaseName);
if (!$this->collectionExists($collectionName)) {
$this->database->createCollection($collectionName);
$this->database->selectCollection($collectionName)
->createIndex(
[self::DRIVER_KEY_WRAPPER_INDEX => 1],
['unique' => true, 'name' => 'unique_key_index']
);
$this->database->selectCollection($collectionName)
->createIndex(
[self::DRIVER_EDATE_WRAPPER_INDEX => 1],
['expireAfterSeconds' => 0, 'name' => 'auto_expire_index']
);
}
$this->collection = $this->database->selectCollection($collectionName);
return true;
}
/**
* Builds the connection URI from the given parameters.
*
* @param string $databaseName
* @return string The connection URI.
*/
protected function buildConnectionURI(string $databaseName): string
{
$databaseName = \urlencode($databaseName);
$servers = $this->getConfig()->getServers();
$options = $this->getConfig()->getOptions();
$protocol = $this->getConfig()->getProtocol();
$host = $this->getConfig()->getHost();
$port = $this->getConfig()->getPort();
$username = $this->getConfig()->getUsername();
$password = $this->getConfig()->getPassword();
if (count($servers) > 0) {
$host = array_reduce(
$servers,
static function ($carry, $data) {
$carry .= ($carry === '' ? '' : ',') . $data['host'] . ':' . $data['port'];
return $carry;
},
''
);
$port = false;
}
return implode(
'',
[
"{$protocol}://",
$username ?: '',
$password ? ":{$password}" : '',
$username ? '@' : '',
$host,
$port !== 27017 && $port !== false ? ":{$port}" : '',
$databaseName ? "/{$databaseName}" : '',
count($options) > 0 ? '?' . http_build_query($options) : '',
]
);
}
protected function getMongoDbItemKey(CacheItemInterface $item)
{
return 'pfc_' . $item->getEncodedKey();
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* Checks if a collection name exists on the Mongo database.
*
* @param string $collectionName The collection name to check.
*
* @return bool True if the collection exists, false if not.
*/
protected function collectionExists($collectionName): bool
{
foreach ($this->database->listCollections() as $collection) {
if ($collection->getName() === $collectionName) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Mongodb;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Mongodb\Driver as MongodbDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Mongodb
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(MongodbDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof MongodbDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,252 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Predis;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Exceptions\PhpfastcacheInvalidConfigurationException;
use Predis\Client;
class Config extends ConfigurationOption
{
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 6379;
/**
* @var string
*/
protected $password = '';
/**
* @var int
*/
protected $database = 0;
/**
* @var Client
*/
protected $predisClient;
/**
* @var string
*/
protected $optPrefix = '';
/**
* @var int
*/
protected $timeout = 5;
/**
* @var bool
*/
protected $persistent = false;
/**
* @var string
*/
protected $scheme = 'unix';
/**
* @return array
*/
public function getPredisConfigArray(): array
{
return [
'host' => $this->getHost(),
'port' => $this->getPort(),
'password' => $this->getPassword() ?: null,
'database' => $this->getDatabase(),
'timeout' => $this->getTimeout(),
];
}
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return Config
*/
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return Config
*/
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
/**
* @return null
*/
public function getPassword()
{
return $this->password;
}
/**
* @param null $password
* @return self
*/
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @return int
*/
public function getDatabase(): int
{
return $this->database;
}
/**
* @param int $database
* @return Config
*/
public function setDatabase(int $database): self
{
$this->database = $database;
return $this;
}
/**
* @return int
*/
public function getTimeout(): int
{
return $this->timeout;
}
/**
* @param int $timeout
* @return self
*/
public function setTimeout(int $timeout): self
{
$this->timeout = $timeout;
return $this;
}
/**
* @return Client|null
*/
public function getPredisClient()
{
return $this->predisClient;
}
/**
* @param Client $predisClient |null
* @return Config
*/
public function setPredisClient(Client $predisClient = null): Config
{
$this->predisClient = $predisClient;
return $this;
}
/**
* @return string
* @since 7.0.2
*/
public function getOptPrefix(): string
{
return $this->optPrefix;
}
/**
* @param string $optPrefix
* @return Config
* @since 7.0.2
*/
public function setOptPrefix(string $optPrefix): Config
{
$this->optPrefix = trim($optPrefix);
return $this;
}
/**
* @return bool
*/
public function isPersistent(): bool
{
return $this->persistent;
}
/**
* @param bool $persistent
* @return Config
*/
public function setPersistent(bool $persistent): Config
{
$this->persistent = $persistent;
return $this;
}
/**
* @return string
*/
public function getScheme(): string
{
return $this->scheme;
}
/**
* @param string $scheme
* @return Config
* @throws PhpfastcacheInvalidConfigurationException
*/
public function setScheme(string $scheme): Config
{
if (!in_array($scheme, ['unix', 'tls'], true)) {
throw new PhpfastcacheInvalidConfigurationException('Invalid scheme: ' . $scheme);
}
$this->scheme = $scheme;
return $this;
}
}

View File

@ -0,0 +1,214 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Predis;
use DateTime;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Predis\Client as PredisClient;
use Predis\Connection\ConnectionException as PredisConnectionException;
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property PredisClient $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
if (extension_loaded('Redis')) {
trigger_error('The native Redis extension is installed, you should use Redis instead of Predis to increase performances', E_USER_NOTICE);
}
return class_exists('Predis\Client');
}
/**
* @return string
*/
public function getHelp(): string
{
return <<<HELP
<p>
To install the Predis library via Composer:
<code>composer require "predis/predis" "~1.1.0"</code>
</p>
HELP;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$info = $this->instance->info();
$size = (isset($info['Memory']['used_memory']) ? $info['Memory']['used_memory'] : 0);
$version = (isset($info['Server']['redis_version']) ? $info['Server']['redis_version'] : 0);
$date = (isset($info['Server']['uptime_in_seconds']) ? (new DateTime())->setTimestamp(time() - $info['Server']['uptime_in_seconds']) : 'unknown date');
return (new DriverStatistic())
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData($info)
->setSize((int)$size)
->setInfo(
sprintf(
"The Redis daemon v%s is up since %s.\n For more information see RawData. \n Driver size includes the memory allocation size.",
$version,
$date->format(DATE_RFC2822)
)
);
}
/**
* @return bool
* @throws PhpfastcacheDriverException
* @throws PhpfastcacheLogicException
*/
protected function driverConnect(): bool
{
if ($this->instance instanceof PredisClient) {
throw new PhpfastcacheLogicException('Already connected to Predis server');
}
/**
* In case of an user-provided
* Predis client just return here
*/
if ($this->getConfig()->getPredisClient() instanceof PredisClient) {
$this->instance = $this->getConfig()->getPredisClient();
if (!$this->instance->isConnected()) {
$this->instance->connect();
}
return true;
}
$options = [];
if ($this->getConfig()->getOptPrefix()) {
$options['prefix'] = $this->getConfig()->getOptPrefix();
}
if (!empty($this->getConfig()->getPath())) {
$this->instance = new PredisClient(
[
'scheme' => $this->getConfig()->getScheme(),
'persistent' => $this->getConfig()->isPersistent(),
'timeout' => $this->getConfig()->getTimeout(),
'path' => $this->getConfig()->getPath(),
], $options
);
} else {
$this->instance = new PredisClient($this->getConfig()->getPredisConfigArray(), $options);
}
try {
$this->instance->connect();
} catch (PredisConnectionException $e) {
throw new PhpfastcacheDriverException(
'Failed to connect to predis server. Check the Predis documentation: https://github.com/nrk/predis/tree/v1.1#how-to-install-and-use-predis',
0,
$e
);
}
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$val = $this->instance->get($item->getKey());
if ($val == false) {
return null;
}
return $this->decode($val);
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$ttl = $item->getExpirationDate()->getTimestamp() - time();
/**
* @see https://redis.io/commands/setex
* @see https://redis.io/commands/expire
*/
if ($ttl <= 0) {
return (bool)$this->instance->expire($item->getKey(), 0);
}
return $this->instance->setex($item->getKey(), $ttl, $this->encode($this->driverPreWrap($item)))->getPayload() === 'OK';
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)$this->instance->del([$item->getKey()]);
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
return $this->instance->flushdb()->getPayload() === 'OK';
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Predis;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Predis\Driver as PredisDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Predis
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(PredisDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof PredisDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,188 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Redis;
use Phpfastcache\Config\ConfigurationOption;
use Redis as RedisClient;
class Config extends ConfigurationOption
{
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 6379;
/**
* @var null|string
*/
protected $password = '';
/**
* @var null|int
*/
protected $database = 0;
/**
* @var int
*/
protected $timeout = 5;
/**
* @var RedisClient
*/
protected $redisClient;
/**
* @var string
*/
protected $optPrefix = '';
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return self
*/
public function setHost(string $host): self
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return self
*/
public function setPort(int $port): self
{
$this->port = $port;
return $this;
}
/**
* @return null|string
*/
public function getPassword()
{
return $this->password;
}
/**
* @param string|null $password
*
* @return self
*/
public function setPassword(string $password = null): self
{
$this->password = $password;
return $this;
}
/**
* @return null|int
*/
public function getDatabase(): ?int
{
return $this->database;
}
/**
* @param int|null $database
*
* @return self
*/
public function setDatabase(int $database = null): self
{
$this->database = $database;
return $this;
}
/**
* @return int
*/
public function getTimeout(): int
{
return $this->timeout;
}
/**
* @param int $timeout
* @return self
*/
public function setTimeout(int $timeout): self
{
$this->timeout = $timeout;
return $this;
}
/**
* @return RedisClient|null
*/
public function getRedisClient()
{
return $this->redisClient;
}
/**
* @param RedisClient $predisClient |null
* @return Config
*/
public function setRedisClient(RedisClient $redisClient = null): Config
{
$this->redisClient = $redisClient;
return $this;
}
/**
* @return string
* @since 7.0.2
*/
public function getOptPrefix(): string
{
return $this->optPrefix;
}
/**
* @param string $optPrefix
* @return Config
* @since 7.0.2
*/
public function setOptPrefix(string $optPrefix): Config
{
$this->optPrefix = trim($optPrefix);
return $this;
}
}

View File

@ -0,0 +1,191 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Redis;
use DateTime;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException, PhpfastcacheLogicException};
use Psr\Cache\CacheItemInterface;
use Redis as RedisClient;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('Redis');
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
// used_memory
$info = $this->instance->info();
$date = (new DateTime())->setTimestamp(time() - $info['uptime_in_seconds']);
return (new DriverStatistic())
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData($info)
->setSize((int)$info['used_memory'])
->setInfo(
sprintf(
"The Redis daemon v%s is up since %s.\n For more information see RawData. \n Driver size includes the memory allocation size.",
$info['redis_version'],
$date->format(DATE_RFC2822)
)
);
}
/**
* @return bool
* @throws PhpfastcacheLogicException
*/
protected function driverConnect(): bool
{
if ($this->instance instanceof RedisClient) {
throw new PhpfastcacheLogicException('Already connected to Redis server');
}
/**
* In case of an user-provided
* Redis client just return here
*/
if ($this->getConfig()->getRedisClient() instanceof RedisClient) {
/**
* Unlike Predis, we can't test if we're are connected
* or not, so let's just assume that we are
*/
$this->instance = $this->getConfig()->getRedisClient();
return true;
}
$this->instance = $this->instance ?: new RedisClient();
/**
* If path is provided we consider it as an UNIX Socket
*/
if ($this->getConfig()->getPath()) {
$isConnected = $this->instance->connect($this->getConfig()->getPath());
} else {
$isConnected = $this->instance->connect($this->getConfig()->getHost(), $this->getConfig()->getPort(), $this->getConfig()->getTimeout());
}
if (!$isConnected && $this->getConfig()->getPath()) {
return false;
}
if ($this->getConfig()->getOptPrefix()) {
$this->instance->setOption(RedisClient::OPT_PREFIX, $this->getConfig()->getOptPrefix());
}
if ($this->getConfig()->getPassword() && !$this->instance->auth($this->getConfig()->getPassword())) {
return false;
}
if ($this->getConfig()->getDatabase() !== null) {
$this->instance->select($this->getConfig()->getDatabase());
}
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$val = $this->instance->get($item->getKey());
if ($val == false) {
return null;
}
return $this->decode($val);
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$ttl = $item->getExpirationDate()->getTimestamp() - time();
/**
* @see https://redis.io/commands/setex
* @see https://redis.io/commands/expire
*/
if ($ttl <= 0) {
return $this->instance->expire($item->getKey(), 0);
}
return $this->instance->setex($item->getKey(), $ttl, $this->encode($this->driverPreWrap($item)));
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)$this->instance->del($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
return $this->instance->flushDB();
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Redis;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Redis\Driver as RedisDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Redis
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(RedisDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof RedisDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Sqlite;
use Phpfastcache\Config\{ConfigurationOption, IOConfigurationOptionTrait};
class Config extends ConfigurationOption
{
use IOConfigurationOptionTrait;
}

View File

@ -0,0 +1,383 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Sqlite;
use PDO;
use PDOException;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface, IO\IOHelperTrait};
use Phpfastcache\Exceptions\{PhpfastcacheCoreException, PhpfastcacheInvalidArgumentException, PhpfastcacheIOException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait, IOHelperTrait;
/**
*
*/
protected const INDEXING_FILE = 'indexing';
/**
* @var int
*/
protected $maxSize = 10; // 10 mb
/**
* @var int
*/
protected $currentDB = 1;
/**
* @var string
*/
protected $SqliteDir = '';
/**
* @var PDO
*/
protected $indexing;
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('pdo_sqlite') && (is_writable($this->getSqliteDir()) || @mkdir($this->getSqliteDir(), $this->getDefaultChmod(), true));
}
/**
* @return string
* @throws PhpfastcacheCoreException
*/
public function getSqliteDir(): string
{
return $this->SqliteDir ?: $this->getPath();
}
/**
* @return array
*/
public function __sleep(): array
{
return array_diff(array_keys(get_object_vars($this)), ['indexing', 'instance']);
}
/**
* @return bool
* @throws PhpfastcacheIOException
*/
protected function driverConnect(): bool
{
if (!file_exists($this->getSqliteDir()) && !@mkdir($this->getSqliteDir(), $this->getDefaultChmod(), true)) {
throw new PhpfastcacheIOException(sprintf('Sqlite cannot write in "%s", aborting...', $this->getPath()));
}
if (!file_exists($this->getPath())) {
if (!mkdir($this->getPath(), $this->getDefaultChmod(), true)
) {
$this->fallback = true;
}
}
$this->SqliteDir = $this->getPath();
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
try {
$stm = $this->getDb($item->getEncodedKey())
->prepare("SELECT * FROM `caching` WHERE `keyword`=:keyword LIMIT 1");
$stm->execute(
[
':keyword' => $item->getEncodedKey(),
]
);
$row = $stm->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
try {
$stm = $this->getDb($item->getEncodedKey(), true)
->prepare("SELECT * FROM `caching` WHERE `keyword`=:keyword LIMIT 1");
$stm->execute(
[
':keyword' => $item->getEncodedKey(),
]
);
$row = $stm->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
return null;
}
}
if (isset($row['object'])) {
return $this->decode($row['object']);
}
return null;
}
/**
* @param string $keyword
* @param bool $reset
* @return PDO
*/
public function getDb(string $keyword, bool $reset = false): PDO
{
/**
* Default is phpfastcache
*/
$instant = $this->indexing($keyword);
/**
* init instant
*/
if (!isset($this->instance[$instant])) {
// check DB Files ready or not
$tableCreated = false;
if ($reset || !file_exists($this->SqliteDir . '/db' . $instant)) {
$tableCreated = true;
}
$PDO = new PDO('sqlite:' . $this->SqliteDir . '/db' . $instant);
$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($tableCreated) {
$this->initDB($PDO);
}
// Added by Observium developers
// Improve write speed, see:
// http://stackoverflow.com/questions/1711631/improve-insert-per-second-performance-of-sqlite
$PDO->exec('PRAGMA synchronous=OFF');
$PDO->exec('PRAGMA journal_mode=MEMORY');
$PDO->exec('PRAGMA temp_store=MEMORY');
//$PDO->exec('PRAGMA count_changes=false');
$this->instance[$instant] = $PDO;
unset($PDO);
}
return $this->instance[$instant];
}
/**
* INIT Instant DB
* Return Database of Keyword
* @param $keyword
* @return int
*/
public function indexing($keyword)
{
if ($this->indexing == null) {
$tableCreated = false;
if (!file_exists($this->SqliteDir . '/indexing')) {
$tableCreated = true;
}
$PDO = new PDO("sqlite:" . $this->SqliteDir . '/' . self::INDEXING_FILE);
$PDO->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
if ($tableCreated) {
$this->initIndexing($PDO);
}
// Added by Observium developers
// Improve write speed, see:
// http://stackoverflow.com/questions/1711631/improve-insert-per-second-performance-of-sqlite
$PDO->exec('PRAGMA synchronous=OFF');
$PDO->exec('PRAGMA journal_mode=MEMORY');
$PDO->exec('PRAGMA temp_store=MEMORY');
//$PDO->exec('PRAGMA count_changes=false');
$this->indexing = $PDO;
unset($PDO);
$stm = $this->indexing->prepare("SELECT MAX(`db`) as `db` FROM `balancing`");
$stm->execute();
$row = $stm->fetch(PDO::FETCH_ASSOC);
if (!isset($row['db'])) {
$db = 1;
} elseif ($row['db'] <= 1) {
$db = 1;
} else {
$db = $row['db'];
}
// check file size
$size = file_exists($this->SqliteDir . '/db' . $db) ? filesize($this->SqliteDir . '/db' . $db) : 1;
$size = round($size / 1024 / 1024, 1);
if ($size > $this->maxSize) {
$db++;
}
$this->currentDB = $db;
}
// look for keyword
$stm = $this->indexing->prepare("SELECT * FROM `balancing` WHERE `keyword`=:keyword LIMIT 1");
$stm->execute(
[
':keyword' => $keyword,
]
);
$row = $stm->fetch(PDO::FETCH_ASSOC);
if (isset($row['db']) && $row['db'] != '') {
$db = $row['db'];
} else {
/*
* Insert new to Indexing
*/
$db = $this->currentDB;
$stm = $this->indexing->prepare("INSERT INTO `balancing` (`keyword`,`db`) VALUES(:keyword, :db)");
$stm->execute(
[
':keyword' => $keyword,
':db' => $db,
]
);
}
return $db;
}
/**
* INIT Indexing DB
* @param PDO $db
*/
public function initIndexing(PDO $db)
{
// delete everything before reset indexing
$dir = opendir($this->SqliteDir);
while ($file = readdir($dir)) {
if ($file != '.' && $file != '..' && $file != 'indexing' && $file != 'dbfastcache') {
unlink($this->SqliteDir . '/' . $file);
}
}
$db->exec('DROP TABLE if exists "balancing"');
$db->exec('CREATE TABLE "balancing" ("keyword" VARCHAR PRIMARY KEY NOT NULL UNIQUE, "db" INTEGER)');
$db->exec('CREATE INDEX "db" ON "balancing" ("db")');
$db->exec('CREATE UNIQUE INDEX "lookup" ON "balancing" ("keyword")');
}
/**
* INIT NEW DB
* @param PDO $db
*/
public function initDB(PDO $db)
{
$db->exec('drop table if exists "caching"');
$db->exec('CREATE TABLE "caching" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "keyword" VARCHAR UNIQUE, "object" BLOB, "exp" INTEGER)');
$db->exec('CREATE UNIQUE INDEX "cleanup" ON "caching" ("keyword","exp")');
$db->exec('CREATE INDEX "exp" ON "caching" ("exp")');
$db->exec('CREATE UNIQUE INDEX "keyword" ON "caching" ("keyword")');
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$stm = $this->getDb($item->getEncodedKey())
->prepare("INSERT OR REPLACE INTO `caching` (`keyword`,`object`,`exp`) values(:keyword,:object,:exp)");
$stm->execute(
[
':keyword' => $item->getEncodedKey(),
':object' => $this->encode($this->driverPreWrap($item)),
':exp' => $item->getExpirationDate()->getTimestamp(),
]
);
return true;
} catch (PDOException $e) {
return false;
}
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
try {
$stm = $this->getDb($item->getEncodedKey())
->prepare("DELETE FROM `caching` WHERE (`exp` <= :U) OR (`keyword`=:keyword) ");
return $stm->execute(
[
':keyword' => $item->getEncodedKey(),
':U' => time(),
]
);
} catch (PDOException $e) {
return false;
}
} else {
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
}
/**
* @return bool
*/
protected function driverClear(): bool
{
$this->instance = [];
$this->indexing = null;
// delete everything before reset indexing
$dir = opendir($this->getSqliteDir());
while ($file = readdir($dir)) {
if ($file != '.' && $file != '..') {
unlink($this->getSqliteDir() . '/' . $file);
}
}
return true;
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Sqlite;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Sqlite\Driver as SqliteDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Sqlite
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(SqliteDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof SqliteDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,114 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Ssdb;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
/**
* @var string
*/
protected $host = '127.0.0.1';
/**
* @var int
*/
protected $port = 8888;
/**
* @var string
*/
protected $password = '';
/**
* @var int
*/
protected $timeout = 2000;
/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}
/**
* @param string $host
* @return Config
*/
public function setHost(string $host): Config
{
$this->host = $host;
return $this;
}
/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}
/**
* @param int $port
* @return Config
*/
public function setPort(int $port): Config
{
$this->port = $port;
return $this;
}
/**
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @param string $password
* @return Config
*/
public function setPassword(string $password): Config
{
$this->password = $password;
return $this;
}
/**
* @return int
*/
public function getTimeout(): int
{
return $this->timeout;
}
/**
* @param int $timeout
* @return Config
*/
public function setTimeout(int $timeout): Config
{
$this->timeout = $timeout;
return $this;
}
}

View File

@ -0,0 +1,156 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Ssdb;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheDriverCheckException, PhpfastcacheDriverException, PhpfastcacheInvalidArgumentException};
use phpssdb\Core\{SimpleSSDB, SSDBException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property SimpleSSDB $instance Instance of driver service
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
static $driverCheck;
if ($driverCheck === null) {
return ($driverCheck = class_exists('phpssdb\Core\SSDB'));
}
return $driverCheck;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stat = new DriverStatistic();
$info = $this->instance->info();
/**
* Data returned by Ssdb are very poorly formatted
* using hardcoded offset of pair key-value :-(
*/
$stat->setInfo(sprintf("Ssdb-server v%s with a total of %s call(s).\n For more information see RawData.", $info[2], $info[6]))
->setRawData($info)
->setData(implode(', ', array_keys($this->itemInstances)))
->setSize($this->instance->dbsize());
return $stat;
}
/**
* @return bool
* @throws PhpfastcacheDriverException
*/
protected function driverConnect(): bool
{
try {
$clientConfig = $this->getConfig();
$this->instance = new SimpleSSDB($clientConfig->getHost(), $clientConfig->getPort(), $clientConfig->getTimeout());
if (!empty($clientConfig->getPassword())) {
$this->instance->auth($clientConfig->getPassword());
}
if (!$this->instance) {
return false;
}
return true;
} catch (SSDBException $e) {
throw new PhpfastcacheDriverCheckException('Ssdb failed to connect with error: ' . $e->getMessage(), 0, $e);
}
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$val = $this->instance->get($item->getEncodedKey());
if ($val == false) {
return null;
}
return $this->decode($val);
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)$this->instance->setx($item->getEncodedKey(), $this->encode($this->driverPreWrap($item)), $item->getTtl());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)$this->instance->del($item->getEncodedKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
return (bool)$this->instance->flushdb('kv');
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Ssdb;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Ssdb\Driver as SsdbDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Ssdb
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(SsdbDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof SsdbDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Wincache;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,130 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Wincache;
use DateTime;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('wincache') && function_exists('wincache_ucache_set');
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$memInfo = wincache_ucache_meminfo();
$info = wincache_ucache_info();
$date = (new DateTime())->setTimestamp(time() - $info['total_cache_uptime']);
return (new DriverStatistic())
->setInfo(sprintf("The Wincache daemon is up since %s.\n For more information see RawData.", $date->format(DATE_RFC2822)))
->setSize($memInfo['memory_free'] - $memInfo['memory_total'])
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData($memInfo);
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$val = wincache_ucache_get($item->getKey(), $suc);
if ($suc === false) {
return null;
}
return $val;
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return wincache_ucache_set($item->getKey(), $this->driverPreWrap($item), $item->getTtl());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return wincache_ucache_delete($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @return bool
*/
protected function driverClear(): bool
{
return wincache_ucache_clear();
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Wincache;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Wincache\Driver as WincacheDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Wincache
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(WincacheDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof WincacheDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Zenddisk;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,141 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Lucas Brucksch <support@hammermaps.de>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Zenddisk;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver (zend disk cache)
* Requires Zend Data Cache Functions from ZendServer
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('Zend Data Cache') && function_exists('zend_disk_cache_store');
}
/**
* @return string
*/
public function getHelp(): string
{
return <<<HELP
<p>
This driver rely on Zend Server 8.5+, see: https://www.zend.com/en/products/zend_server
</p>
HELP;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stat = new DriverStatistic();
$stat->setInfo('[ZendDisk] A void info string')
->setSize(0)
->setData(implode(', ', array_keys($this->itemInstances)))
->setRawData(false);
return $stat;
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$data = zend_disk_cache_fetch($item->getKey());
if ($data === false) {
return null;
}
return $data;
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$ttl = $item->getExpirationDate()->getTimestamp() - time();
return zend_disk_cache_store($item->getKey(), $this->driverPreWrap($item), ($ttl > 0 ? $ttl : 0));
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)zend_disk_cache_delete($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
return @zend_disk_cache_clear();
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Lucas Brucksch <support@hammermaps.de>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Zenddisk;
use Phpfastcache\Core\Item\{ExtendedCacheItemInterface, ItemBaseTrait};
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
use Phpfastcache\Drivers\Zenddisk\Driver as ZendDiskDriver;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
/**
* Class Item
* @package phpFastCache\Drivers\Zenddisk
*/
class Item implements ExtendedCacheItemInterface
{
use ItemBaseTrait {
ItemBaseTrait::__construct as __BaseConstruct;
}
/**
* Item constructor.
* @param Driver $driver
* @param $key
* @throws PhpfastcacheInvalidArgumentException
*/
public function __construct(ZendDiskDriver $driver, $key)
{
$this->__BaseConstruct($driver, $key);
}
/**
* @param ExtendedCacheItemPoolInterface $driver
* @return static
* @throws PhpfastcacheInvalidArgumentException
*/
public function setDriver(ExtendedCacheItemPoolInterface $driver)
{
if ($driver instanceof ZendDiskDriver) {
$this->driver = $driver;
return $this;
}
throw new PhpfastcacheInvalidArgumentException('Invalid driver instance');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> https://www.phpfastcache.com
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Zendshm;
use Phpfastcache\Config\ConfigurationOption;
class Config extends ConfigurationOption
{
}

View File

@ -0,0 +1,140 @@
<?php
/**
*
* This file is part of phpFastCache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Lucas Brucksch <support@hammermaps.de>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Drivers\Zendshm;
use Phpfastcache\Cluster\AggregatablePoolInterface;
use Phpfastcache\Core\Pool\{DriverBaseTrait, ExtendedCacheItemPoolInterface};
use Phpfastcache\Entities\DriverStatistic;
use Phpfastcache\Exceptions\{PhpfastcacheInvalidArgumentException};
use Psr\Cache\CacheItemInterface;
/**
* Class Driver (zend memory cache)
* Requires Zend Data Cache Functions from ZendServer
* @package phpFastCache\Drivers
* @property Config $config Config object
* @method Config getConfig() Return the config object
*/
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
{
use DriverBaseTrait;
/**
* @return bool
*/
public function driverCheck(): bool
{
return extension_loaded('Zend Data Cache') && function_exists('zend_shm_cache_store');
}
/**
* @return string
*/
public function getHelp(): string
{
return <<<HELP
<p>
This driver rely on Zend Server 8.5+, see: https://www.zend.com/en/products/zend_server
</p>
HELP;
}
/**
* @return DriverStatistic
*/
public function getStats(): DriverStatistic
{
$stats = (array)zend_shm_cache_info();
return (new DriverStatistic())
->setData(implode(', ', array_keys($this->itemInstances)))
->setInfo(sprintf("The Zend memory have %d item(s) in cache.\n For more information see RawData.", $stats['items_total']))
->setRawData($stats)
->setSize($stats['memory_total']);
}
/**
* @return bool
*/
protected function driverConnect(): bool
{
return true;
}
/**
* @param CacheItemInterface $item
* @return null|array
*/
protected function driverRead(CacheItemInterface $item)
{
$data = zend_shm_cache_fetch($item->getKey());
if ($data === false) {
return null;
}
return $data;
}
/**
* @param CacheItemInterface $item
* @return mixed
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverWrite(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
$ttl = $item->getExpirationDate()->getTimestamp() - time();
return zend_shm_cache_store($item->getKey(), $this->driverPreWrap($item), ($ttl > 0 ? $ttl : 0));
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/********************
*
* PSR-6 Extended Methods
*
*******************/
/**
* @param CacheItemInterface $item
* @return bool
* @throws PhpfastcacheInvalidArgumentException
*/
protected function driverDelete(CacheItemInterface $item): bool
{
/**
* Check for Cross-Driver type confusion
*/
if ($item instanceof Item) {
return (bool)zend_shm_cache_delete($item->getKey());
}
throw new PhpfastcacheInvalidArgumentException('Cross-Driver type confusion detected');
}
/**
* @return bool
*/
protected function driverClear(): bool
{
return @zend_shm_cache_clear();
}
}

Some files were not shown because too many files have changed in this diff Show More