Spade
Mini Shell
| Directory:~$ /home/lmsyaran/public_html/joomla4/ |
| [Home] [System Details] [Kill Me] |
PK]6�[�]QDIDI Cache.phpnu�[���<?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;
defined('JPATH_PLATFORM') or die;
use Joomla\Application\Web\WebClient;
use Joomla\CMS\Cache\Exception\CacheExceptionInterface;
use Joomla\String\StringHelper;
/**
* Joomla! Cache base object
*
* @since 1.7.0
*/
class Cache
{
/**
* Storage handler
*
* @var CacheStorage[]
* @since 1.7.0
*/
public static $_handler = array();
/**
* Cache options
*
* @var array
* @since 1.7.0
*/
public $_options;
/**
* Constructor
*
* @param array $options Cache options
*
* @since 1.7.0
*/
public function __construct($options)
{
$conf = \JFactory::getConfig();
$this->_options = array(
'cachebase' => $conf->get('cache_path',
JPATH_CACHE),
'lifetime' => (int)
$conf->get('cachetime'),
'language' => $conf->get('language',
'en-GB'),
'storage' => $conf->get('cache_handler',
''),
'defaultgroup' => 'default',
'locking' => true,
'locktime' => 15,
'checkTime' => true,
'caching' => ($conf->get('caching') >=
1) ? true : false,
);
// Overwrite default options with given options
foreach ($options as $option => $value)
{
if (isset($options[$option]) && $options[$option] !==
'')
{
$this->_options[$option] = $options[$option];
}
}
if (empty($this->_options['storage']))
{
$this->setCaching(false);
}
}
/**
* Returns a reference to a cache adapter object, always creating it
*
* @param string $type The cache object type to instantiate
* @param array $options The array of options
*
* @return CacheController
*
* @since 1.7.0
*/
public static function getInstance($type = 'output', $options =
array())
{
return CacheController::getInstance($type, $options);
}
/**
* Get the storage handlers
*
* @return array
*
* @since 1.7.0
*/
public static function getStores()
{
$handlers = array();
// Get an iterator and loop trough the driver classes.
$iterator = new \DirectoryIterator(__DIR__ . '/Storage');
/** @type $file \DirectoryIterator */
foreach ($iterator as $file)
{
$fileName = $file->getFilename();
// Only load for php files.
if (!$file->isFile() || $file->getExtension() != 'php'
|| $fileName == 'CacheStorageHelper.php')
{
continue;
}
// Derive the class name from the type.
$class = str_ireplace('.php', '', __NAMESPACE__ .
'\\Storage\\' . ucfirst(trim($fileName)));
// If the class doesn't exist we have nothing left to do but look
at the next type. We did our best.
if (!class_exists($class))
{
continue;
}
// Sweet! Our class exists, so now we just need to know if it passes
its test method.
if ($class::isSupported())
{
// Connector names should not have file extensions.
$handler = str_ireplace('Storage.php', '',
$fileName);
$handler = str_ireplace('.php', '', $handler);
$handlers[] = strtolower($handler);
}
}
return $handlers;
}
/**
* Set caching enabled state
*
* @param boolean $enabled True to enable caching
*
* @return void
*
* @since 1.7.0
*/
public function setCaching($enabled)
{
$this->_options['caching'] = $enabled;
}
/**
* Get caching state
*
* @return boolean
*
* @since 1.7.0
*/
public function getCaching()
{
return $this->_options['caching'];
}
/**
* Set cache lifetime
*
* @param integer $lt Cache lifetime
*
* @return void
*
* @since 1.7.0
*/
public function setLifeTime($lt)
{
$this->_options['lifetime'] = $lt;
}
/**
* 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 = null)
{
if (!$this->getCaching())
{
return false;
}
// Get the default group
$group = $group ?: $this->_options['defaultgroup'];
return $this->_getStorage()->contains($id, $group);
}
/**
* Get cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function get($id, $group = null)
{
if (!$this->getCaching())
{
return false;
}
// Get the default group
$group = $group ?: $this->_options['defaultgroup'];
return $this->_getStorage()->get($id, $group,
$this->_options['checkTime']);
}
/**
* Get a list of all cached data
*
* @return mixed Boolean false on failure or an object with a list of
cache groups and data
*
* @since 1.7.0
*/
public function getAll()
{
if (!$this->getCaching())
{
return false;
}
return $this->_getStorage()->getAll();
}
/**
* Store the cached data by ID and group
*
* @param mixed $data The data to store
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
*/
public function store($data, $id, $group = null)
{
if (!$this->getCaching())
{
return false;
}
// Get the default group
$group = $group ?: $this->_options['defaultgroup'];
// Get the storage and store the cached data
return $this->_getStorage()->store($id, $group, $data);
}
/**
* 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 = null)
{
// Get the default group
$group = $group ?: $this->_options['defaultgroup'];
try
{
return $this->_getStorage()->remove($id, $group);
}
catch (CacheExceptionInterface $e)
{
if (!$this->getCaching())
{
return false;
}
throw $e;
}
}
/**
* 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 True on success, false otherwise
*
* @since 1.7.0
*/
public function clean($group = null, $mode = 'group')
{
// Get the default group
$group = $group ?: $this->_options['defaultgroup'];
try
{
return $this->_getStorage()->clean($group, $mode);
}
catch (CacheExceptionInterface $e)
{
if (!$this->getCaching())
{
return false;
}
throw $e;
}
}
/**
* Garbage collect expired cache data
*
* @return boolean
*
* @since 1.7.0
*/
public function gc()
{
try
{
return $this->_getStorage()->gc();
}
catch (CacheExceptionInterface $e)
{
if (!$this->getCaching())
{
return false;
}
throw $e;
}
}
/**
* Set lock flag on cached item
*
* @param string $id The cache data ID
* @param string $group The cache data group
* @param string $locktime The default locktime for locking the cache.
*
* @return \stdClass Object with properties of lock and locklooped
*
* @since 1.7.0
*/
public function lock($id, $group = null, $locktime = null)
{
$returning = new \stdClass;
$returning->locklooped = false;
if (!$this->getCaching())
{
$returning->locked = false;
return $returning;
}
// Get the default group
$group = $group ?: $this->_options['defaultgroup'];
// Get the default locktime
$locktime = $locktime ?: $this->_options['locktime'];
/*
* Allow storage handlers to perform locking on their own
* NOTE drivers with lock need also unlock or unlocking will fail because
of false $id
*/
$handler = $this->_getStorage();
if ($this->_options['locking'] == true)
{
$locked = $handler->lock($id, $group, $locktime);
if ($locked !== false)
{
return $locked;
}
}
// Fallback
$curentlifetime = $this->_options['lifetime'];
// Set lifetime to locktime for storing in children
$this->_options['lifetime'] = $locktime;
$looptime = $locktime * 10;
$id2 = $id . '_lock';
if ($this->_options['locking'] == true)
{
$data_lock = $handler->get($id2, $group,
$this->_options['checkTime']);
}
else
{
$data_lock = false;
$returning->locked = false;
}
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 = $handler->get($id2, $group,
$this->_options['checkTime']);
$lock_counter++;
}
}
if ($this->_options['locking'] == true)
{
$returning->locked = $handler->store($id2, $group, 1);
}
// Revert lifetime to previous one
$this->_options['lifetime'] = $curentlifetime;
return $returning;
}
/**
* Unset lock flag on 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)
{
if (!$this->getCaching())
{
return false;
}
// Get the default group
$group = $group ?: $this->_options['defaultgroup'];
// Allow handlers to perform unlocking on their own
$handler = $this->_getStorage();
$unlocked = $handler->unlock($id, $group);
if ($unlocked !== false)
{
return $unlocked;
}
// Fallback
return $handler->remove($id . '_lock', $group);
}
/**
* Get the cache storage handler
*
* @return CacheStorage
*
* @since 1.7.0
*/
public function &_getStorage()
{
$hash = md5(serialize($this->_options));
if (isset(self::$_handler[$hash]))
{
return self::$_handler[$hash];
}
self::$_handler[$hash] =
CacheStorage::getInstance($this->_options['storage'],
$this->_options);
return self::$_handler[$hash];
}
/**
* Perform workarounds on retrieved cached data
*
* @param string $data Cached data
* @param array $options Array of options
*
* @return string Body of cached data
*
* @since 1.7.0
*/
public static function getWorkarounds($data, $options = array())
{
$app = \JFactory::getApplication();
$document = \JFactory::getDocument();
$body = null;
// Get the document head out of the cache.
if (isset($options['mergehead']) &&
$options['mergehead'] == 1 &&
isset($data['head']) && !empty($data['head'])
&& method_exists($document, 'mergeHeadData'))
{
$document->mergeHeadData($data['head']);
}
elseif (isset($data['head']) &&
method_exists($document, 'setHeadData'))
{
$document->setHeadData($data['head']);
}
// Get the document MIME encoding out of the cache
if (isset($data['mime_encoding']))
{
$document->setMimeEncoding($data['mime_encoding'], true);
}
// If the pathway buffer is set in the cache data, get it.
if (isset($data['pathway']) &&
is_array($data['pathway']))
{
// Push the pathway data into the pathway object.
$app->getPathway()->setPathway($data['pathway']);
}
// @todo check if the following is needed, seems like it should be in
page cache
// If a module buffer is set in the cache data, get it.
if (isset($data['module']) &&
is_array($data['module']))
{
// Iterate through the module positions and push them into the document
buffer.
foreach ($data['module'] as $name => $contents)
{
$document->setBuffer($contents, 'module', $name);
}
}
// Set cached headers.
if (isset($data['headers']) &&
$data['headers'])
{
foreach ($data['headers'] as $header)
{
$app->setHeader($header['name'],
$header['value']);
}
}
// The following code searches for a token in the cached page and
replaces it with the proper token.
if (isset($data['body']))
{
$token = \JSession::getFormToken();
$search = '#<input type="hidden"
name="[0-9a-f]{32}" value="1" />#';
$replacement = '<input type="hidden" name="'
. $token . '" value="1" />';
$data['body'] = preg_replace($search, $replacement,
$data['body']);
$body = $data['body'];
}
// Get the document body out of the cache.
return $body;
}
/**
* Create workarounds for data to be cached
*
* @param string $data Cached data
* @param array $options Array of options
*
* @return string Data to be cached
*
* @since 1.7.0
*/
public static function setWorkarounds($data, $options = array())
{
$loptions = array(
'nopathway' => 0,
'nohead' => 0,
'nomodules' => 0,
'modulemode' => 0,
);
if (isset($options['nopathway']))
{
$loptions['nopathway'] = $options['nopathway'];
}
if (isset($options['nohead']))
{
$loptions['nohead'] = $options['nohead'];
}
if (isset($options['nomodules']))
{
$loptions['nomodules'] = $options['nomodules'];
}
if (isset($options['modulemode']))
{
$loptions['modulemode'] = $options['modulemode'];
}
$app = \JFactory::getApplication();
$document = \JFactory::getDocument();
if ($loptions['nomodules'] != 1)
{
// Get the modules buffer before component execution.
$buffer1 = $document->getBuffer();
if (!is_array($buffer1))
{
$buffer1 = array();
}
// Make sure the module buffer is an array.
if (!isset($buffer1['module']) ||
!is_array($buffer1['module']))
{
$buffer1['module'] = array();
}
}
// View body data
$cached['body'] = $data;
// Document head data
if ($loptions['nohead'] != 1 &&
method_exists($document, 'getHeadData'))
{
if ($loptions['modulemode'] == 1)
{
$headnow = $document->getHeadData();
$unset = array('title', 'description',
'link', 'links', 'metaTags');
foreach ($unset as $un)
{
unset($headnow[$un]);
unset($options['headerbefore'][$un]);
}
$cached['head'] = array();
// Only store what this module has added
foreach ($headnow as $now => $value)
{
if (isset($options['headerbefore'][$now]))
{
// We have to serialize the content of the arrays because the may
contain other arrays which is a notice in PHP 5.4 and newer
$nowvalue = array_map('serialize', $headnow[$now]);
$beforevalue = array_map('serialize',
$options['headerbefore'][$now]);
$newvalue = array_diff_assoc($nowvalue, $beforevalue);
$newvalue = array_map('unserialize', $newvalue);
// Special treatment for script and style declarations.
if (($now == 'script' || $now == 'style')
&& is_array($newvalue) &&
is_array($options['headerbefore'][$now]))
{
foreach ($newvalue as $type => $currentScriptStr)
{
if
(isset($options['headerbefore'][$now][strtolower($type)]))
{
$oldScriptStr =
$options['headerbefore'][$now][strtolower($type)];
if ($oldScriptStr != $currentScriptStr)
{
// Save only the appended declaration.
$newvalue[strtolower($type)] =
StringHelper::substr($currentScriptStr,
StringHelper::strlen($oldScriptStr));
}
}
}
}
}
else
{
$newvalue = $headnow[$now];
}
if (!empty($newvalue))
{
$cached['head'][$now] = $newvalue;
}
}
}
else
{
$cached['head'] = $document->getHeadData();
}
}
// Document MIME encoding
$cached['mime_encoding'] = $document->getMimeEncoding();
// Pathway data
if ($app->isClient('site') &&
$loptions['nopathway'] != 1)
{
$cached['pathway'] = is_array($data) &&
isset($data['pathway']) ? $data['pathway'] :
$app->getPathway()->getPathway();
}
if ($loptions['nomodules'] != 1)
{
// @todo Check if the following is needed, seems like it should be in
page cache
// Get the module buffer after component execution.
$buffer2 = $document->getBuffer();
if (!is_array($buffer2))
{
$buffer2 = array();
}
// Make sure the module buffer is an array.
if (!isset($buffer2['module']) ||
!is_array($buffer2['module']))
{
$buffer2['module'] = array();
}
// Compare the second module buffer against the first buffer.
$cached['module'] =
array_diff_assoc($buffer2['module'],
$buffer1['module']);
}
// Headers data
if (isset($options['headers']) &&
$options['headers'])
{
$cached['headers'] = $app->getHeaders();
}
return $cached;
}
/**
* Create a safe ID for cached data from URL parameters
*
* @return string MD5 encoded cache ID
*
* @since 1.7.0
*/
public static function makeId()
{
$app = \JFactory::getApplication();
$registeredurlparams = new \stdClass;
// Get url parameters set by plugins
if (!empty($app->registeredurlparams))
{
$registeredurlparams = $app->registeredurlparams;
}
// Platform defaults
$defaulturlparams = array(
'format' => 'WORD',
'option' => 'WORD',
'view' => 'WORD',
'layout' => 'WORD',
'tpl' => 'CMD',
'id' => 'INT',
);
// Use platform defaults if parameter doesn't already exist.
foreach ($defaulturlparams as $param => $type)
{
if (!property_exists($registeredurlparams, $param))
{
$registeredurlparams->$param = $type;
}
}
$safeuriaddon = new \stdClass;
foreach ($registeredurlparams as $key => $value)
{
$safeuriaddon->$key = $app->input->get($key, null, $value);
}
return md5(serialize($safeuriaddon));
}
/**
* Set a prefix cache key if device calls for separate caching
*
* @return string
*
* @since 3.5
*/
public static function getPlatformPrefix()
{
// No prefix when Global Config is set to no platfom specific prefix
if (!\JFactory::getConfig()->get('cache_platformprefix',
'0'))
{
return '';
}
$webclient = new WebClient;
if ($webclient->mobile)
{
return 'M-';
}
return '';
}
/**
* Add a directory where Cache should search for handlers. You may either
pass a string or an array of directories.
*
* @param array|string $path A path to search.
*
* @return array An array with directory elements
*
* @since 1.7.0
*/
public static function addIncludePath($path = '')
{
static $paths;
if (!isset($paths))
{
$paths = array();
}
if (!empty($path) && !in_array($path, $paths))
{
\JLoader::import('joomla.filesystem.path');
array_unshift($paths, \JPath::clean($path));
}
return $paths;
}
}
PK]6�[�ss22CacheController.phpnu�[���<?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;
defined('JPATH_PLATFORM') or die;
/**
* Public cache handler
*
* @since 1.7.0
* @note As of 4.0 this class will be abstract
*/
class CacheController
{
/**
* Cache object
*
* @var Cache
* @since 1.7.0
*/
public $cache;
/**
* Array of options
*
* @var array
* @since 1.7.0
*/
public $options;
/**
* Constructor
*
* @param array $options Array of options
*
* @since 1.7.0
*/
public function __construct($options)
{
$this->cache = new Cache($options);
$this->options = & $this->cache->_options;
// Overwrite default options with given options
foreach ($options as $option => $value)
{
if (isset($options[$option]))
{
$this->options[$option] = $options[$option];
}
}
}
/**
* Magic method to proxy CacheController method calls to Cache
*
* @param string $name Name of the function
* @param array $arguments Array of arguments for the function
*
* @return mixed
*
* @since 1.7.0
*/
public function __call($name, $arguments)
{
return call_user_func_array(array($this->cache, $name), $arguments);
}
/**
* Returns a reference to a cache adapter object, always creating it
*
* @param string $type The cache object type to instantiate;
default is output.
* @param array $options Array of options
*
* @return CacheController
*
* @since 1.7.0
* @throws \RuntimeException
*/
public static function getInstance($type = 'output', $options =
array())
{
self::addIncludePath(__DIR__ . '/Controller');
$type = strtolower(preg_replace('/[^A-Z0-9_\.-]/i',
'', $type));
$class = __NAMESPACE__ . '\\Controller\\' . ucfirst($type) .
'Controller';
if (!class_exists($class))
{
$class = 'JCacheController' . ucfirst($type);
}
if (!class_exists($class))
{
// Search for the class file in the Cache include paths.
\JLoader::import('joomla.filesystem.path');
$path = \JPath::find(self::addIncludePath(), strtolower($type) .
'.php');
if ($path !== false)
{
\JLoader::register($class, $path);
}
// The class should now be loaded
if (!class_exists($class))
{
throw new \RuntimeException('Unable to load Cache Controller:
' . $type, 500);
}
}
return new $class($options);
}
/**
* Add a directory where Cache should search for controllers. You may
either pass a string or an array of directories.
*
* @param array|string $path A path to search.
*
* @return array An array with directory elements
*
* @since 1.7.0
*/
public static function addIncludePath($path = '')
{
static $paths;
if (!isset($paths))
{
$paths = array();
}
if (!empty($path) && !in_array($path, $paths))
{
\JLoader::import('joomla.filesystem.path');
array_unshift($paths, \JPath::clean($path));
}
return $paths;
}
/**
* Get stored cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return mixed Boolean false on no result, cached object otherwise
*
* @since 1.7.0
* @deprecated 4.0 Implement own method in subclass
*/
public function get($id, $group = null)
{
$data = $this->cache->get($id, $group);
if ($data === false)
{
$locktest = $this->cache->lock($id, $group);
// If locklooped is true try to get the cached data again; it could
exist now.
if ($locktest->locked === true && $locktest->locklooped
=== true)
{
$data = $this->cache->get($id, $group);
}
if ($locktest->locked === true)
{
$this->cache->unlock($id, $group);
}
}
// Check again because we might get it from second attempt
if ($data !== false)
{
// Trim to fix unserialize errors
$data = unserialize(trim($data));
}
return $data;
}
/**
* Store data to cache by ID and group
*
* @param mixed $data The data to store
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $wrkarounds True to use wrkarounds
*
* @return boolean True if cache stored
*
* @since 1.7.0
* @deprecated 4.0 Implement own method in subclass
*/
public function store($data, $id, $group = null, $wrkarounds = true)
{
$locktest = $this->cache->lock($id, $group);
if ($locktest->locked === false && $locktest->locklooped
=== true)
{
// We can not store data because another process is in the middle of
saving
return false;
}
$result = $this->cache->store(serialize($data), $id, $group);
if ($locktest->locked === true)
{
$this->cache->unlock($id, $group);
}
return $result;
}
}
PK]6�[����!�!CacheStorage.phpnu�[���<?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;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\Exception\UnsupportedCacheException;
use Joomla\CMS\Log\Log;
/**
* Abstract cache storage handler
*
* @since 1.7.0
* @note As of 4.0 this class will be abstract
*/
class CacheStorage
{
/**
* The raw object name
*
* @var string
* @since 1.7.0
*/
protected $rawname;
/**
* Time that the cache storage handler was instantiated
*
* @var integer
* @since 1.7.0
*/
public $_now;
/**
* Cache lifetime
*
* @var integer
* @since 1.7.0
*/
public $_lifetime;
/**
* Flag if locking is enabled
*
* @var boolean
* @since 1.7.0
*/
public $_locking;
/**
* Language code
*
* @var string
* @since 1.7.0
*/
public $_language;
/**
* Application name
*
* @var string
* @since 1.7.0
*/
public $_application;
/**
* Object hash
*
* @var string
* @since 1.7.0
*/
public $_hash;
/**
* Constructor
*
* @param array $options Optional parameters
*
* @since 1.7.0
*/
public function __construct($options = array())
{
$config = \JFactory::getConfig();
$this->_hash = md5($config->get('secret'));
$this->_application = (isset($options['application'])) ?
$options['application'] : md5(JPATH_CONFIGURATION);
$this->_language = (isset($options['language'])) ?
$options['language'] : 'en-GB';
$this->_locking = (isset($options['locking'])) ?
$options['locking'] : true;
$this->_lifetime = (isset($options['lifetime'])) ?
$options['lifetime'] * 60 :
$config->get('cachetime') * 60;
$this->_now = (isset($options['now'])) ?
$options['now'] : time();
// Set time threshold value. If the lifetime is not set, default to 60
(0 is BAD)
// _threshold is now available ONLY as a legacy (it's deprecated).
It's no longer used in the core.
if (empty($this->_lifetime))
{
$this->_threshold = $this->_now - 60;
$this->_lifetime = 60;
}
else
{
$this->_threshold = $this->_now - $this->_lifetime;
}
}
/**
* Returns a cache storage handler object.
*
* @param string $handler The cache storage handler to instantiate
* @param array $options Array of handler options
*
* @return CacheStorage
*
* @since 1.7.0
* @throws \UnexpectedValueException
* @throws UnsupportedCacheException
*/
public static function getInstance($handler = null, $options = array())
{
static $now = null;
// @deprecated 4.0 This class path is autoloaded, manual inclusion is
no longer necessary
self::addIncludePath(__DIR__ . '/Storage');
if (!isset($handler))
{
$handler = \JFactory::getConfig()->get('cache_handler');
if (empty($handler))
{
throw new \UnexpectedValueException('Cache Storage Handler not
set.');
}
}
if (is_null($now))
{
$now = time();
}
$options['now'] = $now;
// We can't cache this since options may change...
$handler = strtolower(preg_replace('/[^A-Z0-9_\.-]/i',
'', $handler));
/** @var CacheStorage $class */
$class = __NAMESPACE__ . '\\Storage\\' . ucfirst($handler) .
'Storage';
if (!class_exists($class))
{
$class = 'JCacheStorage' . ucfirst($handler);
}
if (!class_exists($class))
{
// Search for the class file in the JCacheStorage include paths.
\JLoader::import('joomla.filesystem.path');
$path = \JPath::find(self::addIncludePath(), strtolower($handler) .
'.php');
if ($path === false)
{
throw new UnsupportedCacheException(sprintf('Unable to load Cache
Storage: %s', $handler));
}
\JLoader::register($class, $path);
// The class should now be loaded
if (!class_exists($class))
{
throw new UnsupportedCacheException(sprintf('Unable to load Cache
Storage: %s', $handler));
}
}
// Validate the cache storage is supported on this platform
if (!$class::isSupported())
{
throw new UnsupportedCacheException(sprintf('The %s Cache Storage
is not supported on this platform.', $handler));
}
return new $class($options);
}
/**
* 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 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 false;
}
/**
* Get all cached data
*
* @return mixed Boolean false on failure or a cached data object
*
* @since 1.7.0
*/
public function getAll()
{
return false;
}
/**
* 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 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)
{
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;
}
/**
* Flush all existing items in storage.
*
* @return boolean
*
* @since 3.6.3
*/
public function flush()
{
return true;
}
/**
* Garbage collect expired cache data
*
* @return boolean
*
* @since 1.7.0
*/
public function gc()
{
return true;
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 3.0.0
*/
public static function isSupported()
{
return true;
}
/**
* Test to see if the storage handler is available.
*
* @return boolean
*
* @since 1.7.0
* @deprecated 4.0
*/
public static function test()
{
Log::add(__METHOD__ . '() is deprecated. Use
CacheStorage::isSupported() instead.', Log::WARNING,
'deprecated');
return static::isSupported();
}
/**
* 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)
{
return false;
}
/**
* 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 false;
}
/**
* 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
*
* @since 1.7.0
*/
protected function _getCacheId($id, $group)
{
$name = md5($this->_application . '-' . $id .
'-' . $this->_language);
$this->rawname = $this->_hash . '-' . $name;
return Cache::getPlatformPrefix() . $this->_hash . '-cache-'
. $group . '-' . $name;
}
/**
* Add a directory where CacheStorage should search for handlers. You may
either pass a string or an array of directories.
*
* @param array|string $path A path to search.
*
* @return array An array with directory elements
*
* @since 1.7.0
*/
public static function addIncludePath($path = '')
{
static $paths;
if (!isset($paths))
{
$paths = array();
}
if (!empty($path) && !in_array($path, $paths))
{
\JLoader::import('joomla.filesystem.path');
array_unshift($paths, \JPath::clean($path));
}
return $paths;
}
}
PK]6�[�
o�!Controller/CallbackController.phpnu�[���<?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\Controller;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Cache\CacheController;
/**
* Joomla! Cache callback type object
*
* @since 1.7.0
*/
class CallbackController extends CacheController
{
/**
* Executes a cacheable callback if not found in cache else returns cached
output and result
*
* Since arguments to this function are read with func_get_args you can
pass any number of arguments to this method
* as long as the first argument passed is the callback definition.
*
* The callback definition can be in several forms:
* - Standard PHP Callback array see <https://www.php.net/callback>
[recommended]
* - Function name as a string eg. 'foo' for function foo()
* - Static method name as a string eg. 'MyClass::myMethod' for
method myMethod() of class MyClass
*
* @return mixed Result of the callback
*
* @since 1.7.0
* @deprecated 4.0
*/
public function call()
{
// Get callback and arguments
$args = func_get_args();
$callback = array_shift($args);
return $this->get($callback, $args);
}
/**
* Executes a cacheable callback if not found in cache else returns cached
output and result
*
* @param mixed $callback Callback or string shorthand for a
callback
* @param array $args Callback arguments
* @param mixed $id Cache ID
* @param boolean $wrkarounds True to use workarounds
* @param array $woptions Workaround options
*
* @return mixed Result of the callback
*
* @since 1.7.0
*/
public function get($callback, $args = array(), $id = false, $wrkarounds =
false, $woptions = array())
{
// Normalize callback
if (is_array($callback) || is_callable($callback))
{
// We have a standard php callback array -- do nothing
}
elseif (strstr($callback, '::'))
{
// This is shorthand for a static method callback classname::methodname
list ($class, $method) = explode('::', $callback);
$callback = array(trim($class), trim($method));
}
elseif (strstr($callback, '->'))
{
/*
* This is a really not so smart way of doing this... we provide this
for backward compatibility but this
* WILL! disappear in a future version. If you are using this syntax
change your code to use the standard
* PHP callback array syntax: <https://www.php.net/callback>
*
* We have to use some silly global notation to pull it off and this is
very unreliable
*/
list ($object_123456789, $method) = explode('->',
$callback);
global $$object_123456789;
$callback = array($$object_123456789, $method);
}
if (!$id)
{
// Generate an ID
$id = $this->_makeId($callback, $args);
}
$data = $this->cache->get($id);
$locktest = (object) array('locked' => null,
'locklooped' => null);
if ($data === false)
{
$locktest = $this->cache->lock($id);
// If locklooped is true try to get the cached data again; it could
exist now.
if ($locktest->locked === true && $locktest->locklooped
=== true)
{
$data = $this->cache->get($id);
}
}
if ($data !== false)
{
if ($locktest->locked === true)
{
$this->cache->unlock($id);
}
$data = unserialize(trim($data));
if ($wrkarounds)
{
echo Cache::getWorkarounds(
$data['output'],
array('mergehead' =>
isset($woptions['mergehead']) ? $woptions['mergehead']
: 0)
);
}
else
{
echo $data['output'];
}
return $data['result'];
}
if (!is_array($args))
{
$referenceArgs = !empty($args) ? array(&$args) : array();
}
else
{
$referenceArgs = &$args;
}
if ($locktest->locked === false && $locktest->locklooped
=== true)
{
// We can not store data because another process is in the middle of
saving
return call_user_func_array($callback, $referenceArgs);
}
$coptions = array();
if (isset($woptions['modulemode']) &&
$woptions['modulemode'] == 1)
{
$document = \JFactory::getDocument();
if (method_exists($document, 'getHeadData'))
{
$coptions['headerbefore'] = $document->getHeadData();
}
$coptions['modulemode'] = 1;
}
else
{
$coptions['modulemode'] = 0;
}
$coptions['nopathway'] =
isset($woptions['nopathway']) ? $woptions['nopathway']
: 1;
$coptions['nohead'] = isset($woptions['nohead'])
? $woptions['nohead'] : 1;
$coptions['nomodules'] =
isset($woptions['nomodules']) ? $woptions['nomodules']
: 1;
ob_start();
ob_implicit_flush(false);
$result = call_user_func_array($callback, $referenceArgs);
$output = ob_get_clean();
$data = array('result' => $result);
if ($wrkarounds)
{
$data['output'] = Cache::setWorkarounds($output, $coptions);
}
else
{
$data['output'] = $output;
}
// Store the cache data
$this->cache->store(serialize($data), $id);
if ($locktest->locked === true)
{
$this->cache->unlock($id);
}
echo $output;
return $result;
}
/**
* Generate a callback cache ID
*
* @param callback $callback Callback to cache
* @param array $args Arguments to the callback method to cache
*
* @return string MD5 Hash
*
* @since 1.7.0
*/
protected function _makeId($callback, $args)
{
if (is_array($callback) && is_object($callback[0]))
{
$vars = get_object_vars($callback[0]);
$vars[] = strtolower(get_class($callback[0]));
$callback[0] = $vars;
}
// A Closure can't be serialized, so to generate the ID we'll
need to get its hash
if (is_a($callback, 'closure'))
{
$hash = spl_object_hash($callback);
return md5($hash . serialize(array($args)));
}
return md5(serialize(array($callback, $args)));
}
}
PK]6�[�~
��Controller/OutputController.phpnu�[���<?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\Controller;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\CacheController;
use Joomla\CMS\Log\Log;
/**
* Joomla Cache output type object
*
* @since 1.7.0
*/
class OutputController extends CacheController
{
/**
* Cache data ID
*
* @var string
* @since 1.7.0
*/
protected $_id;
/**
* Cache data group
*
* @var string
* @since 1.7.0
*/
protected $_group;
/**
* Object to test locked state
*
* @var \stdClass
* @since 1.7.0
* @deprecated 4.0
*/
protected $_locktest = null;
/**
* Start the cache
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return boolean
*
* @since 1.7.0
* @deprecated 4.0
*/
public function start($id, $group = null)
{
Log::add(
__METHOD__ . '() is deprecated.',
Log::WARNING,
'deprecated'
);
// If we have data in cache use that.
$data = $this->cache->get($id, $group);
$this->_locktest = new \stdClass;
$this->_locktest->locked = null;
$this->_locktest->locklooped = null;
if ($data === false)
{
$this->_locktest = $this->cache->lock($id, $group);
if ($this->_locktest->locked == true &&
$this->_locktest->locklooped == true)
{
$data = $this->cache->get($id, $group);
}
}
if ($data !== false)
{
$data = unserialize(trim($data));
echo $data;
if ($this->_locktest->locked == true)
{
$this->cache->unlock($id, $group);
}
return true;
}
// Nothing in cache... let's start the output buffer and start
collecting data for next time.
if ($this->_locktest->locked == false)
{
$this->_locktest = $this->cache->lock($id, $group);
}
ob_start();
ob_implicit_flush(false);
// Set id and group placeholders
$this->_id = $id;
$this->_group = $group;
return false;
}
/**
* Stop the cache buffer and store the cached data
*
* @return boolean True if the cache data was stored
*
* @since 1.7.0
* @deprecated 4.0
*/
public function end()
{
Log::add(
__METHOD__ . '() is deprecated.',
Log::WARNING,
'deprecated'
);
// Get data from output buffer and echo it
$data = ob_get_clean();
echo $data;
// Get the ID and group and reset the placeholders
$id = $this->_id;
$group = $this->_group;
$this->_id = null;
$this->_group = null;
// Get the storage handler and store the cached data
$ret = $this->cache->store(serialize($data), $id, $group);
if ($this->_locktest->locked == true)
{
$this->cache->unlock($id, $group);
}
return $ret;
}
/**
* Get stored cached data by ID and group
*
* @param string $id The cache data ID
* @param string $group The cache data group
*
* @return mixed Boolean false on no result, cached object otherwise
*
* @since 1.7.0
*/
public function get($id, $group = null)
{
$data = $this->cache->get($id, $group);
if ($data === false)
{
$locktest = $this->cache->lock($id, $group);
// If locklooped is true try to get the cached data again; it could
exist now.
if ($locktest->locked === true && $locktest->locklooped
=== true)
{
$data = $this->cache->get($id, $group);
}
if ($locktest->locked === true)
{
$this->cache->unlock($id, $group);
}
}
// Check again because we might get it from second attempt
if ($data !== false)
{
// Trim to fix unserialize errors
$data = unserialize(trim($data));
}
return $data;
}
/**
* Store data to cache by ID and group
*
* @param mixed $data The data to store
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $wrkarounds True to use wrkarounds
*
* @return boolean True if cache stored
*
* @since 1.7.0
*/
public function store($data, $id, $group = null, $wrkarounds = true)
{
$locktest = $this->cache->lock($id, $group);
if ($locktest->locked === false && $locktest->locklooped
=== true)
{
// We can not store data because another process is in the middle of
saving
return false;
}
$result = $this->cache->store(serialize($data), $id, $group);
if ($locktest->locked === true)
{
$this->cache->unlock($id, $group);
}
return $result;
}
}
PK]6�[;g�
DDController/PageController.phpnu�[���<?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\Controller;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Cache\CacheController;
/**
* Joomla! Cache page type object
*
* @since 1.7.0
*/
class PageController extends CacheController
{
/**
* ID property for the cache page object.
*
* @var integer
* @since 1.7.0
*/
protected $_id;
/**
* Cache group
*
* @var string
* @since 1.7.0
*/
protected $_group;
/**
* Cache lock test
*
* @var \stdClass
* @since 1.7.0
*/
protected $_locktest = null;
/**
* Get the cached page data
*
* @param boolean $id The cache data ID
* @param string $group The cache data group
*
* @return mixed Boolean false on no result, cached object otherwise
*
* @since 1.7.0
*/
public function get($id = false, $group = 'page')
{
// If an id is not given, generate it from the request
if (!$id)
{
$id = $this->_makeId();
}
// If the etag matches the page id ... set a no change header and exit :
utilize browser cache
if (!headers_sent() &&
isset($_SERVER['HTTP_IF_NONE_MATCH']))
{
$etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
if ($etag == $id)
{
$browserCache = isset($this->options['browsercache']) ?
$this->options['browsercache'] : false;
if ($browserCache)
{
$this->_noChange();
}
}
}
// We got a cache hit... set the etag header and echo the page data
$data = $this->cache->get($id, $group);
$this->_locktest = (object) array('locked' => null,
'locklooped' => null);
if ($data === false)
{
$this->_locktest = $this->cache->lock($id, $group);
// If locklooped is true try to get the cached data again; it could
exist now.
if ($this->_locktest->locked === true &&
$this->_locktest->locklooped === true)
{
$data = $this->cache->get($id, $group);
}
}
if ($data !== false)
{
if ($this->_locktest->locked === true)
{
$this->cache->unlock($id, $group);
}
$data = unserialize(trim($data));
$data = Cache::getWorkarounds($data);
$this->_setEtag($id);
return $data;
}
// Set ID and group placeholders
$this->_id = $id;
$this->_group = $group;
return false;
}
/**
* Stop the cache buffer and store the cached data
*
* @param mixed $data The data to store
* @param string $id The cache data ID
* @param string $group The cache data group
* @param boolean $wrkarounds True to use workarounds
*
* @return boolean
*
* @since 1.7.0
*/
public function store($data, $id, $group = null, $wrkarounds = true)
{
if ($this->_locktest->locked === false &&
$this->_locktest->locklooped === true)
{
// We can not store data because another process is in the middle of
saving
return false;
}
// Get page data from the application object
if (!$data)
{
$data = \JFactory::getApplication()->getBody();
// Only attempt to store if page data exists.
if (!$data)
{
return false;
}
}
// Get id and group and reset the placeholders
if (!$id)
{
$id = $this->_id;
}
if (!$group)
{
$group = $this->_group;
}
if ($wrkarounds)
{
$data = Cache::setWorkarounds(
$data,
array(
'nopathway' => 1,
'nohead' => 1,
'nomodules' => 1,
'headers' => true,
)
);
}
$result = $this->cache->store(serialize($data), $id, $group);
if ($this->_locktest->locked === true)
{
$this->cache->unlock($id, $group);
}
return $result;
}
/**
* Generate a page cache id
*
* @return string MD5 Hash
*
* @since 1.7.0
* @todo Discuss whether this should be coupled to a data hash or a
request hash ... perhaps hashed with a serialized request
*/
protected function _makeId()
{
return Cache::makeId();
}
/**
* There is no change in page data so send an unmodified header and die
gracefully
*
* @return void
*
* @since 1.7.0
*/
protected function _noChange()
{
$app = \JFactory::getApplication();
// Send not modified header and exit gracefully
$app->setHeader('Status', 304, true);
$app->sendHeaders();
$app->close();
}
/**
* Set the ETag header in the response
*
* @param string $etag The entity tag (etag) to set
*
* @return void
*
* @since 1.7.0
*/
protected function _setEtag($etag)
{
\JFactory::getApplication()->setHeader('ETag',
'"' . $etag . '"', true);
}
}
PK]6�[h�i�
Controller/ViewController.phpnu�[���<?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\Controller;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Cache\CacheController;
/**
* Joomla! Cache view type object
*
* @since 1.7.0
*/
class ViewController extends CacheController
{
/**
* Get the cached view data
*
* @param object $view The view object to cache output for
* @param string $method The method name of the view method to
cache output for
* @param mixed $id The cache data ID
* @param boolean $wrkarounds True to enable workarounds.
*
* @return boolean True if the cache is hit (false else)
*
* @since 1.7.0
*/
public function get($view, $method = 'display', $id = false,
$wrkarounds = true)
{
// If an id is not given generate it from the request
if (!$id)
{
$id = $this->_makeId($view, $method);
}
$data = $this->cache->get($id);
$locktest = (object) array('locked' => null,
'locklooped' => null);
if ($data === false)
{
$locktest = $this->cache->lock($id);
/*
* If the loop is completed and returned true it means the lock has been
set.
* If looped is true try to get the cached data again; it could exist
now.
*/
if ($locktest->locked === true && $locktest->locklooped
=== true)
{
$data = $this->cache->get($id);
}
// False means that locking is either turned off or maxtime has been
exceeded. Execute the view.
}
if ($data !== false)
{
if ($locktest->locked === true)
{
$this->cache->unlock($id);
}
$data = unserialize(trim($data));
if ($wrkarounds)
{
echo Cache::getWorkarounds($data);
}
else
{
// No workarounds, so all data is stored in one piece
echo $data;
}
return true;
}
// No hit so we have to execute the view
if (!method_exists($view, $method))
{
return false;
}
if ($locktest->locked === false && $locktest->locklooped
=== true)
{
// We can not store data because another process is in the middle of
saving
$view->$method();
return false;
}
// Capture and echo output
ob_start();
ob_implicit_flush(false);
$view->$method();
$data = ob_get_clean();
echo $data;
/*
* For a view we have a special case. We need to cache not only the
output from the view, but the state
* of the document head after the view has been rendered. This will
allow us to properly cache any attached
* scripts or stylesheets or links or any other modifications that the
view has made to the document object
*/
if ($wrkarounds)
{
$data = Cache::setWorkarounds($data);
}
// Store the cache data
$this->cache->store(serialize($data), $id);
if ($locktest->locked === true)
{
$this->cache->unlock($id);
}
return false;
}
/**
* Generate a view cache ID.
*
* @param object $view The view object to cache output for
* @param string $method The method name to cache for the view object
*
* @return string MD5 Hash
*
* @since 1.7.0
*/
protected function _makeId($view, $method)
{
return md5(serialize(array(Cache::makeId(), get_class($view), $method)));
}
}
PK]6�[�D#}��&Exception/CacheConnectingException.phpnu�[���<?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\Exception;
defined('JPATH_PLATFORM') or die;
/**
* Exception class defining an error connecting to the cache storage engine
*
* @since 3.6.3
*/
class CacheConnectingException extends \RuntimeException implements
CacheExceptionInterface
{
}
PK]6�[��1��%Exception/CacheExceptionInterface.phpnu�[���<?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\Exception;
defined('JPATH_PLATFORM') or die;
/**
* Exception interface defining a cache storage error
*
* @since 3.7.0
*/
interface CacheExceptionInterface
{
}
PK]6�[�^��'Exception/UnsupportedCacheException.phpnu�[���<?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\Exception;
defined('JPATH_PLATFORM') or die;
/**
* Exception class defining an unsupported cache storage object
*
* @since 3.6.3
*/
class UnsupportedCacheException extends \RuntimeException implements
CacheExceptionInterface
{
}
PK]6�[&*&
Storage/ApcStorage.phpnu�[���<?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');
}
}
PK]6�[�Q�e22Storage/ApcuStorage.phpnu�[���<?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;
}
}
PK]6�[�ʸ�qqStorage/CacheliteStorage.phpnu�[���<?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');
}
}
PK]6�[rCʙStorage/CacheStorageHelper.phpnu�[���<?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++;
}
}
PK]6�[sp� D DStorage/FileStorage.phpnu�[���<?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;
}
}
PK]6�[�`ػ&�&Storage/MemcachedStorage.phpnu�[���<?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');
}
}
PK]6�[7ԝm$m$Storage/MemcacheStorage.phpnu�[���<?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');
}
}
PK]6�[�D���Storage/RedisStorage.phpnu�[���<?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;
}
}
PK]6�[�S����Storage/WincacheStorage.phpnu�[���<?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');
}
}
PK`6�[���x��Storage/XcacheStorage.phpnu�[���<?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;
}
}
PK2K�[�r AbstractCache.phpnu�[���<?php
namespace Nextend\Framework\Cache;
use Nextend\Framework\Cache\Storage\AbstractStorage;
abstract class AbstractCache {
protected $group = '';
protected $isAccessible = false;
/** @var AbstractStorage */
public $storage;
protected $_storageEngine = 'filesystem';
/**
* @param string $engine
*
* @return AbstractStorage
*/
public static function getStorage($engine = "filesystem") {
static $storage = null;
if ($storage === null) {
$storage = array(
'filesystem' => new Storage\Filesystem(),
'database' => new Storage\Database()
);
}
return $storage[$engine];
}
public static function clearAll() {
self::getStorage('filesystem')
->clearAll();
self::getStorage('filesystem')
->clearAll('web');
}
public static function clearGroup($group) {
self::getStorage('filesystem')
->clear($group);
self::getStorage('filesystem')
->clear($group, 'web');
self::getStorage('database')
->clear($group);
self::getStorage('database')
->clear($group, 'web');
}
public function __construct($group, $isAccessible = false) {
$this->group = $group;
$this->isAccessible = $isAccessible;
$this->storage =
self::getStorage($this->_storageEngine);
}
protected function clearCurrentGroup() {
$this->storage->clear($this->group, $this->getScope());
}
protected function getScope() {
if ($this->isAccessible) {
return 'web';
}
return 'notweb';
}
protected function exists($key) {
return $this->storage->exists($this->group, $key,
$this->getScope());
}
protected function get($key) {
return $this->storage->get($this->group, $key,
$this->getScope());
}
protected function set($key, $value) {
$this->storage->set($this->group, $key, $value,
$this->getScope());
}
protected function getPath($key) {
return $this->storage->getPath($this->group, $key,
$this->getScope());
}
protected function remove($key) {
return $this->storage->remove($this->group, $key,
$this->getScope());
}
}PK2K�[�i�vSSCacheImage.phpnu�[���<?php
namespace Nextend\Framework\Cache;
use DateTime;
class CacheImage extends AbstractCache {
protected $_storageEngine = 'filesystem';
protected $lazy = false;
public function __construct($group) {
parent::__construct($group, true);
}
protected function getScope() {
return 'image';
}
public function setLazy($lazy) {
$this->lazy = $lazy;
}
/**
* @param $fileExtension
* @param callable $callable
* @param array $parameters
* @param bool $hash
*
* @return mixed
*/
public function makeCache($fileExtension, $callable, $parameters =
array(), $hash = false) {
if (!$hash) {
$hash = $this->generateHash($fileExtension, $callable,
$parameters);
}
if (strpos($parameters[1], '?') !== false) {
$fileNameParts = explode('?', $parameters[1]);
$keepFileName = pathinfo($fileNameParts[0],
PATHINFO_FILENAME);
} else {
$keepFileName = pathinfo($parameters[1], PATHINFO_FILENAME);
}
$fileName = $hash . (!empty($keepFileName) ?
'/' . $keepFileName : '');
$fileNameWithExtension = $fileName . '.' .
$fileExtension;
$isCached = $this->exists($fileNameWithExtension);
if ($isCached) {
if (!$this->testManifestFile($fileName, $parameters[1])) {
$isCached = false;
}
}
if (!$isCached) {
if ($this->lazy) {
return $parameters[1];
}
array_unshift($parameters,
$this->getPath($fileNameWithExtension));
call_user_func_array($callable, $parameters);
$this->createManifestFile($fileName, $parameters[2]);
}
return $this->getPath($fileNameWithExtension);
}
private function generateHash($fileExtension, $callable, $parameters) {
return md5(json_encode(array(
$fileExtension,
$callable,
$parameters
)));
}
protected function testManifestFile($fileName, $originalFile) {
$manifestKey = $this->getManifestKey($fileName);
if ($this->exists($manifestKey)) {
$manifestData = json_decode($this->get($manifestKey), true);
$newManifestData = $this->getManifestData($originalFile);
if ($manifestData['mtime'] ==
$newManifestData['mtime']) {
return true;
}
} else {
// Backward compatibility
$this->createManifestFile($fileName, $originalFile);
return true;
}
return false;
}
protected function createManifestFile($fileName, $originalFile) {
$this->set($this->getManifestKey($fileName),
json_encode($this->getManifestData($originalFile)));
}
private function getManifestData($originalFile) {
$manifestData = array();
if (strpos($originalFile, '//') !== false) {
$manifestData['mtime'] =
$this->getRemoteMTime($originalFile);
} else {
$manifestData['mtime'] = filemtime($originalFile);
}
return $manifestData;
}
private function getRemoteMTime($url) {
$h = get_headers($url, 1);
if (!$h || strpos($h[0], '200') !== false) {
foreach ($h as $k => $v) {
if (strtolower(trim($k)) == "last-modified") {
return (new DateTime($v))->getTimestamp();
}
}
}
return 0;
}
protected function getManifestKey($fileName) {
return $fileName . '.manifest';
}
}PK2K�[�n� � Manifest.phpnu�[���<?php
namespace Nextend\Framework\Cache;
class Manifest extends AbstractCache {
private $isRaw = false;
private $manifestData;
public function __construct($group, $isAccessible = false, $isRaw =
false) {
parent::__construct($group, $isAccessible);
$this->isRaw = $isRaw;
}
protected function decode($data) {
return $data;
}
/**
* @param $fileName
* @param $hash
* @param callback $callable
*
* @return bool
*/
public function makeCache($fileName, $hash, $callable) {
if (!$this->isCached($fileName, $hash)) {
$return = call_user_func($callable, $this);
if ($return === false) {
return false;
}
return $this->createCacheFile($fileName, $hash, $return);
}
if ($this->isAccessible) {
return $this->getPath($fileName);
}
return $this->decode($this->get($fileName));
}
private function isCached($fileName, $hash) {
$manifestKey = $this->getManifestKey($fileName);
if ($this->exists($manifestKey)) {
$this->manifestData =
json_decode($this->get($manifestKey), true);
if (!$this->isCacheValid($this->manifestData) ||
$this->manifestData['hash'] != $hash ||
!$this->exists($fileName)) {
$this->clean($fileName);
return false;
}
return true;
}
return false;
}
protected function createCacheFile($fileName, $hash, $content) {
$this->manifestData = array();
$this->manifestData['hash'] = $hash;
$this->addManifestData($this->manifestData);
$this->set($this->getManifestKey($fileName),
json_encode($this->manifestData));
$this->set($fileName, $this->isRaw ? $content :
json_encode($content));
if ($this->isAccessible) {
return $this->getPath($fileName);
}
return $content;
}
protected function isCacheValid(&$manifestData) {
return true;
}
protected function addManifestData(&$manifestData) {
}
public function clean($fileName) {
$this->remove($this->getManifestKey($fileName));
$this->remove($fileName);
}
protected function getManifestKey($fileName) {
return $fileName . '.manifest';
}
public function getData($key, $default = 0) {
return isset($this->manifestData[$key]) ?
$this->manifestData[$key] : $default;
}
}PK2K�[�����Storage/AbstractStorage.phpnu�[���<?php
namespace Nextend\Framework\Cache\Storage;
abstract class AbstractStorage {
protected $paths = array();
public function isFilesystem() {
return false;
}
public abstract function clearAll($scope = 'notweb');
public abstract function clear($group, $scope = 'notweb');
public abstract function exists($group, $key, $scope =
'notweb');
public abstract function set($group, $key, $value, $scope =
'notweb');
public abstract function get($group, $key, $scope =
'notweb');
public abstract function remove($group, $key, $scope =
'notweb');
public abstract function getPath($group, $key, $scope =
'notweb');
}PK2K�[Pb��GGStorage/Database.phpnu�[���<?php
namespace Nextend\Framework\Cache\Storage;
use Nextend\Framework\Model\ApplicationSection;
use Nextend\Framework\Platform\Platform;
class Database extends AbstractStorage {
protected $db;
public function __construct() {
$this->paths['web'] = 'web';
$this->paths['notweb'] = 'notweb';
$this->paths['image'] = 'image';
$this->db = new ApplicationSection('cache');
}
public function clearAll($scope = 'notweb') {
}
public function clear($group, $scope = 'notweb') {
$this->db->delete($scope . '/' . $group);
}
public function exists($group, $key, $scope = 'notweb') {
if ($this->db->get($scope . '/' . $group, $key)) {
return true;
}
return false;
}
public function set($group, $key, $value, $scope = 'notweb')
{
$this->db->set($scope . '/' . $group, $key,
$value);
}
public function get($group, $key, $scope = 'notweb') {
return $this->db->get($scope . '/' . $group, $key);
}
public function remove($group, $key, $scope = 'notweb') {
$this->db->delete($scope . '/' . $group, $key);
}
public function getPath($group, $key, $scope = 'notweb') {
return Platform::getSiteUrl() . '?nextendcache=1&g='
. urlencode($group) . '&k=' . urlencode($key);
}
}PK2K�[K�GP��Storage/Filesystem.phpnu�[���<?php
namespace Nextend\Framework\Cache\Storage;
class Filesystem extends AbstractStorage {
public function __construct() {
$this->paths['web'] =
\Nextend\Framework\Filesystem\Filesystem::getWebCachePath();
$this->paths['notweb'] =
\Nextend\Framework\Filesystem\Filesystem::getNotWebCachePath();
$this->paths['image'] =
\Nextend\Framework\Filesystem\Filesystem::getImagesFolder();
}
public function isFilesystem() {
return true;
}
public function clearAll($scope = 'notweb') {
if
(\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope]))
{
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope]);
}
}
public function clear($group, $scope = 'notweb') {
if
(\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope]
. '/' . $group)) {
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope]
. '/' . $group);
}
}
public function exists($group, $key, $scope = 'notweb') {
if
(\Nextend\Framework\Filesystem\Filesystem::existsFile($this->paths[$scope]
. '/' . $group . '/' . $key)) {
return true;
}
return false;
}
public function set($group, $key, $value, $scope = 'notweb')
{
$path = $this->paths[$scope] . '/' . $group .
'/' . $key;
$dir = dirname($path);
if (!\Nextend\Framework\Filesystem\Filesystem::existsFolder($dir))
{
\Nextend\Framework\Filesystem\Filesystem::createFolder($dir);
}
\Nextend\Framework\Filesystem\Filesystem::createFile($path,
$value);
}
public function get($group, $key, $scope = 'notweb') {
return
\Nextend\Framework\Filesystem\Filesystem::readFile($this->paths[$scope]
. '/' . $group . '/' . $key);
}
public function remove($group, $key, $scope = 'notweb') {
if ($this->exists($group, $key, $scope)) {
@unlink($this->paths[$scope] . '/' . $group .
'/' . $key);
}
}
public function getPath($group, $key, $scope = 'notweb') {
return $this->paths[$scope] . DIRECTORY_SEPARATOR . $group .
DIRECTORY_SEPARATOR . $key;
}
}PK2K�[������StoreImage.phpnu�[���<?php
namespace Nextend\Framework\Cache;
class StoreImage extends AbstractCache {
protected $_storageEngine = 'filesystem';
protected function getScope() {
return 'image';
}
public function makeCache($fileName, $content) {
if (!$this->isImage($fileName)) {
return false;
}
if (!$this->exists($fileName)) {
$this->set($fileName, $content);
}
return $this->getPath($fileName);
}
private function isImage($fileName) {
$supported_image = array(
'gif',
'jpg',
'jpeg',
'png',
'mp4',
'mp3',
'webp',
'svg'
);
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
if (in_array($ext, $supported_image)) {
return true;
}
return false;
}
}PKʈ�[��P;��CacheInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Interface implemented by cache classes.
*
* It is highly recommended to always store templates on the filesystem to
* benefit from the PHP opcode cache. This interface is mostly useful if
you
* need to implement a custom strategy for storing templates on the
filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
interface CacheInterface
{
/**
* Generates a cache key for the given template class name.
*
* @param string $name The template name
* @param string $className The template class name
*
* @return string
*/
public function generateKey($name, $className);
/**
* Writes the compiled template to cache.
*
* @param string $key The cache key
* @param string $content The template representation as a PHP class
*/
public function write($key, $content);
/**
* Loads a template from the cache.
*
* @param string $key The cache key
*/
public function load($key);
/**
* Returns the modification timestamp of a key.
*
* @param string $key The cache key
*
* @return int
*/
public function getTimestamp($key);
}
class_alias('Twig\Cache\CacheInterface',
'Twig_CacheInterface');
PKʈ�[E���0
0
FilesystemCache.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Implements a cache on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
class FilesystemCache implements CacheInterface
{
const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
/**
* @param string $directory The root cache directory
* @param int $options A set of options
*/
public function __construct($directory, $options = 0)
{
$this->directory = rtrim($directory,
'\/').'/';
$this->options = $options;
}
public function generateKey($name, $className)
{
$hash = hash('sha256', $className);
return
$this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
public function load($key)
{
if (file_exists($key)) {
@include_once $key;
}
}
public function write($key, $content)
{
$dir = \dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
clearstatcache(true, $dir);
if (!is_dir($dir)) {
throw new \RuntimeException(sprintf('Unable to
create the cache directory (%s).', $dir));
}
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in
the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) &&
@rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options
& self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (\function_exists('opcache_invalidate')
&& filter_var(ini_get('opcache.enable'),
FILTER_VALIDATE_BOOLEAN)) {
@opcache_invalidate($key, true);
} elseif (\function_exists('apc_compile_file')) {
apc_compile_file($key);
}
}
return;
}
throw new \RuntimeException(sprintf('Failed to write cache
file "%s".', $key));
}
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}
class_alias('Twig\Cache\FilesystemCache',
'Twig_Cache_Filesystem');
PKʈ�[�6T��
NullCache.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Implements a no-cache strategy.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class NullCache implements CacheInterface
{
public function generateKey($name, $className)
{
return '';
}
public function write($key, $content)
{
}
public function load($key)
{
}
public function getTimestamp($key)
{
return 0;
}
}
class_alias('Twig\Cache\NullCache', 'Twig_Cache_Null');
PK�U�[Ew*kggCacheItemInterface.phpnu�[���<?php
/**
* @package Common interface for caching libraries
*
* @created Feb 9, 2021
* @author PHP-FIG <https://www.php-fig.org/>
* @git Caching Interface <https://github.com/php-fig/cache>
* @license MIT
*/
namespace VDM\Psr\Cache;
/**
* CacheItemInterface defines an interface for interacting with objects
inside a cache.
*
* Each Item object MUST be associated with a specific key, which can be
set
* according to the implementing system and is typically passed by the
* Cache\CacheItemPoolInterface object.
*
* The Cache\CacheItemInterface object encapsulates the storage and
retrieval of
* cache items. Each Cache\CacheItemInterface is generated by a
* Cache\CacheItemPoolInterface object, which is responsible for any
required
* setup as well as associating the object with a unique Key.
* Cache\CacheItemInterface objects MUST be able to store and retrieve any
type
* of PHP value defined in the Data section of the specification.
*
* Calling Libraries MUST NOT instantiate Item objects themselves. They may
only
* be requested from a Pool object via the getItem() method. Calling
Libraries
* SHOULD NOT assume that an Item created by one Implementing Library is
* compatible with a Pool from another Implementing Library.
*/
interface CacheItemInterface
{
/**
* Returns the key for the current cache item.
*
* The key is loaded by the Implementing Library, but should be
available to
* the higher level callers when needed.
*
* @return string
* The key string for this cache item.
*/
public function getKey(): string;
/**
* Retrieves the value of the item from the cache associated with this
object's key.
*
* The value returned must be identical to the value originally stored
by set().
*
* If isHit() returns false, this method MUST return null. Note that
null
* is a legitimate cached value, so the isHit() method SHOULD be used
to
* differentiate between "null value was found" and "no
value was found."
*
* @return mixed
* The value corresponding to this cache item's key, or null if
not found.
*/
public function get(): mixed;
/**
* Confirms if the cache item lookup resulted in a cache hit.
*
* Note: This method MUST NOT have a race condition between calling
isHit()
* and calling get().
*
* @return bool
* True if the request resulted in a cache hit. False otherwise.
*/
public function isHit(): bool;
/**
* Sets the value represented by this cache item.
*
* The $value argument may be any item that can be serialized by PHP,
* although the method of serialization is left up to the Implementing
* Library.
*
* @param mixed $value
* The serializable value to be stored.
*
* @return static
* The invoked object.
*/
public function set(mixed $value): static;
/**
* Sets the expiration time for this cache item.
*
* @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 static
* The called object.
*/
public function expiresAt(?\DateTimeInterface $expiration): static;
/**
* Sets the expiration time for this cache item.
*
* @param int|\DateInterval|null $time
* The period of time from the present after which the item MUST be
considered
* expired. An integer parameter is understood to be the time in
seconds until
* expiration. 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 static
* The called object.
*/
public function expiresAfter(int|\DateInterval|null $time): static;
}
PK�U�[�#o,,
index.htmlnu�[���<html><body
bgcolor="#FFFFFF"></body></html>PK]6�[�]QDIDI Cache.phpnu�[���PK]6�[�ss22}ICacheController.phpnu�[���PK]6�[����!�!�\CacheStorage.phpnu�[���PK]6�[�
o�!�~Controller/CallbackController.phpnu�[���PK]6�[�~
��,�Controller/OutputController.phpnu�[���PK]6�[;g�
DDE�Controller/PageController.phpnu�[���PK]6�[h�i�
ֺController/ViewController.phpnu�[���PK]6�[�D#}��&<�Exception/CacheConnectingException.phpnu�[���PK]6�[��1��%��Exception/CacheExceptionInterface.phpnu�[���PK]6�[�^��'u�Exception/UnsupportedCacheException.phpnu�[���PK]6�[&*&
��Storage/ApcStorage.phpnu�[���PK]6�[�Q�e22�Storage/ApcuStorage.phpnu�[���PK]6�[�ʸ�qq|Storage/CacheliteStorage.phpnu�[���PK]6�[rCʙ9$Storage/CacheStorageHelper.phpnu�[���PK]6�[sp�
D
D�(Storage/FileStorage.phpnu�[���PK]6�[�`ػ&�&mStorage/MemcachedStorage.phpnu�[���PK]6�[7ԝm$m$�Storage/MemcacheStorage.phpnu�[���PK]6�[�D���ĸStorage/RedisStorage.phpnu�[���PK]6�[�S������Storage/WincacheStorage.phpnu�[���PK`6�[���x����Storage/XcacheStorage.phpnu�[���PK2K�[�r �AbstractCache.phpnu�[���PK2K�[�i�vSS=CacheImage.phpnu�[���PK2K�[�n� � �Manifest.phpnu�[���PK2K�[������Storage/AbstractStorage.phpnu�[���PK2K�[Pb��GG�
Storage/Database.phpnu�[���PK2K�[K�GP��l&Storage/Filesystem.phpnu�[���PK2K�[������h/StoreImage.phpnu�[���PKʈ�[��P;��)3CacheInterface.phpnu�[���PKʈ�[E���0
0
)9FilesystemCache.phpnu�[���PKʈ�[�6T��
�CNullCache.phpnu�[���PK�U�[Ew*kgg�FCacheItemInterface.phpnu�[���PK�U�[�#o,,
5Windex.htmlnu�[���PK �
�W