Spade
Mini Shell
| Directory:~$ /home/lmsyaran/public_html/joomla4/ |
| [Home] [System Details] [Kill Me] |
ApcStorage.php000064400000015415151157453270007325 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheStorage;
/**
* APC cache storage handler
*
* @link https://www.php.net/manual/en/book.apc.php
* @since 1.7.0
* @deprecated 4.0 Use the APCu handler instead
*/
class ApcStorage extends CacheStorage
{
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
return apc_exists($this->_getCacheId($id, $group));
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function get($id, $group, $checkTime = true)
{
return apc_fetch($this->_getCacheId($id, $group));
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function getAll()
{
$allinfo = apc_cache_info('user');
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
$data = array();
foreach ($keys as $key)
{
if (isset($key['info']))
{
// If APCu is being used for this adapter, the internal key name
changed with APCu 4.0.7 from key to info
$name = $key['info'];
}
elseif (isset($key['entry_name']))
{
// Some APC modules changed the internal key name from key to
entry_name, HHVM is one such case
$name = $key['entry_name'];
}
else
{
// A fall back for the old internal key name
$name = $key['key'];
}
$namearr = explode('-', $name);
if ($namearr !== false && $namearr[0] == $secret &&
$namearr[1] == 'cache')
{
$group = $namearr[2];
if (!isset($data[$group]))
{
$item = new CacheStorageHelper($group);
}
else
{
$item = $data[$group];
}
$item->updateSize($key['mem_size']);
$data[$group] = $item;
}
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 1.7.0
*/
public function store($id, $group, $data)
{
return apc_store($this->_getCacheId($id, $group), $data,
$this->_lifetime);
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function remove($id, $group)
{
return apc_delete($this->_getCacheId($id, $group));
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 1.7.0
*/
public function clean($group, $mode = null)
{
$allinfo = apc_cache_info('user');
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
foreach ($keys as $key)
{
if (isset($key['info']))
{
// If APCu is being used for this adapter, the internal key name
changed with APCu 4.0.7 from key to info
$internalKey = $key['info'];
}
elseif (isset($key['entry_name']))
{
// Some APC modules changed the internal key name from key to
entry_name, HHVM is one such case
$internalKey = $key['entry_name'];
}
else
{
// A fall back for the old internal key name
$internalKey = $key['key'];
}
if (strpos($internalKey, $secret . '-cache-' . $group .
'-') === 0 xor $mode != 'group')
{
apc_delete($internalKey);
}
}
return true;
}
/**
* Garbage collect expired cache data
*
* @return boolean
*
* @since 1.7.0
*/
public function gc()
{
$allinfo = apc_cache_info('user');
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
foreach ($keys as $key)
{
if (isset($key['info']))
{
// If APCu is being used for this adapter, the internal key name
changed with APCu 4.0.7 from key to info
$internalKey = $key['info'];
}
elseif (isset($key['entry_name']))
{
// Some APC modules changed the internal key name from key to
entry_name, HHVM is one such case
$internalKey = $key['entry_name'];
}
else
{
// A fall back for the old internal key name
$internalKey = $key['key'];
}
if (strpos($internalKey, $secret . '-cache-'))
{
apc_fetch($internalKey);
}
}
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.0.0
*/
public static function isSupported()
{
$supported = extension_loaded('apc') &&
ini_get('apc.enabled');
// If on the CLI interface, the `apc.enable_cli` option must also be
enabled
if ($supported && php_sapi_name() === 'cli')
{
$supported = ini_get('apc.enable_cli');
}
return (bool) $supported;
}
/**
* Lock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param integer $locktime Cached item max lock time
*
* @return mixed Boolean false if locking failed or an object containing
properties lock and locklooped
*
* @since 1.7.0
*/
public function lock($id, $group, $locktime)
{
$returning = new \stdClass;
$returning->locklooped = false;
$looptime = $locktime * 10;
$cache_id = $this->_getCacheId($id, $group) . '_lock';
$data_lock = apc_add($cache_id, 1, $locktime);
if ($data_lock === false)
{
$lock_counter = 0;
// Loop until you find that the lock has been released. That implies
that data get from other thread has finished
while ($data_lock === false)
{
if ($lock_counter > $looptime)
{
$returning->locked = false;
$returning->locklooped = true;
break;
}
usleep(100);
$data_lock = apc_add($cache_id, 1, $locktime);
$lock_counter++;
}
}
$returning->locked = $data_lock;
return $returning;
}
/**
* Unlock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function unlock($id, $group = null)
{
return apc_delete($this->_getCacheId($id, $group) .
'_lock');
}
}
ApcuStorage.php000064400000015462151157453270007514 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheStorage;
/**
* APCu cache storage handler
*
* @link https://www.php.net/manual/en/ref.apcu.php
* @since 3.5
*/
class ApcuStorage extends CacheStorage
{
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
return apcu_exists($this->_getCacheId($id, $group));
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 3.5
*/
public function get($id, $group, $checkTime = true)
{
return apcu_fetch($this->_getCacheId($id, $group));
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 3.5
*/
public function getAll()
{
$allinfo = apcu_cache_info();
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
$data = array();
foreach ($keys as $key)
{
if (isset($key['info']))
{
// The internal key name changed with APCu 4.0.7 from key to info
$name = $key['info'];
}
elseif (isset($key['entry_name']))
{
// Some APCu modules changed the internal key name from key to
entry_name
$name = $key['entry_name'];
}
else
{
// A fall back for the old internal key name
$name = $key['key'];
}
$namearr = explode('-', $name);
if ($namearr !== false && $namearr[0] == $secret &&
$namearr[1] == 'cache')
{
$group = $namearr[2];
if (!isset($data[$group]))
{
$item = new CacheStorageHelper($group);
}
else
{
$item = $data[$group];
}
$item->updateSize($key['mem_size']);
$data[$group] = $item;
}
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 3.5
*/
public function store($id, $group, $data)
{
return apcu_store($this->_getCacheId($id, $group), $data,
$this->_lifetime);
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.5
*/
public function remove($id, $group)
{
$cache_id = $this->_getCacheId($id, $group);
// The apcu_delete function returns false if the ID does not exist
if (apcu_exists($cache_id))
{
return apcu_delete($cache_id);
}
return true;
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 3.5
*/
public function clean($group, $mode = null)
{
$allinfo = apcu_cache_info();
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
foreach ($keys as $key)
{
if (isset($key['info']))
{
// The internal key name changed with APCu 4.0.7 from key to info
$internalKey = $key['info'];
}
elseif (isset($key['entry_name']))
{
// Some APCu modules changed the internal key name from key to
entry_name
$internalKey = $key['entry_name'];
}
else
{
// A fall back for the old internal key name
$internalKey = $key['key'];
}
if (strpos($internalKey, $secret . '-cache-' . $group .
'-') === 0 xor $mode != 'group')
{
apcu_delete($internalKey);
}
}
return true;
}
/**
* Garbage collect expired cache data
*
* @return boolean
*
* @since 3.5
*/
public function gc()
{
$allinfo = apcu_cache_info();
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
foreach ($keys as $key)
{
if (isset($key['info']))
{
// The internal key name changed with APCu 4.0.7 from key to info
$internalKey = $key['info'];
}
elseif (isset($key['entry_name']))
{
// Some APCu modules changed the internal key name from key to
entry_name
$internalKey = $key['entry_name'];
}
else
{
// A fall back for the old internal key name
$internalKey = $key['key'];
}
if (strpos($internalKey, $secret . '-cache-'))
{
apcu_fetch($internalKey);
}
}
return true;
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.5
*/
public static function isSupported()
{
$supported = extension_loaded('apcu') &&
ini_get('apc.enabled');
// If on the CLI interface, the `apc.enable_cli` option must also be
enabled
if ($supported && php_sapi_name() === 'cli')
{
$supported = ini_get('apc.enable_cli');
}
return (bool) $supported;
}
/**
* Lock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param integer $locktime Cached item max lock time
*
* @return mixed Boolean false if locking failed or an object containing
properties lock and locklooped
*
* @since 3.5
*/
public function lock($id, $group, $locktime)
{
$returning = new \stdClass;
$returning->locklooped = false;
$looptime = $locktime * 10;
$cache_id = $this->_getCacheId($id, $group) . '_lock';
$data_lock = apcu_add($cache_id, 1, $locktime);
if ($data_lock === false)
{
$lock_counter = 0;
// Loop until you find that the lock has been released.
// That implies that data get from other thread has finished
while ($data_lock === false)
{
if ($lock_counter > $looptime)
{
$returning->locked = false;
$returning->locklooped = true;
break;
}
usleep(100);
$data_lock = apcu_add($cache_id, 1, $locktime);
$lock_counter++;
}
}
$returning->locked = $data_lock;
return $returning;
}
/**
* Unlock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.5
*/
public function unlock($id, $group = null)
{
$cache_id = $this->_getCacheId($id, $group) . '_lock';
// The apcu_delete function returns false if the ID does not exist
if (apcu_exists($cache_id))
{
return apcu_delete($cache_id);
}
return true;
}
}
CacheliteStorage.php000064400000017161151157453270010503 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheStorage;
/**
* Cache lite storage handler
*
* @link http://pear.php.net/package/Cache_Lite/
* @since 1.7.0
* @deprecated 4.0 Deprecated without replacement
*/
class CacheliteStorage extends CacheStorage
{
/**
* Singleton Cache_Lite instance
*
* @var \Cache_Lite
* @since 1.7.0
*/
protected static $CacheLiteInstance = null;
/**
* Root path
*
* @var string
* @since 1.7.0
*/
protected $_root;
/**
* Constructor
*
* @param array $options Optional parameters.
*
* @since 1.7.0
*/
public function __construct($options = array())
{
parent::__construct($options);
$this->_root = $options['cachebase'];
$cloptions = array(
'cacheDir' => $this->_root .
'/',
'lifeTime' => $this->_lifetime,
'fileLocking' => $this->_locking,
'automaticCleaningFactor' =>
isset($options['autoclean']) ? $options['autoclean'] :
200,
'fileNameProtection' => false,
'hashedDirectoryLevel' => 0,
'caching' => $options['caching'],
);
if (static::$CacheLiteInstance === null)
{
$this->initCache($cloptions);
}
}
/**
* Instantiates the Cache_Lite object. Only initializes the engine if it
does not already exist.
*
* @param array $cloptions optional parameters
*
* @return \Cache_Lite
*
* @since 1.7.0
*/
protected function initCache($cloptions)
{
if (!class_exists('\\Cache_Lite'))
{
require_once 'Cache/Lite.php';
}
static::$CacheLiteInstance = new \Cache_Lite($cloptions);
return static::$CacheLiteInstance;
}
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
return $this->get($id, $group) !== false;
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function get($id, $group, $checkTime = true)
{
static::$CacheLiteInstance->setOption('cacheDir',
$this->_root . '/' . $group . '/');
// This call is needed to ensure $this->rawname is set
$this->_getCacheId($id, $group);
return static::$CacheLiteInstance->get($this->rawname, $group);
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function getAll()
{
$path = $this->_root;
$folders = new \DirectoryIterator($path);
$data = array();
foreach ($folders as $folder)
{
if (!$folder->isDir() || $folder->isDot())
{
continue;
}
$foldername = $folder->getFilename();
$files = new \DirectoryIterator($path . '/' . $foldername);
$item = new CacheStorageHelper($foldername);
foreach ($files as $file)
{
if (!$file->isFile())
{
continue;
}
$filename = $file->getFilename();
$item->updateSize(filesize($path . '/' . $foldername .
'/' . $filename));
}
$data[$foldername] = $item;
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 1.7.0
*/
public function store($id, $group, $data)
{
$dir = $this->_root . '/' . $group;
// If the folder doesn't exist try to create it
if (!is_dir($dir))
{
// Make sure the index file is there
$indexFile = $dir . '/index.html';
@mkdir($dir) && file_put_contents($indexFile, '<!DOCTYPE
html><title></title>');
}
// Make sure the folder exists
if (!is_dir($dir))
{
return false;
}
static::$CacheLiteInstance->setOption('cacheDir',
$this->_root . '/' . $group . '/');
// This call is needed to ensure $this->rawname is set
$this->_getCacheId($id, $group);
return static::$CacheLiteInstance->save($data, $this->rawname,
$group);
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function remove($id, $group)
{
static::$CacheLiteInstance->setOption('cacheDir',
$this->_root . '/' . $group . '/');
// This call is needed to ensure $this->rawname is set
$this->_getCacheId($id, $group);
return static::$CacheLiteInstance->remove($this->rawname, $group);
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 1.7.0
*/
public function clean($group, $mode = null)
{
\JLoader::import('joomla.filesystem.folder');
\JLoader::import('joomla.filesystem.file');
switch ($mode)
{
case 'notgroup':
$clmode = 'notingroup';
$success = static::$CacheLiteInstance->clean($group, $clmode);
break;
case 'group':
if (is_dir($this->_root . '/' . $group))
{
$clmode = $group;
static::$CacheLiteInstance->setOption('cacheDir',
$this->_root . '/' . $group . '/');
$success = static::$CacheLiteInstance->clean($group, $clmode);
// Remove sub-folders of folder; disable all filtering
$folders = \JFolder::folders($this->_root . '/' . $group,
'.', false, true, array(), array());
foreach ($folders as $folder)
{
if (is_link($folder))
{
if (\JFile::delete($folder) !== true)
{
return false;
}
}
elseif (\JFolder::delete($folder) !== true)
{
return false;
}
}
}
else
{
$success = true;
}
break;
default:
if (is_dir($this->_root . '/' . $group))
{
$clmode = $group;
static::$CacheLiteInstance->setOption('cacheDir',
$this->_root . '/' . $group . '/');
$success = static::$CacheLiteInstance->clean($group, $clmode);
}
else
{
$success = true;
}
break;
}
return $success;
}
/**
* Garbage collect expired cache data
*
* @return boolean
*
* @since 1.7.0
*/
public function gc()
{
$result = true;
static::$CacheLiteInstance->setOption('automaticCleaningFactor',
1);
static::$CacheLiteInstance->setOption('hashedDirectoryLevel',
1);
$success1 = static::$CacheLiteInstance->_cleanDir($this->_root .
'/', false, 'old');
if (!($dh = opendir($this->_root . '/')))
{
return false;
}
while ($file = readdir($dh))
{
if (($file != '.') && ($file != '..')
&& ($file != '.svn'))
{
$file2 = $this->_root . '/' . $file;
if (is_dir($file2))
{
$result = ($result &&
(static::$CacheLiteInstance->_cleanDir($file2 . '/', false,
'old')));
}
}
}
$success = ($success1 && $result);
return $success;
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.0.0
*/
public static function isSupported()
{
@include_once 'Cache/Lite.php';
return class_exists('\Cache_Lite');
}
}
CacheStorageHelper.php000064400000002027151157453270010760 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
/**
* Cache storage helper functions.
*
* @since 1.7.0
*/
class CacheStorageHelper
{
/**
* Cache data group
*
* @var string
* @since 1.7.0
*/
public $group = '';
/**
* Cached item size
*
* @var string
* @since 1.7.0
*/
public $size = 0;
/**
* Counter
*
* @var integer
* @since 1.7.0
*/
public $count = 0;
/**
* Constructor
*
* @param string $group The cache data group
*
* @since 1.7.0
*/
public function __construct($group)
{
$this->group = $group;
}
/**
* Increase cache items count.
*
* @param string $size Cached item size
*
* @return void
*
* @since 1.7.0
*/
public function updateSize($size)
{
$this->size += $size;
$this->count++;
}
}
FileStorage.php000064400000042040151157453270007473 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheStorage;
use Joomla\CMS\Log\Log;
/**
* File cache storage handler
*
* @since 1.7.0
* @note For performance reasons this class does not use the Filesystem
package's API
*/
class FileStorage extends CacheStorage
{
/**
* Root path
*
* @var string
* @since 1.7.0
*/
protected $_root;
/**
* Locked resources
*
* @var array
* @since 3.7.0
*
*/
protected $_locked_files = array();
/**
* Constructor
*
* @param array $options Optional parameters
*
* @since 1.7.0
*/
public function __construct($options = array())
{
parent::__construct($options);
$this->_root = $options['cachebase'];
// Workaround for php 5.3
$locked_files = &$this->_locked_files;
// Remove empty locked files at script shutdown.
$clearAtShutdown = function () use (&$locked_files)
{
foreach ($locked_files as $path => $handle)
{
if (is_resource($handle))
{
@flock($handle, LOCK_UN);
@fclose($handle);
}
// Delete only the existing file if it is empty.
if (@filesize($path) === 0)
{
@unlink($path);
}
unset($locked_files[$path]);
}
};
register_shutdown_function($clearAtShutdown);
}
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
return $this->_checkExpire($id, $group);
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function get($id, $group, $checkTime = true)
{
$path = $this->_getFilePath($id, $group);
$close = false;
if ($checkTime == false || ($checkTime == true &&
$this->_checkExpire($id, $group) === true))
{
if (file_exists($path))
{
if (isset($this->_locked_files[$path]))
{
$_fileopen = $this->_locked_files[$path];
}
else
{
$_fileopen = @fopen($path, 'rb');
// There is no lock, we have to close file after store data
$close = true;
}
if ($_fileopen)
{
// On Windows system we can not use file_get_contents on the file
locked by yourself
$data = stream_get_contents($_fileopen);
if ($close)
{
@fclose($_fileopen);
}
if ($data !== false)
{
// Remove the initial die() statement
return str_replace('<?php die("Access Denied");
?>#x#', '', $data);
}
}
}
}
return false;
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function getAll()
{
$path = $this->_root;
$folders = $this->_folders($path);
$data = array();
foreach ($folders as $folder)
{
$files = $this->_filesInFolder($path . '/' . $folder);
$item = new CacheStorageHelper($folder);
foreach ($files as $file)
{
$item->updateSize(filesize($path . '/' . $folder .
'/' . $file));
}
$data[$folder] = $item;
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 1.7.0
*/
public function store($id, $group, $data)
{
$path = $this->_getFilePath($id, $group);
$close = false;
// Prepend a die string
$data = '<?php die("Access Denied"); ?>#x#' .
$data;
if (isset($this->_locked_files[$path]))
{
$_fileopen = $this->_locked_files[$path];
// Because lock method uses flag c+b we have to truncate it manually
@ftruncate($_fileopen, 0);
}
else
{
$_fileopen = @fopen($path, 'wb');
// There is no lock, we have to close file after store data
$close = true;
}
if ($_fileopen)
{
$length = strlen($data);
$result = @fwrite($_fileopen, $data, $length);
if ($close)
{
@fclose($_fileopen);
}
return $result === $length;
}
return false;
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function remove($id, $group)
{
$path = $this->_getFilePath($id, $group);
if (!@unlink($path))
{
return false;
}
return true;
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 1.7.0
*/
public function clean($group, $mode = null)
{
$return = true;
$folder = $group;
if (trim($folder) == '')
{
$mode = 'notgroup';
}
switch ($mode)
{
case 'notgroup' :
$folders = $this->_folders($this->_root);
for ($i = 0, $n = count($folders); $i < $n; $i++)
{
if ($folders[$i] != $folder)
{
$return |= $this->_deleteFolder($this->_root . '/' .
$folders[$i]);
}
}
break;
case 'group' :
default :
if (is_dir($this->_root . '/' . $folder))
{
$return = $this->_deleteFolder($this->_root . '/' .
$folder);
}
break;
}
return (bool) $return;
}
/**
* Garbage collect expired cache data
*
* @return boolean
*
* @since 1.7.0
*/
public function gc()
{
$result = true;
// Files older than lifeTime get deleted from cache
$files = $this->_filesInFolder($this->_root, '', true,
true, array('.svn', 'CVS', '.DS_Store',
'__MACOSX', 'index.html'));
foreach ($files as $file)
{
$time = @filemtime($file);
if (($time + $this->_lifetime) < $this->_now || empty($time))
{
$result |= @unlink($file);
}
}
return (bool) $result;
}
/**
* Lock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param integer $locktime Cached item max lock time
*
* @return mixed Boolean false if locking failed or an object containing
properties lock and locklooped
*
* @since 1.7.0
*/
public function lock($id, $group, $locktime)
{
$returning = new \stdClass;
$returning->locklooped = false;
$looptime = $locktime * 10;
$path = $this->_getFilePath($id, $group);
$_fileopen = @fopen($path, 'c+b');
if (!$_fileopen)
{
$returning->locked = false;
return $returning;
}
$data_lock = (bool) @flock($_fileopen, LOCK_EX|LOCK_NB);
if ($data_lock === false)
{
$lock_counter = 0;
// Loop until you find that the lock has been released.
// That implies that data get from other thread has finished
while ($data_lock === false)
{
if ($lock_counter > $looptime)
{
break;
}
usleep(100);
$data_lock = (bool) @flock($_fileopen, LOCK_EX|LOCK_NB);
$lock_counter++;
}
$returning->locklooped = true;
}
if ($data_lock === true)
{
// Remember resource, flock release lock if you unset/close resource
$this->_locked_files[$path] = $_fileopen;
}
$returning->locked = $data_lock;
return $returning;
}
/**
* Unlock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function unlock($id, $group = null)
{
$path = $this->_getFilePath($id, $group);
if (isset($this->_locked_files[$path]))
{
$ret = (bool) @flock($this->_locked_files[$path], LOCK_UN);
@fclose($this->_locked_files[$path]);
unset($this->_locked_files[$path]);
return $ret;
}
return true;
}
/**
* Check if a cache object has expired
*
* Using @ error suppressor here because between if we did a file_exists()
and then filemsize() there will
* be a little time space when another process can delete the file and
then you get PHP Warning
*
* @param string $id Cache ID to check
* @param string $group The cache data group
*
* @return boolean True if the cache ID is valid
*
* @since 1.7.0
*/
protected function _checkExpire($id, $group)
{
$path = $this->_getFilePath($id, $group);
// Check prune period
if (file_exists($path))
{
$time = @filemtime($path);
if (($time + $this->_lifetime) < $this->_now || empty($time))
{
@unlink($path);
return false;
}
// If, right now, the file does not exist then return false
if (@filesize($path) == 0)
{
return false;
}
return true;
}
return false;
}
/**
* Get a cache file path from an ID/group pair
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean|string The path to the data object or boolean false
if the cache directory does not exist
*
* @since 1.7.0
*/
protected function _getFilePath($id, $group)
{
$name = $this->_getCacheId($id, $group);
$dir = $this->_root . '/' . $group;
// If the folder doesn't exist try to create it
if (!is_dir($dir))
{
// Make sure the index file is there
$indexFile = $dir . '/index.html';
@mkdir($dir) && file_put_contents($indexFile, '<!DOCTYPE
html><title></title>');
}
// Make sure the folder exists
if (!is_dir($dir))
{
return false;
}
return $dir . '/' . $name . '.php';
}
/**
* Quickly delete a folder of files
*
* @param string $path The path to the folder to delete.
*
* @return boolean
*
* @since 1.7.0
*/
protected function _deleteFolder($path)
{
// Sanity check
if (!$path || !is_dir($path) || empty($this->_root))
{
// Bad programmer! Bad, bad programmer!
Log::add(__METHOD__ . ' ' .
\JText::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY'),
Log::WARNING, 'jerror');
return false;
}
$path = $this->_cleanPath($path);
// Check to make sure path is inside cache folder, we do not want to
delete Joomla root!
$pos = strpos($path, $this->_cleanPath($this->_root));
if ($pos === false || $pos > 0)
{
Log::add(__METHOD__ . ' ' .
\JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER',
$path), Log::WARNING, 'jerror');
return false;
}
// Remove all the files in folder if they exist; disable all filtering
$files = $this->_filesInFolder($path, '.', false, true,
array(), array());
if (!empty($files) && !is_array($files))
{
if (@unlink($files) !== true)
{
return false;
}
}
elseif (!empty($files) && is_array($files))
{
foreach ($files as $file)
{
$file = $this->_cleanPath($file);
// In case of restricted permissions we zap it one way or the other as
long as the owner is either the webserver or the ftp
if (@unlink($file) !== true)
{
Log::add(__METHOD__ . ' ' .
\JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED',
basename($file)), Log::WARNING, 'jerror');
return false;
}
}
}
// Remove sub-folders of folder; disable all filtering
$folders = $this->_folders($path, '.', false, true, array(),
array());
foreach ($folders as $folder)
{
if (is_link($folder))
{
// Don't descend into linked directories, just delete the link.
if (@unlink($folder) !== true)
{
return false;
}
}
elseif ($this->_deleteFolder($folder) !== true)
{
return false;
}
}
// In case of restricted permissions we zap it one way or the other as
long as the owner is either the webserver or the ftp
if (@rmdir($path))
{
return true;
}
Log::add(__METHOD__ . ' ' .
\JText::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE', $path),
Log::WARNING, 'jerror');
return false;
}
/**
* Function to strip additional / or \ in a path name
*
* @param string $path The path to clean
* @param string $ds Directory separator (optional)
*
* @return string The cleaned path
*
* @since 1.7.0
*/
protected function _cleanPath($path, $ds = DIRECTORY_SEPARATOR)
{
$path = trim($path);
if (empty($path))
{
return $this->_root;
}
// Remove double slashes and backslahses and convert all slashes and
backslashes to DIRECTORY_SEPARATOR
$path = preg_replace('#[/\\\\]+#', $ds, $path);
return $path;
}
/**
* Utility function to quickly read the files in a folder.
*
* @param string $path The path of the folder to read.
* @param string $filter A filter for file names.
* @param mixed $recurse True to recursively search into
sub-folders, or an integer to specify the maximum depth.
* @param boolean $fullpath True to return the full path to the
file.
* @param array $exclude Array with names of files which
should not be shown in the result.
* @param array $excludefilter Array of folder names to exclude
*
* @return array Files in the given folder.
*
* @since 1.7.0
*/
protected function _filesInFolder($path, $filter = '.', $recurse
= false, $fullpath = false,
$exclude = array('.svn', 'CVS',
'.DS_Store', '__MACOSX'), $excludefilter =
array('^\..*', '.*~'))
{
$arr = array();
// Check to make sure the path valid and clean
$path = $this->_cleanPath($path);
// Is the path a folder?
if (!is_dir($path))
{
Log::add(__METHOD__ . ' ' .
\JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER',
$path), Log::WARNING, 'jerror');
return false;
}
// Read the source directory.
if (!($handle = @opendir($path)))
{
return $arr;
}
if (count($excludefilter))
{
$excludefilter = '/(' . implode('|', $excludefilter)
. ')/';
}
else
{
$excludefilter = '';
}
while (($file = readdir($handle)) !== false)
{
if (($file != '.') && ($file != '..')
&& (!in_array($file, $exclude)) && (!$excludefilter ||
!preg_match($excludefilter, $file)))
{
$dir = $path . '/' . $file;
$isDir = is_dir($dir);
if ($isDir)
{
if ($recurse)
{
if (is_int($recurse))
{
$arr2 = $this->_filesInFolder($dir, $filter, $recurse - 1,
$fullpath);
}
else
{
$arr2 = $this->_filesInFolder($dir, $filter, $recurse,
$fullpath);
}
$arr = array_merge($arr, $arr2);
}
}
else
{
if (preg_match("/$filter/", $file))
{
if ($fullpath)
{
$arr[] = $path . '/' . $file;
}
else
{
$arr[] = $file;
}
}
}
}
}
closedir($handle);
return $arr;
}
/**
* Utility function to read the folders in a folder.
*
* @param string $path The path of the folder to read.
* @param string $filter A filter for folder names.
* @param mixed $recurse True to recursively search into
sub-folders, or an integer to specify the maximum depth.
* @param boolean $fullpath True to return the full path to the
folders.
* @param array $exclude Array with names of folders which
should not be shown in the result.
* @param array $excludefilter Array with regular expressions
matching folders which should not be shown in the result.
*
* @return array Folders in the given folder.
*
* @since 1.7.0
*/
protected function _folders($path, $filter = '.', $recurse =
false, $fullpath = false, $exclude = array('.svn',
'CVS', '.DS_Store', '__MACOSX'),
$excludefilter = array('^\..*'))
{
$arr = array();
// Check to make sure the path valid and clean
$path = $this->_cleanPath($path);
// Is the path a folder?
if (!is_dir($path))
{
Log::add(__METHOD__ . ' ' .
\JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER',
$path), Log::WARNING, 'jerror');
return false;
}
// Read the source directory
if (!($handle = @opendir($path)))
{
return $arr;
}
if (count($excludefilter))
{
$excludefilter_string = '/(' . implode('|',
$excludefilter) . ')/';
}
else
{
$excludefilter_string = '';
}
while (($file = readdir($handle)) !== false)
{
if (($file != '.') && ($file != '..')
&& (!in_array($file, $exclude))
&& (empty($excludefilter_string) ||
!preg_match($excludefilter_string, $file)))
{
$dir = $path . '/' . $file;
$isDir = is_dir($dir);
if ($isDir)
{
// Removes filtered directories
if (preg_match("/$filter/", $file))
{
if ($fullpath)
{
$arr[] = $dir;
}
else
{
$arr[] = $file;
}
}
if ($recurse)
{
if (is_int($recurse))
{
$arr2 = $this->_folders($dir, $filter, $recurse - 1, $fullpath,
$exclude, $excludefilter);
}
else
{
$arr2 = $this->_folders($dir, $filter, $recurse, $fullpath,
$exclude, $excludefilter);
}
$arr = array_merge($arr, $arr2);
}
}
}
}
closedir($handle);
return $arr;
}
}
MemcachedStorage.php000064400000023273151157453270010471 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Cache\CacheStorage;
use Joomla\CMS\Cache\Exception\CacheConnectingException;
/**
* Memcached cache storage handler
*
* @link https://www.php.net/manual/en/book.memcached.php
* @since 3.0.0
*/
class MemcachedStorage extends CacheStorage
{
/**
* Memcached connection object
*
* @var \Memcached
* @since 3.0.0
*/
protected static $_db = null;
/**
* Payload compression level
*
* @var integer
* @since 3.0.0
*/
protected $_compress = 0;
/**
* Constructor
*
* @param array $options Optional parameters.
*
* @since 3.0.0
*/
public function __construct($options = array())
{
parent::__construct($options);
$this->_compress =
\JFactory::getConfig()->get('memcached_compress', false) ?
\Memcached::OPT_COMPRESSION : 0;
if (static::$_db === null)
{
$this->getConnection();
}
}
/**
* Create the Memcached connection
*
* @return void
*
* @since 3.0.0
* @throws \RuntimeException
*/
protected function getConnection()
{
if (!static::isSupported())
{
throw new \RuntimeException('Memcached Extension is not
available');
}
$config = \JFactory::getConfig();
$host = $config->get('memcached_server_host',
'localhost');
$port = $config->get('memcached_server_port', 11211);
// Create the memcached connection
if ($config->get('memcached_persist', true))
{
static::$_db = new \Memcached($this->_hash);
$servers = static::$_db->getServerList();
if ($servers && ($servers[0]['host'] != $host ||
$servers[0]['port'] != $port))
{
static::$_db->resetServerList();
$servers = array();
}
if (!$servers)
{
static::$_db->addServer($host, $port);
}
}
else
{
static::$_db = new \Memcached;
static::$_db->addServer($host, $port);
}
static::$_db->setOption(\Memcached::OPT_COMPRESSION,
$this->_compress);
$stats = static::$_db->getStats();
$result = !empty($stats["$host:$port"]) &&
$stats["$host:$port"]['pid'] > 0;
if (!$result)
{
// Null out the connection to inform the constructor it will need to
attempt to connect if this class is instantiated again
static::$_db = null;
throw new CacheConnectingException('Could not connect to memcached
server');
}
}
/**
* Get a cache_id string from an id/group pair
*
* @param string $id The cache data id
* @param string $group The cache data group
*
* @return string The cache_id string
*
* @since 1.7.0
*/
protected function _getCacheId($id, $group)
{
$prefix = Cache::getPlatformPrefix();
$length = strlen($prefix);
$cache_id = parent::_getCacheId($id, $group);
if ($length)
{
// Memcached use suffix instead of prefix
$cache_id = substr($cache_id, $length) . strrev($prefix);
}
return $cache_id;
}
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
static::$_db->get($this->_getCacheId($id, $group));
return static::$_db->getResultCode() !== \Memcached::RES_NOTFOUND;
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 3.0.0
*/
public function get($id, $group, $checkTime = true)
{
return static::$_db->get($this->_getCacheId($id, $group));
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 3.0.0
*/
public function getAll()
{
$keys = static::$_db->get($this->_hash . '-index');
$secret = $this->_hash;
$data = array();
if (is_array($keys))
{
foreach ($keys as $key)
{
if (empty($key))
{
continue;
}
$namearr = explode('-', $key->name);
if ($namearr !== false && $namearr[0] == $secret &&
$namearr[1] == 'cache')
{
$group = $namearr[2];
if (!isset($data[$group]))
{
$item = new CacheStorageHelper($group);
}
else
{
$item = $data[$group];
}
$item->updateSize($key->size);
$data[$group] = $item;
}
}
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 3.0.0
*/
public function store($id, $group, $data)
{
$cache_id = $this->_getCacheId($id, $group);
if (!$this->lockindex())
{
return false;
}
$index = static::$_db->get($this->_hash . '-index');
if (!is_array($index))
{
$index = array();
}
$tmparr = new \stdClass;
$tmparr->name = $cache_id;
$tmparr->size = strlen($data);
$index[] = $tmparr;
static::$_db->set($this->_hash . '-index', $index, 0);
$this->unlockindex();
static::$_db->set($cache_id, $data, $this->_lifetime);
return true;
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.0.0
*/
public function remove($id, $group)
{
$cache_id = $this->_getCacheId($id, $group);
if (!$this->lockindex())
{
return false;
}
$index = static::$_db->get($this->_hash . '-index');
if (is_array($index))
{
foreach ($index as $key => $value)
{
if ($value->name == $cache_id)
{
unset($index[$key]);
static::$_db->set($this->_hash . '-index', $index, 0);
break;
}
}
}
$this->unlockindex();
return static::$_db->delete($cache_id);
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 3.0.0
*/
public function clean($group, $mode = null)
{
if (!$this->lockindex())
{
return false;
}
$index = static::$_db->get($this->_hash . '-index');
if (is_array($index))
{
$prefix = $this->_hash . '-cache-' . $group .
'-';
foreach ($index as $key => $value)
{
if (strpos($value->name, $prefix) === 0 xor $mode !=
'group')
{
static::$_db->delete($value->name);
unset($index[$key]);
}
}
static::$_db->set($this->_hash . '-index', $index, 0);
}
$this->unlockindex();
return true;
}
/**
* Flush all existing items in storage.
*
* @return boolean
*
* @since 3.6.3
*/
public function flush()
{
if (!$this->lockindex())
{
return false;
}
return static::$_db->flush();
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.0.0
*/
public static function isSupported()
{
/*
* GAE and HHVM have both had instances where Memcached the class was
defined but no extension was loaded.
* If the class is there, we can assume support.
*/
return class_exists('Memcached');
}
/**
* Lock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param integer $locktime Cached item max lock time
*
* @return mixed Boolean false if locking failed or an object containing
properties lock and locklooped
*
* @since 3.0.0
*/
public function lock($id, $group, $locktime)
{
$returning = new \stdClass;
$returning->locklooped = false;
$looptime = $locktime * 10;
$cache_id = $this->_getCacheId($id, $group);
$data_lock = static::$_db->add($cache_id . '_lock', 1,
$locktime);
if ($data_lock === false)
{
$lock_counter = 0;
// Loop until you find that the lock has been released.
// That implies that data get from other thread has finished.
while ($data_lock === false)
{
if ($lock_counter > $looptime)
{
break;
}
usleep(100);
$data_lock = static::$_db->add($cache_id . '_lock', 1,
$locktime);
$lock_counter++;
}
$returning->locklooped = true;
}
$returning->locked = $data_lock;
return $returning;
}
/**
* Unlock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.0.0
*/
public function unlock($id, $group = null)
{
$cache_id = $this->_getCacheId($id, $group) . '_lock';
return static::$_db->delete($cache_id);
}
/**
* Lock cache index
*
* @return boolean
*
* @since 3.0.0
*/
protected function lockindex()
{
$looptime = 300;
$data_lock = static::$_db->add($this->_hash .
'-index_lock', 1, 30);
if ($data_lock === false)
{
$lock_counter = 0;
// Loop until you find that the lock has been released. that implies
that data get from other thread has finished
while ($data_lock === false)
{
if ($lock_counter > $looptime)
{
return false;
}
usleep(100);
$data_lock = static::$_db->add($this->_hash .
'-index_lock', 1, 30);
$lock_counter++;
}
}
return true;
}
/**
* Unlock cache index
*
* @return boolean
*
* @since 3.0.0
*/
protected function unlockindex()
{
return static::$_db->delete($this->_hash .
'-index_lock');
}
}
MemcacheStorage.php000064400000022155151157453270010323 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Cache\CacheStorage;
use Joomla\CMS\Cache\Exception\CacheConnectingException;
/**
* Memcache cache storage handler
*
* @link https://www.php.net/manual/en/book.memcache.php
* @since 1.7.0
* @deprecated 4.0 Use the Memcached handler instead
*/
class MemcacheStorage extends CacheStorage
{
/**
* Memcache connection object
*
* @var \Memcache
* @since 1.7.0
*/
protected static $_db = null;
/**
* Payload compression level
*
* @var integer
* @since 1.7.0
*/
protected $_compress = 0;
/**
* Constructor
*
* @param array $options Optional parameters.
*
* @since 1.7.0
*/
public function __construct($options = array())
{
parent::__construct($options);
$this->_compress =
\JFactory::getConfig()->get('memcache_compress', false) ?
MEMCACHE_COMPRESSED : 0;
if (static::$_db === null)
{
$this->getConnection();
}
}
/**
* Create the Memcache connection
*
* @return void
*
* @since 1.7.0
* @throws \RuntimeException
*/
protected function getConnection()
{
if (!static::isSupported())
{
throw new \RuntimeException('Memcache Extension is not
available');
}
$config = \JFactory::getConfig();
$host = $config->get('memcache_server_host',
'localhost');
$port = $config->get('memcache_server_port', 11211);
// Create the memcache connection
static::$_db = new \Memcache;
if ($config->get('memcache_persist', true))
{
$result = @static::$_db->pconnect($host, $port);
}
else
{
$result = @static::$_db->connect($host, $port);
}
if (!$result)
{
// Null out the connection to inform the constructor it will need to
attempt to connect if this class is instantiated again
static::$_db = null;
throw new CacheConnectingException('Could not connect to memcache
server');
}
}
/**
* Get a cache_id string from an id/group pair
*
* @param string $id The cache data id
* @param string $group The cache data group
*
* @return string The cache_id string
*
* @since 1.7.0
*/
protected function _getCacheId($id, $group)
{
$prefix = Cache::getPlatformPrefix();
$length = strlen($prefix);
$cache_id = parent::_getCacheId($id, $group);
if ($length)
{
// Memcache use suffix instead of prefix
$cache_id = substr($cache_id, $length) . strrev($prefix);
}
return $cache_id;
}
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
return $this->get($id, $group) !== false;
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function get($id, $group, $checkTime = true)
{
return static::$_db->get($this->_getCacheId($id, $group));
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function getAll()
{
$keys = static::$_db->get($this->_hash . '-index');
$secret = $this->_hash;
$data = array();
if (is_array($keys))
{
foreach ($keys as $key)
{
if (empty($key))
{
continue;
}
$namearr = explode('-', $key->name);
if ($namearr !== false && $namearr[0] == $secret &&
$namearr[1] == 'cache')
{
$group = $namearr[2];
if (!isset($data[$group]))
{
$item = new CacheStorageHelper($group);
}
else
{
$item = $data[$group];
}
$item->updateSize($key->size);
$data[$group] = $item;
}
}
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 1.7.0
*/
public function store($id, $group, $data)
{
$cache_id = $this->_getCacheId($id, $group);
if (!$this->lockindex())
{
return false;
}
$index = static::$_db->get($this->_hash . '-index');
if (!is_array($index))
{
$index = array();
}
$tmparr = new \stdClass;
$tmparr->name = $cache_id;
$tmparr->size = strlen($data);
$index[] = $tmparr;
static::$_db->set($this->_hash . '-index', $index, 0, 0);
$this->unlockindex();
static::$_db->set($cache_id, $data, $this->_compress,
$this->_lifetime);
return true;
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function remove($id, $group)
{
$cache_id = $this->_getCacheId($id, $group);
if (!$this->lockindex())
{
return false;
}
$index = static::$_db->get($this->_hash . '-index');
if (is_array($index))
{
foreach ($index as $key => $value)
{
if ($value->name == $cache_id)
{
unset($index[$key]);
static::$_db->set($this->_hash . '-index', $index, 0,
0);
break;
}
}
}
$this->unlockindex();
return static::$_db->delete($cache_id);
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 1.7.0
*/
public function clean($group, $mode = null)
{
if (!$this->lockindex())
{
return false;
}
$index = static::$_db->get($this->_hash . '-index');
if (is_array($index))
{
$prefix = $this->_hash . '-cache-' . $group .
'-';
foreach ($index as $key => $value)
{
if (strpos($value->name, $prefix) === 0 xor $mode !=
'group')
{
static::$_db->delete($value->name);
unset($index[$key]);
}
}
static::$_db->set($this->_hash . '-index', $index, 0,
0);
}
$this->unlockindex();
return true;
}
/**
* Flush all existing items in storage.
*
* @return boolean
*
* @since 3.6.3
*/
public function flush()
{
if (!$this->lockindex())
{
return false;
}
return static::$_db->flush();
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.0.0
*/
public static function isSupported()
{
return extension_loaded('memcache') &&
class_exists('\\Memcache');
}
/**
* Lock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param integer $locktime Cached item max lock time
*
* @return mixed Boolean false if locking failed or an object containing
properties lock and locklooped
*
* @since 1.7.0
*/
public function lock($id, $group, $locktime)
{
$returning = new \stdClass;
$returning->locklooped = false;
$looptime = $locktime * 10;
$cache_id = $this->_getCacheId($id, $group);
$data_lock = static::$_db->add($cache_id . '_lock', 1, 0,
$locktime);
if ($data_lock === false)
{
$lock_counter = 0;
// Loop until you find that the lock has been released.
// That implies that data get from other thread has finished.
while ($data_lock === false)
{
if ($lock_counter > $looptime)
{
break;
}
usleep(100);
$data_lock = static::$_db->add($cache_id . '_lock', 1, 0,
$locktime);
$lock_counter++;
}
$returning->locklooped = true;
}
$returning->locked = $data_lock;
return $returning;
}
/**
* Unlock cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function unlock($id, $group = null)
{
$cache_id = $this->_getCacheId($id, $group) . '_lock';
return static::$_db->delete($cache_id);
}
/**
* Lock cache index
*
* @return boolean
*
* @since 1.7.0
*/
protected function lockindex()
{
$looptime = 300;
$data_lock = static::$_db->add($this->_hash .
'-index_lock', 1, 0, 30);
if ($data_lock === false)
{
$lock_counter = 0;
// Loop until you find that the lock has been released. that implies
that data get from other thread has finished
while ($data_lock === false)
{
if ($lock_counter > $looptime)
{
return false;
}
usleep(100);
$data_lock = static::$_db->add($this->_hash .
'-index_lock', 1, 0, 30);
$lock_counter++;
}
}
return true;
}
/**
* Unlock cache index
*
* @return boolean
*
* @since 1.7.0
*/
protected function unlockindex()
{
return static::$_db->delete($this->_hash .
'-index_lock');
}
}
RedisStorage.php000064400000016710151157453270007667 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheStorage;
use Joomla\CMS\Log\Log;
/**
* Redis cache storage handler for PECL
*
* @since 3.4
*/
class RedisStorage extends CacheStorage
{
/**
* Redis connection object
*
* @var \Redis
* @since 3.4
*/
protected static $_redis = null;
/**
* Persistent session flag
*
* @var boolean
* @since 3.4
*/
protected $_persistent = false;
/**
* Constructor
*
* @param array $options Optional parameters.
*
* @since 3.4
*/
public function __construct($options = array())
{
parent::__construct($options);
if (static::$_redis === null)
{
$this->getConnection();
}
}
/**
* Create the Redis connection
*
* @return \Redis|boolean Redis connection object on success, boolean on
failure
*
* @since 3.4
* @note As of 4.0 this method will throw a JCacheExceptionConnecting
object on connection failure
*/
protected function getConnection()
{
if (static::isSupported() == false)
{
return false;
}
$config = \JFactory::getConfig();
$this->_persistent = $config->get('redis_persist', true);
$server = array(
'host' => $config->get('redis_server_host',
'localhost'),
'port' => $config->get('redis_server_port',
6379),
'auth' => $config->get('redis_server_auth',
null),
'db' => (int)
$config->get('redis_server_db', null),
);
// If you are trying to connect to a socket file, ignore the supplied
port
if ($server['host'][0] === '/')
{
$server['port'] = 0;
}
static::$_redis = new \Redis;
try
{
if ($this->_persistent)
{
$connection = static::$_redis->pconnect($server['host'],
$server['port']);
}
else
{
$connection = static::$_redis->connect($server['host'],
$server['port']);
}
}
catch (\RedisException $e)
{
Log::add($e->getMessage(), Log::DEBUG);
}
if ($connection == false)
{
static::$_redis = null;
// Because the application instance may not be available on cli script,
use it only if needed
if (\JFactory::getApplication()->isClient('administrator'))
{
\JError::raiseWarning(500, 'Redis connection failed');
}
return false;
}
try
{
$auth = $server['auth'] ?
static::$_redis->auth($server['auth']) : true;
}
catch (\RedisException $e)
{
$auth = false;
Log::add($e->getMessage(), Log::DEBUG);
}
if ($auth === false)
{
static::$_redis = null;
// Because the application instance may not be available on cli script,
use it only if needed
if (\JFactory::getApplication()->isClient('administrator'))
{
\JError::raiseWarning(500, 'Redis authentication failed');
}
return false;
}
$select = static::$_redis->select($server['db']);
if ($select == false)
{
static::$_redis = null;
// Because the application instance may not be available on cli script,
use it only if needed
if (\JFactory::getApplication()->isClient('administrator'))
{
\JError::raiseWarning(500, 'Redis failed to select
database');
}
return false;
}
try
{
static::$_redis->ping();
}
catch (\RedisException $e)
{
static::$_redis = null;
// Because the application instance may not be available on cli script,
use it only if needed
if (\JFactory::getApplication()->isClient('administrator'))
{
\JError::raiseWarning(500, 'Redis ping failed');
}
return false;
}
return static::$_redis;
}
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
if (static::isConnected() == false)
{
return false;
}
// Redis exists returns integer values lets convert that to boolean see:
https://redis.io/commands/exists
return (bool) static::$_redis->exists($this->_getCacheId($id,
$group));
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 3.4
*/
public function get($id, $group, $checkTime = true)
{
if (static::isConnected() == false)
{
return false;
}
return static::$_redis->get($this->_getCacheId($id, $group));
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 3.4
*/
public function getAll()
{
if (static::isConnected() == false)
{
return false;
}
$allKeys = static::$_redis->keys('*');
$data = array();
$secret = $this->_hash;
if (!empty($allKeys))
{
foreach ($allKeys as $key)
{
$namearr = explode('-', $key);
if ($namearr !== false && $namearr[0] == $secret &&
$namearr[1] == 'cache')
{
$group = $namearr[2];
if (!isset($data[$group]))
{
$item = new CacheStorageHelper($group);
}
else
{
$item = $data[$group];
}
$item->updateSize(strlen($key)*8);
$data[$group] = $item;
}
}
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 3.4
*/
public function store($id, $group, $data)
{
if (static::isConnected() == false)
{
return false;
}
static::$_redis->setex($this->_getCacheId($id, $group),
$this->_lifetime, $data);
return true;
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.4
*/
public function remove($id, $group)
{
if (static::isConnected() == false)
{
return false;
}
return (bool) static::$_redis->del($this->_getCacheId($id,
$group));
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 3.4
*/
public function clean($group, $mode = null)
{
if (static::isConnected() == false)
{
return false;
}
$allKeys = static::$_redis->keys('*');
if ($allKeys === false)
{
$allKeys = array();
}
$secret = $this->_hash;
foreach ($allKeys as $key)
{
if (strpos($key, $secret . '-cache-' . $group . '-')
=== 0 && $mode == 'group')
{
static::$_redis->del($key);
}
if (strpos($key, $secret . '-cache-' . $group . '-')
!== 0 && $mode != 'group')
{
static::$_redis->del($key);
}
}
return true;
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.4
*/
public static function isSupported()
{
return class_exists('\\Redis');
}
/**
* Test to see if the Redis connection is available.
*
* @return boolean
*
* @since 3.4
*/
public static function isConnected()
{
return static::$_redis instanceof \Redis;
}
}
WincacheStorage.php000064400000010221151157453270010331 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheStorage;
/**
* WinCache cache storage handler
*
* @link https://www.php.net/manual/en/book.wincache.php
* @since 1.7.0
*/
class WincacheStorage extends CacheStorage
{
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
return wincache_ucache_exists($this->_getCacheId($id, $group));
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function get($id, $group, $checkTime = true)
{
return wincache_ucache_get($this->_getCacheId($id, $group));
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function getAll()
{
$allinfo = wincache_ucache_info();
$keys = $allinfo['ucache_entries'];
$secret = $this->_hash;
$data = array();
foreach ($keys as $key)
{
$name = $key['key_name'];
$namearr = explode('-', $name);
if ($namearr !== false && $namearr[0] == $secret &&
$namearr[1] == 'cache')
{
$group = $namearr[2];
if (!isset($data[$group]))
{
$item = new CacheStorageHelper($group);
}
else
{
$item = $data[$group];
}
if (isset($key['value_size']))
{
$item->updateSize($key['value_size']);
}
else
{
// Dummy, WINCACHE version is too low.
$item->updateSize(1);
}
$data[$group] = $item;
}
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 1.7.0
*/
public function store($id, $group, $data)
{
return wincache_ucache_set($this->_getCacheId($id, $group), $data,
$this->_lifetime);
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function remove($id, $group)
{
return wincache_ucache_delete($this->_getCacheId($id, $group));
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 1.7.0
*/
public function clean($group, $mode = null)
{
$allinfo = wincache_ucache_info();
$keys = $allinfo['ucache_entries'];
$secret = $this->_hash;
foreach ($keys as $key)
{
if (strpos($key['key_name'], $secret . '-cache-' .
$group . '-') === 0 xor $mode != 'group')
{
wincache_ucache_delete($key['key_name']);
}
}
return true;
}
/**
* Garbage collect expired cache data
*
* @return boolean
*
* @since 1.7.0
*/
public function gc()
{
$allinfo = wincache_ucache_info();
$keys = $allinfo['ucache_entries'];
$secret = $this->_hash;
foreach ($keys as $key)
{
if (strpos($key['key_name'], $secret . '-cache-'))
{
wincache_ucache_get($key['key_name']);
}
}
return true;
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.0.0
*/
public static function isSupported()
{
return extension_loaded('wincache') &&
function_exists('wincache_ucache_get') &&
!strcmp(ini_get('wincache.ucenabled'), '1');
}
}
XcacheStorage.php000064400000011745151157453270010017 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Cache\Storage;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheStorage;
/**
* XCache cache storage handler
*
* @link https://xcache.lighttpd.net/
* @since 1.7.0
* @deprecated 4.0 The XCache PHP extension is not compatible with PHP 7
*/
class XcacheStorage extends CacheStorage
{
/**
* Check if the cache contains data stored by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 3.7.0
*/
public function contains($id, $group)
{
return xcache_isset($this->_getCacheId($id, $group));
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $checkTime True to verify cache time expiration
threshold
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function get($id, $group, $checkTime = true)
{
// Make sure XCache is configured properly
if (static::isSupported() == false)
{
return false;
}
$cache_id = $this->_getCacheId($id, $group);
$cache_content = xcache_get($cache_id);
if ($cache_content === null)
{
return false;
}
return $cache_content;
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
* @note This requires the php.ini setting xcache.admin.enable_auth =
Off.
*/
public function getAll()
{
// Make sure XCache is configured properly
if (static::isSupported() == false)
{
return array();
}
$allinfo = xcache_list(XC_TYPE_VAR, 0);
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
$data = array();
foreach ($keys as $key)
{
$namearr = explode('-', $key['name']);
if ($namearr !== false && $namearr[0] == $secret &&
$namearr[1] == 'cache')
{
$group = $namearr[2];
if (!isset($data[$group]))
{
$item = new CacheStorageHelper($group);
}
else
{
$item = $data[$group];
}
$item->updateSize($key['size']);
$data[$group] = $item;
}
}
return $data;
}
/**
* Store the data to cache by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $data The data to store in cache
*
* @return boolean
*
* @since 1.7.0
*/
public function store($id, $group, $data)
{
// Make sure XCache is configured properly
if (static::isSupported() == false)
{
return false;
}
return xcache_set($this->_getCacheId($id, $group), $data,
$this->_lifetime);
}
/**
* Remove a cached data entry by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function remove($id, $group)
{
// Make sure XCache is configured properly
if (static::isSupported() == false)
{
return false;
}
$cache_id = $this->_getCacheId($id, $group);
if (!xcache_isset($cache_id))
{
return true;
}
return xcache_unset($cache_id);
}
/**
* Clean cache for a group given a mode.
*
* group mode : cleans all cache in the group
* notgroup mode : cleans all cache not in the group
*
* @param string $group The cache data group
* @param string $mode The mode for cleaning cache [group|notgroup]
*
* @return boolean
*
* @since 1.7.0
*/
public function clean($group, $mode = null)
{
// Make sure XCache is configured properly
if (static::isSupported() == false)
{
return true;
}
$allinfo = xcache_list(XC_TYPE_VAR, 0);
$keys = $allinfo['cache_list'];
$secret = $this->_hash;
foreach ($keys as $key)
{
if (strpos($key['name'], $secret . '-cache-' .
$group . '-') === 0 xor $mode != 'group')
{
xcache_unset($key['name']);
}
}
return true;
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.0.0
*/
public static function isSupported()
{
if (extension_loaded('xcache'))
{
// XCache Admin must be disabled for Joomla to use XCache
$xcache_admin_enable_auth =
ini_get('xcache.admin.enable_auth');
// Some extensions ini variables are reported as strings
if ($xcache_admin_enable_auth == 'Off')
{
return true;
}
// We require a string with contents 0, not a null value because it is
not set since that then defaults to On/True
if ($xcache_admin_enable_auth === '0')
{
return true;
}
// In some enviorments empty is equivalent to Off; See JC: #34044
&& Github: #4083
if ($xcache_admin_enable_auth === '')
{
return true;
}
}
// If the settings are not correct, give up
return false;
}
}