Version 4.6.0

This commit is contained in:
Neo committed 2025-12-19 05:55:31 -08:00
1 parent f79dcf067a
commit 517a5e1f70
2036 files changed
+110041 -26162

No files matched your search

+27 -2
View File
@@ -37,6 +37,27 @@ abstract class _Cache extends AbstractData
*/
public $log = array();
/**
* Available Cache Store Methods
* - MUST always return a 'None' option
*
* @return array
*/
public static function availableMethods(): array
{
$return = [
'None' => 'IPS\Data\Cache\None',
'Redis' => 'IPS\Data\Cache\Redis',
];
if( \IPS\TEST_CACHING )
{
$return['Test'] = 'IPS\Data\Cache\Test';
}
return $return;
}
/**
* Get instance
*
@@ -46,8 +67,12 @@ abstract class _Cache extends AbstractData
{
if( static::$instance === NULL )
{
$classname = 'IPS\Data\Cache\\' . \IPS\CACHE_METHOD;
$classname = '\IPS\Data\Cache\None';
if( isset( static::availableMethods()[ \IPS\CACHE_METHOD ] ) AND class_exists( static::availableMethods()[ \IPS\CACHE_METHOD ] ) )
{
$classname = static::availableMethods()[ \IPS\CACHE_METHOD ];
}
if ( $classname::supported() )
{
try
-119
View File
@@ -1,119 +0,0 @@
<?php
/**
* @brief APC Caching Class
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 17 Sept 2013
*/
namespace IPS\Data\Cache;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* APC Storage Class
*/
class _Apc extends \IPS\Data\Cache
{
/**
* Server supports this method?
*
* @return bool
*/
public static function supported()
{
return \function_exists('apcu_fetch');
}
/**
* Abstract Method: Get
*
* @param string $key Key
* @return string Value from the _datastore
*/
protected function get( $key )
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::debug( "Get {$key} from APC (already loaded)", 'cache' );
return $this->cache[ $key ];
}
\IPS\Log::debug( "Get {$key} from APC", 'cache' );
$this->cache[ $key ] = apcu_fetch( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
return $this->cache[ $key ];
}
/**
* Abstract Method: Set
*
* @param string $key Key
* @param string $value Value
* @param \IPS\DateTime|NULL $expire Expreation time, or NULL for no expiration
* @return bool
*/
protected function set( $key, $value, \IPS\DateTime $expire = NULL )
{
\IPS\Log::debug( "Set {$key} in APC", 'cache' );
return (bool) apcu_store( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $value, $expire ? ( $expire->getTimestamp() - time() ) : 0 );
}
/**
* Abstract Method: Exists?
*
* @param string $key Key
* @return bool
*/
protected function exists( $key )
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::debug( "Check exists {$key} from APC (already loaded)", 'cache' );
return ( $this->cache[ $key ] === FALSE ) ? FALSE : TRUE;
}
\IPS\Log::debug( "Check exists {$key} from APC", 'cache' );
$result = apcu_fetch( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $exists );
if ( $exists )
{
$this->cache[ $key ] = $result;
return TRUE;
}
else
{
return FALSE;
}
}
/**
* Abstract Method: Delete
*
* @param string $key Key
* @return bool
*/
protected function delete( $key )
{
\IPS\Log::debug( "Delete {$key} from APC", 'cache' );
return (bool) apcu_delete( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
}
/**
* Abstract Method: Clear All Caches
*
* @return void
*/
public function clearAll()
{
parent::clearAll();
apcu_clear_cache();
}
}
-258
View File
@@ -1,258 +0,0 @@
<?php
/**
* @brief Memcache Cache Class
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 17 Sept 2013
*/
namespace IPS\Data\Cache;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Memcache Cache Class
*/
class _Memcache extends \IPS\Data\Cache
{
/**
* Server supports this method?
*
* @return bool
*/
public static function supported()
{
return ( class_exists( 'Memcached' ) OR class_exists( 'Memcache' ) );
}
/**
* Configuration
*
* @param array $configuration Existing settings
* @return array \IPS\Helpers\Form\FormAbstract elements
*/
public static function configuration( $configuration )
{
return array(
'servers' => new \IPS\Helpers\Form\Stack( 'datastore_memcache_servers', isset( $configuration['servers'] ) ? $configuration['servers'] : array(), FALSE, array( 'placeholder' => '127.0.0.1:11211' ), function( $val )
{
if ( \IPS\Request::i()->cache_method === 'Memcache' )
{
if ( empty( $val ) )
{
throw new \DomainException( 'datastore_memcache_servers_err' );
}
else
{
$test = new \IPS\Data\Cache\Memcache( array( 'servers' => $val ) );
if ( $test->link->getStats() === FALSE )
{
throw new \DomainException( 'datastore_memcache_servers_err2' );
}
}
}
} )
);
}
/**
* @brief Connection resource
*/
protected $link = null;
/**
* @brief Keys that do not exist
*/
protected $doesNotExist = array();
/**
* Get the server link
*
* @return \Memcache|\Memcached
*/
protected function _getLink()
{
if( class_exists( 'Memcached' ) )
{
return new \Memcached;
}
else
{
return new \Memcache;
}
}
/**
* Constructor
*
* @param array $configuration Configuration
* @return void
*/
public function __construct( $configuration )
{
/* Connect and add the servers that are defined to the pool */
$this->link = $this->_getLink();
$configuration['servers'] = ( !\is_array( $configuration['servers'] ) ) ? array( $configuration['servers'] ) : $configuration['servers'];
foreach( $configuration['servers'] as $server )
{
$exploded = explode( ':', $server );
/* set the port to 0 if unix sockets are used - see http://php.net/manual/de/memcached.addserver.php */
if ( \mb_substr( $server, -5) == '.sock' AND !isset( $exploded[1] ) )
{
$exploded[1] = 0;
}
$this->link->addServer( $exploded[0], isset( $exploded[1] ) ? $exploded[1] : 11211 );
}
}
/**
* Abstract Method: Get
*
* @param string $key Key
* @return string Value from the _datastore
*/
protected function get( $key )
{
if( !isset( $this->cache[ $key ] ) )
{
$value = $this->link->get( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
if( method_exists( $this->link, 'getResultCode' ) and $this->link->getResultCode() == \Memcached::RES_NOTFOUND )
{
$this->doesNotExist[] = $key;
throw new \OutOfRangeException;
}
$this->cache[ $key ] = $value;
}
return $this->cache[ $key ];
}
/**
* Abstract Method: Set
*
* @param string $key Key
* @param string $value Value
* @param \IPS\DateTime|NULL $expire Expreation time, or NULL for no expiration
* @return bool
*/
protected function set( $key, $value, \IPS\DateTime $expire = NULL )
{
if ( \in_array( $key, $this->doesNotExist ) )
{
unset( $this->doesNotExist[ array_search( $key, $this->doesNotExist ) ] );
}
$this->cache[ $key ] = $value;
if ( $this->link instanceof \Memcached )
{
$result = (bool) $this->link->set( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $value, $expire ? $expire->getTimestamp() : 0 );
if ( !$result )
{
$error = $this->link->getResultCode();
/** will log the error code returned by memcached; lookup: http://php.net/manual/en/memcached.getresultcode.php */
\IPS\Log::debug( 'error code ' . $error, 'memcached_set_error' );
}
return $result;
}
else
{
return (bool) $this->link->set( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $value, MEMCACHE_COMPRESSED, $expire ? $expire->getTimestamp() : 0 );
}
}
/**
* Abstract Method: Exists?
*
* @param string $key Key
* @return bool
*/
protected function exists( $key )
{
if ( \in_array( $key, $this->doesNotExist ) )
{
return FALSE;
}
elseif ( isset( $this->cache[ $key ] ) )
{
return TRUE;
}
else
{
$value = $this->link->get( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
if( method_exists( $this->link, 'getResultCode' ) )
{
if ( $this->link->getResultCode() == \Memcached::RES_NOTFOUND or $value === FALSE )
{
$this->doesNotExist[] = $key;
return FALSE;
}
}
else
{
if ( $value === FALSE )
{
$this->doesNotExist[] = $key;
return FALSE;
}
}
$this->cache[ $key ] = $value;
return TRUE;
}
}
/**
* Abstract Method: Delete
*
* @param string $key Key
* @return bool
*/
protected function delete( $key )
{
return (bool) $this->link->delete( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
}
/**
* Destructor
*
* @return void
*/
public function __destruct()
{
if( $this->link )
{
if( method_exists( $this->link, 'quit' ) )
{
$this->link->quit();
}
elseif( method_exists( $this->link, 'close' ) )
{
$this->link->close();
}
}
}
/**
* Abstract Method: Clear All Caches
*
* @return void
*/
public function clearAll()
{
parent::clearAll();
$this->link->flush();
}
}
-110
View File
@@ -1,110 +0,0 @@
<?php
/**
* @brief Wincache Cache Class
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 17 Sept 2013
*/
namespace IPS\Data\Cache;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Wincache Storage Class
*/
class _Wincache extends \IPS\Data\Cache
{
/**
* Server supports this method?
*
* @return bool
*/
public static function supported()
{
return \function_exists('wincache_ucache_get');
}
/**
* Abstract Method: Get
*
* @param string $key Key
* @return string Value from the _datastore
*/
protected function get( $key )
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::debug( "Get {$key} from Wincache (already loaded)", 'cache' );
return $this->cache[ $key ];
}
\IPS\Log::debug( "Get {$key} from Wincache", 'cache' );
$this->cache[ $key ] = wincache_ucache_get( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
return $this->cache[ $key ];
}
/**
* Abstract Method: Set
*
* @param string $key Key
* @param string $value Value
* @param \IPS\DateTime|NULL $expire Expreation time, or NULL for no expiration
* @return bool
*/
protected function set( $key, $value, \IPS\DateTime $expire = NULL )
{
\IPS\Log::debug( "Set {$key} in Wincache", 'cache' );
return (bool) wincache_ucache_set( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $value, $expire ? ( $expire->getTimestamp() - time() ) : 0 );
}
/**
* Abstract Method: Exists?
*
* @param string $key Key
* @return bool
*/
protected function exists( $key )
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::debug( "Check exists {$key} from Wincache (already loaded)", 'cache' );
return ( $this->cache[ $key ] === FALSE ) ? FALSE : TRUE;
}
\IPS\Log::debug( "Check exists {$key} from Wincache", 'cache' );
return wincache_ucache_exists( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
}
/**
* Abstract Method: Delete
*
* @param string $key Key
* @return bool
*/
protected function delete( $key )
{
\IPS\Log::debug( "Delete {$key} from Wincache", 'cache' );
return (bool) wincache_ucache_delete( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
}
/**
* Abstract Method: Clear All Caches
*
* @return void
*/
public function clearAll()
{
parent::clearAll();
wincache_ucache_clear();
}
}
-98
View File
@@ -1,98 +0,0 @@
<?php
/**
* @brief XCache Cache Class
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 17 Sept 2013
*/
namespace IPS\Data\Cache;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* XCache Storage Class
*/
class _Xcache extends \IPS\Data\Cache
{
/**
* Server supports this method?
*
* @return bool
*/
public static function supported()
{
return \function_exists('xcache_get');
}
/**
* Abstract Method: Get
*
* @param string $key Key
* @return string Value from the _datastore
*/
protected function get( $key )
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::debug( "Get {$key} from Xcache (already loaded)", 'cache' );
return $this->cache[ $key ];
}
\IPS\Log::debug( "Get {$key} from Xcache", 'cache' );
$this->cache[ $key ] = xcache_get( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
return $this->cache[ $key ];
}
/**
* Abstract Method: Set
*
* @param string $key Key
* @param string $value Value
* @param \IPS\DateTime|NULL $expire Expreation time, or NULL for no expiration
* @return bool
*/
protected function set( $key, $value, \IPS\DateTime $expire = NULL )
{
\IPS\Log::debug( "Set {$key} in Xcache", 'cache' );
return (bool) xcache_set( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $value, $expire ? ( $expire->getTimestamp() - time() ) : 0 );
}
/**
* Abstract Method: Exists?
*
* @param string $key Key
* @return bool
*/
protected function exists( $key )
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::debug( "Check exists {$key} from Xcache (already loaded)", 'cache' );
return ( $this->cache[ $key ] === FALSE OR $this->cache[ $key ] === NULL ) ? FALSE : TRUE;
}
\IPS\Log::debug( "Check exists {$key} from Xcache", 'cache' );
return xcache_isset( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
}
/**
* Abstract Method: Delete
*
* @param string $key Key
* @return bool
*/
protected function delete( $key )
{
\IPS\Log::debug( "Delete {$key} from Xcache", 'cache' );
return (bool) xcache_unset( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
}
}
+29 -3
View File
@@ -26,6 +26,21 @@ abstract class _Store extends AbstractData
* @brief Instance
*/
protected static $instance;
/**
* Available Data Store Methods
* - MUST always return 'Database' and 'FileSystem' options
*
* @return array
*/
public static function availableMethods(): array
{
return [
'Database' => 'IPS\Data\Store\Database',
'FileSystem' => 'IPS\Data\Store\FileSystem',
'Redis' => 'IPS\Data\Store\Redis',
];
}
/**
* Get instance
@@ -38,7 +53,18 @@ abstract class _Store extends AbstractData
{
try
{
$classname = 'IPS\Data\Store\\' . \IPS\STORE_METHOD;
if( !isset( static::availableMethods()[ \IPS\STORE_METHOD ] ) )
{
throw new \IPS\Data\Store\Exception;
}
$classname = static::availableMethods()[ \IPS\STORE_METHOD ];
if( !$classname::supported() )
{
throw new \IPS\Data\Store\Exception;
}
static::$instance = new $classname( json_decode( \IPS\STORE_CONFIG, TRUE ) );
}
catch( \IPS\Data\Store\Exception $e )
@@ -46,11 +72,11 @@ abstract class _Store extends AbstractData
/* Fall back to MySQL (if not using it currently, and then FileSystem if we are) */
if ( \IPS\STORE_METHOD !== 'Database' )
{
$classname = 'IPS\Data\Store\Database';
$classname = static::availableMethods()['Database'];
}
else
{
$classname = 'IPS\Data\Store\FileSystem';
$classname = static::availableMethods()['FileSystem'];
}
static::$instance = new $classname( json_decode( \IPS\STORE_CONFIG, TRUE ) );