prefix) { self::$_prefix = substr(sha1(\RX_BASEDIR), 0, 10) . ':' . \RX_VERSION . ':'; } else { self::$_prefix = \RX_VERSION . ':'; } return self::$_driver; } /** * Get the list of supported cache drivers. * * @return array */ public static function getSupportedDrivers(): array { $result = array(); foreach (Storage::readDirectory(__DIR__ . '/drivers/cache', false) as $filename) { $driver_name = substr($filename, 0, -4); $class_name = '\Rhymix\Framework\Drivers\Cache\\' . $driver_name; if ($class_name::isSupported()) { $result[] = $driver_name; } } return $result; } /** * Get the name of the currently enabled cache driver. * * @return ?string */ public static function getDriverName(): ?string { return self::$_driver_name; } /** * Get the currently enabled cache driver, or a named driver with the given settings. * * @param string $name (optional) * @param array $config (optional) * @return ?Drivers\CacheInterface */ public static function getDriverInstance($name = null, array $config = []): ?Drivers\CacheInterface { if ($name === null) { return self::$_driver; } else { $class_name = '\\Rhymix\\Framework\\Drivers\\Cache\\' . $name; if (class_exists($class_name) && $class_name::isSupported() && $class_name::validateSettings($config)) { return $class_name::getInstance($config); } else { return null; } } } /** * Get the automatically generated cache prefix for this installation of Rhymix. * * @return string */ public static function getPrefix(): string { return self::$_prefix; } /** * Get the default TTL. * * @return int */ public static function getDefaultTTL(): int { return self::$_ttl; } /** * Set the default TTL. * * @param int $ttl * @return void */ public static function setDefaultTTL(int $ttl): void { self::$_ttl = $ttl; } /** * Get the value of a key. * * This method returns null if the key was not found. * * @param string $key * @return mixed */ public static function get(string $key) { if (self::$_driver !== null) { return self::$_driver->get(self::getRealKey($key)); } else { return null; } } /** * Set the value to a key. * * This method returns true on success and false on failure. * $ttl is measured in seconds. If it is not given, the default TTL is used. * $force is used to cache essential data when using the default driver. * * @param string $key * @param mixed $value * @param int $ttl (optional) * @param bool $force (optional) * @return bool */ public static function set(string $key, $value, int $ttl = 0, bool $force = false): bool { if (self::$_driver !== null) { if ($ttl >= (3600 * 24 * 30)) { $ttl = min(3600 * 24 * 30, max(0, $ttl - time())); } if ($ttl === 0) { $ttl = self::$_ttl; } return self::$_driver->set(self::getRealKey($key), $value, $ttl, $force) ? true : false; } else { return false; } } /** * Delete a key. * * This method returns true on success and false on failure. * If the key does not exist, it should return false. * * @param string $key * @return bool */ public static function delete(string $key): bool { if (self::$_driver !== null) { if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli') { self::sendClearRequest([$key]); } return self::$_driver->delete(self::getRealKey($key)) ? true : false; } else { return false; } } /** * Check if a key exists. * * This method returns true on success and false on failure. * * @param string $key * @return bool */ public static function exists(string $key): bool { if (self::$_driver !== null) { return self::$_driver->exists(self::getRealKey($key)) ? true : false; } else { return false; } } /** * Increase the value of a key by $amount. * * If the key does not exist, this method assumes that the current value is zero. * This method returns the new value, or -1 on failure. * * @param string $key * @param int $amount (optional) * @return int */ public static function incr(string $key, int $amount = 1): int { if (self::$_driver !== null) { return self::$_driver->incr(self::getRealKey($key), $amount); } else { return -1; } } /** * Decrease the value of a key by $amount. * * If the key does not exist, this method assumes that the current value is zero. * This method returns the new value, or -1 on failure. * * @param string $key * @param int $amount (optional) * @return int */ public static function decr(string $key, int $amount = 1): int { if (self::$_driver !== null) { return self::$_driver->decr(self::getRealKey($key), $amount); } else { return -1; } } /** * Clear a group of keys from the cache. * * This method returns true on success and false on failure. * * @param string $group_name * @return bool */ public static function clearGroup(string $group_name): bool { if (self::$_driver !== null) { if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli') { self::sendClearRequest([$group_name . ':*']); } $success = self::$_driver->incr(self::$_prefix . $group_name . '#version', 1) ? true : false; unset(self::$_group_versions[$group_name]); return $success; } else { return false; } } /** * Clear all keys from the cache. * * This method returns true on success and false on failure. * * @return bool */ public static function clearAll(): bool { if (self::$_driver !== null) { if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli') { self::sendClearRequest(['*']); } return self::$_driver->clear() ? true : false; } else { return false; } } /** * Get the group version. * * @param string $group_name * @return int */ public static function getGroupVersion(string $group_name): int { if (isset(self::$_group_versions[$group_name])) { return self::$_group_versions[$group_name]; } else { if (self::$_driver !== null) { return self::$_group_versions[$group_name] = intval(self::$_driver->get(self::$_prefix . $group_name . '#version')); } else { return self::$_group_versions[$group_name] = 0; } } } /** * Get the actual key used by Rhymix. * * @param string $key * @return string */ public static function getRealKey(string $key): string { $key = preg_replace_callback('/[^\x21-\x7E]/', function($match) { return rawurlencode($match[0]); }, $key); if (preg_match('/^([^:]+):(.+)$/i', $key, $matches)) { $key = $matches[1] . '#' . self::getGroupVersion($matches[1]) . ':' . $matches[2]; } return self::$_prefix . $key; } /** * Send a web request to clear the cache. * * @param array $keys * @return void */ public static function sendClearRequest(array $keys): void { if (!$keys) { return; } $keystring = implode('|', $keys); $signature = Security::createSignature($keystring); HTTP::post(\Context::getRequestUri(), [ 'module' => 'module', 'act' => 'procModuleClearCache', 'keys' => $keys, 'signature' => $signature, ]); } }