mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 17:28:55 +00:00
391 lines
12 KiB
PHP
Executable File
391 lines
12 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Blacklight\libraries;
|
|
|
|
/**
|
|
* Class Cache.
|
|
*
|
|
* Class for connecting to a memcached or redis server to cache data.
|
|
*/
|
|
class Cache
|
|
{
|
|
private const SERIALIZER_PHP = 0;
|
|
private const SERIALIZER_IGBINARY = 1;
|
|
private const SERIALIZER_NONE = 2;
|
|
|
|
private const TYPE_DISABLED = 0;
|
|
private const TYPE_MEMCACHED = 1;
|
|
private const TYPE_REDIS = 2;
|
|
private const TYPE_APC = 3;
|
|
|
|
/**
|
|
* @var \Memcached
|
|
*/
|
|
private $server;
|
|
|
|
/**
|
|
* Are we connected to the cache server?
|
|
* @var bool
|
|
*/
|
|
private $connected = false;
|
|
|
|
/**
|
|
* Optional socket file location.
|
|
* @var bool|string
|
|
*/
|
|
private $socketFile;
|
|
|
|
/**
|
|
* Store data on the cache server.
|
|
*
|
|
*
|
|
* @param $key
|
|
* @param $data
|
|
* @param $expiration
|
|
* @return bool
|
|
* @throws \Blacklight\libraries\CacheException
|
|
*/
|
|
public function set($key, $data, $expiration): bool
|
|
{
|
|
if ($this->ping()) {
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
case self::TYPE_MEMCACHED:
|
|
return $this->server->set($key, $data, $expiration);
|
|
case self::TYPE_APC:
|
|
return apc_add($key, $data, $expiration);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Attempt to retrieve a value from the cache server, if not set it.
|
|
*
|
|
*
|
|
* @param $key
|
|
* @return bool|mixed|string
|
|
* @throws \Blacklight\libraries\CacheException
|
|
*/
|
|
public function get($key)
|
|
{
|
|
if ($this->ping()) {
|
|
$data = '';
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
case self::TYPE_MEMCACHED:
|
|
$data = $this->server->get($key);
|
|
break;
|
|
case self::TYPE_APC:
|
|
$data = apc_fetch($key);
|
|
break;
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Delete data tied to a key on the cache server.
|
|
*
|
|
*
|
|
* @param $key
|
|
* @return bool|string[]
|
|
* @throws \Blacklight\libraries\CacheException
|
|
*/
|
|
public function delete($key)
|
|
{
|
|
if ($this->ping()) {
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
case self::TYPE_MEMCACHED:
|
|
return (bool) $this->server->delete($key);
|
|
case self::TYPE_APC:
|
|
return apc_delete($key);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Flush all data from the cache server?
|
|
*
|
|
*
|
|
* @throws \Blacklight\libraries\CacheException
|
|
*/
|
|
public function flush()
|
|
{
|
|
if ($this->ping()) {
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
$this->server->flushAll();
|
|
break;
|
|
case self::TYPE_MEMCACHED:
|
|
$this->server->flush();
|
|
break;
|
|
case self::TYPE_APC:
|
|
apc_clear_cache('user');
|
|
apc_clear_cache();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a SHA1 hash from a string which can be used to store/retrieve data.
|
|
*
|
|
* @param string $string
|
|
*
|
|
* @return string SHA1 hash of the input string.
|
|
*/
|
|
public function createKey($string)
|
|
{
|
|
return sha1($string);
|
|
}
|
|
|
|
/**
|
|
* Get cache server statistics.
|
|
*
|
|
*
|
|
* @return array|bool
|
|
* @throws \Blacklight\libraries\CacheException
|
|
*/
|
|
public function serverStatistics()
|
|
{
|
|
if ($this->ping()) {
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
return $this->server->info();
|
|
case self::TYPE_MEMCACHED:
|
|
return $this->server->getStats();
|
|
case self::TYPE_APC:
|
|
return apc_cache_info();
|
|
}
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Verify the user's cache settings, try to connect to the cache server.
|
|
*
|
|
* @throws \Blacklight\libraries\CacheException
|
|
*/
|
|
public function __construct()
|
|
{
|
|
if (! \defined('NN_CACHE_HOSTS')) {
|
|
throw new CacheException(
|
|
'The NN_CACHE_HOSTS is not defined! Define it in settings.php'
|
|
);
|
|
}
|
|
|
|
if (! \defined('NN_CACHE_TIMEOUT')) {
|
|
throw new CacheException(
|
|
'The NN_CACHE_TIMEOUT is not defined! Define it in settings.php, it is the time in seconds to time out from your cache server.'
|
|
);
|
|
}
|
|
|
|
$this->socketFile = false;
|
|
if (\defined('NN_CACHE_SOCKET_FILE') && NN_CACHE_SOCKET_FILE != '') {
|
|
$this->socketFile = true;
|
|
}
|
|
|
|
$serializer = false;
|
|
if (\defined('NN_CACHE_SERIALIZER')) {
|
|
$serializer = true;
|
|
}
|
|
|
|
switch (NN_CACHE_TYPE) {
|
|
|
|
case self::TYPE_REDIS:
|
|
if (! \extension_loaded('redis')) {
|
|
throw new CacheException('The redis extension is not loaded!');
|
|
}
|
|
$this->server = new \Redis();
|
|
$this->connect();
|
|
if ($serializer) {
|
|
$this->server->setOption(\Redis::OPT_SERIALIZER, $this->verifySerializer());
|
|
}
|
|
break;
|
|
|
|
case self::TYPE_MEMCACHED:
|
|
if (! \extension_loaded('memcached')) {
|
|
throw new CacheException('The memcached extension is not loaded!');
|
|
}
|
|
$this->server = new \Memcached();
|
|
if ($serializer) {
|
|
$this->server->setOption(\Memcached::OPT_SERIALIZER, $this->verifySerializer());
|
|
}
|
|
$this->server->setOption(\Memcached::OPT_COMPRESSION, (defined('NN_CACHE_COMPRESSION') ? NN_CACHE_COMPRESSION : false));
|
|
$this->connect();
|
|
break;
|
|
|
|
case self::TYPE_APC:
|
|
// Faster than checking if apcu or apc is loaded.
|
|
if (! \function_exists('apc_add')) {
|
|
throw new CacheException('The APCu extension is not loaded or enabled!');
|
|
}
|
|
$this->connect();
|
|
break;
|
|
|
|
case self::TYPE_DISABLED:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destroy the connections.
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
$this->server->close();
|
|
break;
|
|
case self::TYPE_MEMCACHED:
|
|
$this->server->quit();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Connect to the cache server(s).
|
|
*
|
|
* @throws CacheException
|
|
*/
|
|
private function connect()
|
|
{
|
|
$this->connected = false;
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
if ($this->socketFile === false) {
|
|
$servers = unserialize(NN_CACHE_HOSTS);
|
|
foreach ($servers as $server) {
|
|
if ($this->server->connect($server['host'], $server['port'], (float) NN_CACHE_TIMEOUT) === false) {
|
|
throw new CacheException('Error connecting to the Redis server!');
|
|
} else {
|
|
$this->connected = true;
|
|
}
|
|
}
|
|
} else {
|
|
if ($this->server->connect(NN_CACHE_SOCKET_FILE) === false) {
|
|
throw new CacheException('Error connecting to the Redis server!');
|
|
} else {
|
|
$this->connected = true;
|
|
}
|
|
}
|
|
break;
|
|
case self::TYPE_MEMCACHED:
|
|
$params = ($this->socketFile === false ? unserialize(NN_CACHE_HOSTS) : [[NN_CACHE_SOCKET_FILE, 'port' => 0]]);
|
|
if ($this->server->addServers($params) === false) {
|
|
throw new CacheException('Error connecting to the Memcached server!');
|
|
} else {
|
|
$this->connected = true;
|
|
}
|
|
break;
|
|
case self::TYPE_APC:
|
|
$this->connected = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if we are still connected to the cache server, reconnect if not.
|
|
*
|
|
*
|
|
* @return bool
|
|
* @throws \Blacklight\libraries\CacheException
|
|
*/
|
|
private function ping()
|
|
{
|
|
if (! $this->connected) {
|
|
return false;
|
|
}
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
try {
|
|
return (bool) $this->server->ping();
|
|
} catch (\RedisException $error) {
|
|
// nothing to see here, move along
|
|
}
|
|
break;
|
|
case self::TYPE_MEMCACHED:
|
|
$versions = $this->server->getVersion();
|
|
if ($versions) {
|
|
foreach ($versions as $version) {
|
|
if ($version != '255.255.255') {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case self::TYPE_APC:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
$this->connect();
|
|
|
|
return $this->connected;
|
|
}
|
|
|
|
/**
|
|
* Verify the user selected serializer, return the memcached or redis appropriate serializer option.
|
|
*
|
|
* @return int
|
|
* @throws CacheException
|
|
*/
|
|
private function verifySerializer()
|
|
{
|
|
switch (NN_CACHE_SERIALIZER) {
|
|
case self::SERIALIZER_IGBINARY:
|
|
if (! \extension_loaded('igbinary')) {
|
|
throw new CacheException('Error: The igbinary extension is not loaded!');
|
|
}
|
|
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
// If this is not defined, it means phpredis was not compiled with --enable-redis-igbinary
|
|
if (! \defined('\Redis::SERIALIZER_IGBINARY')) {
|
|
throw new CacheException('Error: phpredis was not compiled with igbinary support!');
|
|
}
|
|
|
|
return \Redis::SERIALIZER_IGBINARY;
|
|
case self::TYPE_MEMCACHED:
|
|
if (\Memcached::HAVE_IGBINARY > 0) {
|
|
return \Memcached::SERIALIZER_IGBINARY;
|
|
}
|
|
throw new CacheException('Error: You have not compiled Memcached with igbinary support!');
|
|
case self::TYPE_APC: // Ignore - set by apc.serializer setting.
|
|
default:
|
|
return null;
|
|
}
|
|
|
|
// no break
|
|
case self::SERIALIZER_NONE:
|
|
// Only redis supports this.
|
|
if (NN_CACHE_TYPE !== self::TYPE_REDIS) {
|
|
throw new CacheException('Error: Disabled serialization is only available on Redis!');
|
|
}
|
|
|
|
return \Redis::SERIALIZER_NONE;
|
|
|
|
case self::SERIALIZER_PHP:
|
|
default:
|
|
switch (NN_CACHE_TYPE) {
|
|
case self::TYPE_REDIS:
|
|
return \Redis::SERIALIZER_PHP;
|
|
case self::TYPE_MEMCACHED:
|
|
return \Memcached::SERIALIZER_PHP;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|