first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
<?php
/**
* @file classes/cache/APCCache.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class apc_false
*
* @ingroup cache
*
* @see GenericCache
*
* @brief Provides caching based on APC's variable store.
*/
namespace PKP\cache;
class apc_false
{
};
class APCCache extends GenericCache
{
/**
* Flush the cache.
*/
public function flush()
{
$prefix = INDEX_FILE_LOCATION . ':' . $this->getContext() . ':' . $this->getCacheId();
$info = apc_cache_info('user');
foreach ($info['cache_list'] as $entry) {
if (substr($entry['info'], 0, strlen($prefix)) == $prefix) {
apc_delete($entry['info']);
}
}
}
/**
* Get an object from the cache.
*
*/
public function getCache($id)
{
$key = INDEX_FILE_LOCATION . ':' . $this->getContext() . ':' . $this->getCacheId() . ':' . $id;
$returner = unserialize(apc_fetch($key));
if ($returner === false) {
return $this->cacheMiss;
}
if ($returner instanceof apc_false) {
$returner = false;
}
return $returner;
}
/**
* Set an object in the cache. This function should be overridden
* by subclasses.
*
*/
public function setCache($id, $value)
{
$key = INDEX_FILE_LOCATION . ':' . $this->getContext() . ':' . $this->getCacheId() . ':' . $id;
if ($value === false) {
$value = new apc_false();
}
apc_store($key, serialize($value));
}
/**
* Get the time at which the data was cached.
* Not implemented in this type of cache.
*/
public function getCacheTime()
{
return null;
}
/**
* Set the entire contents of the cache.
* WARNING: THIS DOES NOT FLUSH THE CACHE FIRST!
*
* @param array $contents Complete cache contents.
*/
public function setEntireCache($contents)
{
foreach ($contents as $id => $value) {
$this->setCache($id, $value);
}
}
}
+171
View File
@@ -0,0 +1,171 @@
<?php
/**
* @file classes/cache/CacheManager.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @ingroup cache
*
* @see GenericCache
*
* @brief Provides cache management functions.
*
*/
namespace PKP\cache;
use PKP\config\Config;
use PKP\core\Core;
use PKP\core\Registry;
define('CACHE_TYPE_FILE', 1);
define('CACHE_TYPE_OBJECT', 2);
class CacheManager
{
/**
* Get the static instance of the cache manager.
*
* @return CacheManager
*/
public static function getManager()
{
$manager = & Registry::get('cacheManager', true, null);
if ($manager === null) {
$manager = new CacheManager();
}
return $manager;
}
/**
* Get a file cache.
*
* @param string $context
* @param string $cacheId
* @param callable $fallback
*
* @return FileCache
*/
public function getFileCache($context, $cacheId, $fallback)
{
return new FileCache(
$context,
$cacheId,
$fallback,
$this->getFileCachePath()
);
}
public function getObjectCache($context, $cacheId, $fallback)
{
return $this->getCache($context, $cacheId, $fallback, CACHE_TYPE_OBJECT);
}
public function getCacheImplementation($type)
{
switch ($type) {
case CACHE_TYPE_FILE: return 'file';
case CACHE_TYPE_OBJECT: return Config::getVar('cache', 'object_cache');
default: return null;
}
}
/**
* Get a cache.
*
* @param string $context
* @param string $cacheId
* @param ?callable $fallback
* @param string $type Type of cache: CACHE_TYPE_...
*
* @return GenericCache
*/
public function getCache($context, $cacheId, $fallback, $type = CACHE_TYPE_FILE)
{
switch ($this->getCacheImplementation($type)) {
case 'xcache':
$cache = new \PKP\cache\XCacheCache(
$context,
$cacheId,
$fallback
);
break;
case 'apc':
$cache = new \PKP\cache\APCCache(
$context,
$cacheId,
$fallback
);
break;
case 'memcache':
$cache = new \PKP\cache\MemcacheCache(
$context,
$cacheId,
$fallback,
Config::getVar('cache', 'memcache_hostname'),
Config::getVar('cache', 'memcache_port')
);
break;
case '': // Provide a default if not specified
case 'file':
$cache = $this->getFileCache($context, $cacheId, $fallback);
break;
case 'none':
$cache = new \PKP\cache\GenericCache(
$context,
$cacheId,
$fallback
);
break;
default:
exit("Unknown cache type \"{$type}\"!\n");
}
return $cache;
}
/**
* Get the path in which file caches will be stored.
*
* @return string The full path to the file cache directory
*/
public static function getFileCachePath()
{
return Core::getBaseDir() . '/cache';
}
/**
* Flush an entire context, if specified, or
* the whole cache.
*
* @param string $context The context to flush, if only one is to be flushed
* @param string $type The type of cache to flush
*/
public function flush($context = null, $type = CACHE_TYPE_FILE)
{
$cacheImplementation = $this->getCacheImplementation($type);
switch ($cacheImplementation) {
case 'xcache':
case 'apc':
case 'memcache':
$junkCache = $this->getCache($context, null, null);
$junkCache->flush();
break;
case 'file':
$filePath = $this->getFileCachePath();
$files = glob("{$filePath}/fc-" . (isset($context) ? $context . '-' : '') . '*.php');
foreach ($files as $file) {
@unlink($file);
}
break;
case '':
case 'none':
// Nothing necessary.
break;
default:
exit("Unknown cache type \"{$type}\"!\n");
}
}
}
+150
View File
@@ -0,0 +1,150 @@
<?php
/**
* @defgroup cache Cache
* Implements various forms of caching, i.e. object caches, file caches, etc.
*/
/**
* @file classes/cache/FileCache.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class FileCache
*
* @ingroup cache
*
* @brief Provides caching based on machine-generated PHP code on the filesystem.
*/
namespace PKP\cache;
use Exception;
use PKP\config\Config;
use PKP\file\FileManager;
class FileCache extends GenericCache
{
/**
* Connection to use for caching.
*/
public $filename;
/**
* @var ?array The cached data
*/
public $cache;
/**
* Instantiate a cache.
*/
public function __construct($context, $cacheId, $fallback, $path)
{
parent::__construct($context, $cacheId, $fallback);
$this->filename = "{$path}/fc-{$context}-" . str_replace('/', '.', $cacheId) . '.php';
// If the file couldn't be opened or if a lock couldn't be acquired, quit
if (!($fp = @fopen($this->filename, 'r')) || !flock($fp, LOCK_SH)) {
$this->cache = null;
return;
}
// Reasoning: When the include below fails, it returns "false" and we have no way to determine if it's an error or a valid cache value
set_error_handler(static fn () => throw new Exception('Failed to include file'));
try {
$this->cache = include $this->filename;
} catch (Exception) {
$this->cache = null;
} finally {
restore_error_handler();
flock($fp, LOCK_UN);
fclose($fp);
}
}
/**
* Flush the cache
*/
public function flush()
{
unset($this->cache);
$this->cache = null;
if (function_exists('opcache_invalidate')) {
opcache_invalidate($this->filename, true);
}
@unlink($this->filename);
}
/**
* Get an object from the cache.
*
* @param string $id
*/
public function getCache($id)
{
if (!isset($this->cache)) {
return $this->cacheMiss;
}
return ($this->cache[$id] ?? null);
}
/**
* Set an object in the cache. This function should be overridden
* by subclasses.
*
* @param string $id
*/
public function setCache($id, $value)
{
// Flush the cache; it will be regenerated on demand.
$this->flush();
}
/**
* Set the entire contents of the cache.
*/
public function setEntireCache($contents)
{
if (@file_put_contents(
$this->filename,
'<?php return ' . var_export($contents, true) . ';',
LOCK_EX
) !== false) {
$umask = Config::getVar('files', 'umask');
if ($umask) {
@chmod($this->filename, FileManager::FILE_MODE_MASK & ~$umask);
}
}
$this->cache = $contents;
}
/**
* Get the time at which the data was cached.
* If the file does not exist or an error occurs, null is returned.
*
* @return int|null
*/
public function getCacheTime()
{
$result = @filemtime($this->filename);
if ($result === false) {
return null;
}
return ((int) $result);
}
/**
* Get the entire contents of the cache in an associative array.
*/
public function &getContents()
{
if (!isset($this->cache)) {
// Trigger a cache miss to load the cache.
$this->get(null);
}
return $this->cache;
}
}
+154
View File
@@ -0,0 +1,154 @@
<?php
/**
* @file classes/cache/GenericCache.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class generic_cache_miss
*
* @ingroup cache
*
* @brief Provides implementation-independent caching. Although this class is intended
* to be overridden with a more specific implementation, it can be used as the
* null cache.
*/
namespace PKP\cache;
// Pseudotype to represent a cache miss
class generic_cache_miss
{
}
class GenericCache
{
/**
* The unique string identifying the context of this cache.
* Must be suitable for a filename.
*/
public $context;
/**
* The ID of this particular cache within the context
*/
public $cacheId;
public $cacheMiss;
/**
* The getter fallback callback (for a cache miss)
* This function is called with two parameters:
* 1. The cache object that is suffering a miss
* 2. The id of the value to fetch
* The function is responsible for loading data into the
* cache, using setEntireCache or setCache.
*/
public $fallback;
/**
* Instantiate a cache.
*/
public function __construct($context, $cacheId, $fallback)
{
$this->context = $context;
$this->cacheId = $cacheId;
$this->fallback = $fallback;
$this->cacheMiss = new generic_cache_miss();
}
/**
* Get an object from cache, using the fallback if necessary.
*/
public function get($id)
{
$result = $this->getCache($id);
if (is_object($result) && $result instanceof generic_cache_miss) {
$result = call_user_func_array($this->fallback, [$this, $id]);
}
return $result;
}
/**
* Set an object in the cache. This function should be overridden
* by subclasses.
*/
public function set($id, $value)
{
return $this->setCache($id, $value);
}
/**
* Flush the cache.
*/
public function flush()
{
}
/**
* Set the entire contents of the cache. May (should) be overridden
* by subclasses.
*/
public function setEntireCache($contents)
{
$this->flush();
foreach ($contents as $id => $value) {
$this->setCache($id, $value);
}
}
/**
* Get an object from the cache. This function should be overridden
* by subclasses.
*
* @param string $id
*/
public function getCache($id)
{
return $this->cacheMiss;
}
/**
* Set an object in the cache. This function should be overridden
* by subclasses.
*
* @param string $id
*/
public function setCache($id, $value)
{
}
/**
* Close the cache. (Optionally overridden by subclasses.)
*/
public function close()
{
}
/**
* Get the context.
*/
public function getContext()
{
return $this->context;
}
/**
* Get the cache ID within its context
*/
public function getCacheId()
{
return $this->cacheId;
}
/**
* Get the time at which the data was cached.
*/
public function getCacheTime()
{
// Since it's not really cached, we'll consider it to have been cached just now.
return time();
}
}
+166
View File
@@ -0,0 +1,166 @@
<?php
/**
* @file classes/cache/MemcacheCache.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class memcache_null
*
* @ingroup cache
*
* @see GenericCache
*
* @brief Provides caching based on Memcache.
*/
namespace PKP\cache;
use Memcached;
// WARNING: This cache MUST be loaded in batch, or else many cache
// misses will result.
// Pseudotypes used to represent false and null values in the cache
class memcache_false
{
}
class memcache_null
{
}
class MemcacheCache extends GenericCache
{
/**
* Connection to use for caching.
*/
public $connection;
/**
* Flag (used by Memcache::set)
*/
public $flag;
/**
* Expiry (used by Memcache::set)
*/
public $expire;
/**
* Instantiate a cache.
*/
public function __construct($context, $cacheId, $fallback, $hostname, $port)
{
parent::__construct($context, $cacheId, $fallback);
$this->connection = new Memcached();
// FIXME This should use connection pooling
// XXX check whether memcached server is usable
if (!$this->connection->addServer($hostname, $port)) {
$this->connection = null;
}
$this->flag = null;
$this->expire = 3600; // 1 hour default expiry
}
/**
* Set the flag (used in Memcache::set)
*/
public function setFlag($flag)
{
$this->flag = $flag;
}
/**
* Set the expiry time (used in Memcache::set)
*/
public function setExpiry($expiry)
{
$this->expire = $expiry;
}
/**
* Flush the cache.
*/
public function flush()
{
$this->connection->flush();
}
/**
* Get an object from the cache.
*
* @param string $id
*/
public function getCache($id)
{
$result = $this->connection->get($this->getContext() . ':' . $this->getCacheId() . ':' . $id);
if ($this->connection->getResultCode() == Memcached::RES_NOTFOUND) {
return $this->cacheMiss;
}
if ($result instanceof memcache_false) {
$result = false;
}
if ($result instanceof memcache_null) {
$result = null;
}
return $result;
}
/**
* Set an object in the cache. This function should be overridden
* by subclasses.
*
* @param string $id
*/
public function setCache($id, $value)
{
if ($value === false) {
$value = new memcache_false();
} elseif ($value === null) {
$value = new memcache_null();
}
return ($this->connection->set($this->getContext() . ':' . $this->getCacheId() . ':' . $id, $value, $this->expire));
}
/**
* Close the cache and free resources.
*/
public function close()
{
$this->connection->quit();
unset($this->connection);
$this->contextChecked = false;
}
/**
* Get the time at which the data was cached.
* Note that keys expire in memcache, which means
* that it's possible that the date will disappear
* before the data -- in this case we'll have to
* assume the data is still good.
*/
public function getCacheTime()
{
return null;
}
/**
* Set the entire contents of the cache.
* WARNING: THIS DOES NOT FLUSH THE CACHE FIRST!
* This is because there is no "scope restriction"
* for flushing within memcache and therefore
* a flush here would flush the entire cache,
* resulting in more subsequent calls to this function,
* resulting in more flushes, etc.
*/
public function setEntireCache($contents)
{
foreach ($contents as $id => $value) {
$this->setCache($id, $value);
}
}
}
+90
View File
@@ -0,0 +1,90 @@
<?php
/**
* @file classes/cache/XCacheCache.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class XCacheCache
*
* @ingroup cache
*
* @see GenericCache
*
* @brief Provides caching based on XCache's variable store.
*/
namespace PKP\cache;
class XCacheCache extends GenericCache
{
/**
* Flush the cache.
*/
public function flush()
{
$prefix = INDEX_FILE_LOCATION . ':' . $this->getContext() . ':' . $this->getCacheId();
if (function_exists('xcache_unset_by_prefix')) {
// If possible, just flush the context
xcache_unset_by_prefix(prefix);
} else {
// Otherwise, we need to do this manually
for ($i = 0; $i < xcache_count(XC_TYPE_VAR); $i++) {
$cache = xcache_list(XC_TYPE_VAR, $i);
foreach ($cache['cache_list'] as $entry) {
if (substr($entry['name'], 0, strlen($prefix)) == $prefix) {
xcache_unset($entry['name']);
}
}
}
}
}
/**
* Get an object from the cache.
*
* @param string $id
*/
public function getCache($id)
{
$key = INDEX_FILE_LOCATION . ':' . $this->getContext() . ':' . $this->getCacheId() . ':' . $id;
if (!xcache_isset($key)) {
return $this->cacheMiss;
}
$returner = unserialize(xcache_get($key));
return $returner;
}
/**
* Set an object in the cache. This function should be overridden
* by subclasses.
*
* @param string $id
*/
public function setCache($id, $value)
{
return (xcache_set(INDEX_FILE_LOCATION . ':' . $this->getContext() . ':' . $this->getCacheId() . ':' . $id, serialize($value)));
}
/**
* Get the time at which the data was cached.
* Not implemented in this type of cache.
*/
public function getCacheTime()
{
return null;
}
/**
* Set the entire contents of the cache.
* WARNING: THIS DOES NOT FLUSH THE CACHE FIRST!
*/
public function setEntireCache($contents)
{
foreach ($contents as $id => $value) {
$this->setCache($id, $value);
}
}
}