Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
@@ -1,123 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Abstract output 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 12 November 2018
|
||||
*/
|
||||
|
||||
namespace IPS\Output;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Output Caching Class
|
||||
*/
|
||||
abstract class _Cache
|
||||
{
|
||||
/**
|
||||
* @brief Instance
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* @brief Caches already retrieved this instance
|
||||
*/
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* @brief Log
|
||||
*/
|
||||
public $log = array();
|
||||
|
||||
/**
|
||||
* Get instance
|
||||
*
|
||||
* @return \IPS\Data\Cache
|
||||
*/
|
||||
public static function i()
|
||||
{
|
||||
if( static::$instance === NULL )
|
||||
{
|
||||
$classname = 'IPS\Output\Cache\\' . \IPS\OUTPUT_CACHE_METHOD;
|
||||
|
||||
if ( \class_exists( $classname ) and $classname::supported() )
|
||||
{
|
||||
try
|
||||
{
|
||||
static::$instance = new $classname();
|
||||
}
|
||||
catch( \IPS\Data\Cache\Exception $e )
|
||||
{
|
||||
static::$instance = new \IPS\Output\Cache\Database();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static::$instance = new \IPS\Output\Cache\Database();
|
||||
}
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store value
|
||||
*
|
||||
* @param string $key Key
|
||||
* @param mixed $value Value
|
||||
* @param mixed $meta Meta data (contentType, headers, etc)
|
||||
* @param \IPS\DateTime $expire Expiration if using database
|
||||
* @return bool
|
||||
*/
|
||||
public function set( $key, $value, $meta, \IPS\DateTime $expire )
|
||||
{
|
||||
if ( \IPS\CACHING_LOG )
|
||||
{
|
||||
$this->log[ microtime(true) ] = array( 'set', $key, json_encode( $value, JSON_PRETTY_PRINT ), var_export( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ), TRUE ) );
|
||||
}
|
||||
|
||||
if ( $this->_set( $key, $value, $meta, $expire ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value
|
||||
*
|
||||
* @param string $key Key
|
||||
* @return mixed
|
||||
* @throws \OutOfRangeException
|
||||
*/
|
||||
public function get( $key )
|
||||
{
|
||||
$data = $this->_get( $key );
|
||||
|
||||
if( \is_array( $data ) and \count( $data ) and isset( $data['output'] ) and isset( $data['expires'] ) )
|
||||
{
|
||||
/* Is it expired? */
|
||||
if( $data['expires'] AND time() < $data['expires'] )
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Database Output Cache Storage 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 November 2018
|
||||
*/
|
||||
|
||||
namespace IPS\Output\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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Database Output Cache Storage Class
|
||||
*/
|
||||
class _Database extends \IPS\Output\Cache
|
||||
{
|
||||
/**
|
||||
* Server supports this method?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function supported()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Method: Get
|
||||
*
|
||||
* @param string $key Key
|
||||
* @return array
|
||||
*/
|
||||
protected function _get( $key )
|
||||
{
|
||||
try
|
||||
{
|
||||
$data = \IPS\Db::i()->select( '*', 'core_output_cache', array( 'cache_key=? AND cache_expire>?', $key, time() ) )->first();
|
||||
$meta = array();
|
||||
|
||||
if ( ! empty( $data['cache_meta'] ) )
|
||||
{
|
||||
$meta = json_decode( $data['cache_meta'], TRUE );
|
||||
}
|
||||
return array( 'output' => $data['cache_value'], 'meta' => $meta, 'expires' => $data['cache_expire'] );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store value using cache method if available or falling back to the database
|
||||
*
|
||||
* @param string $key Key
|
||||
* @param mixed $value Value
|
||||
* @param mixed $meta Meta data (contentType, headers, etc)
|
||||
* @param \IPS\DateTime $expire Expiration if using database
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set( $key, $value, $meta, \IPS\DateTime $expire )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->replace( 'core_output_cache', array(
|
||||
'cache_key' => $key,
|
||||
'cache_value' => $value,
|
||||
'cache_meta' => json_encode( $meta ),
|
||||
'cache_expire' => $expire->getTimestamp()
|
||||
) );
|
||||
}
|
||||
catch( \IPS\Db\Exception $e )
|
||||
{
|
||||
\IPS\Log::debug( $e, 'guest_cache_fail' );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all expired caches
|
||||
*
|
||||
* @param boolean $truncate Truncate the table
|
||||
* @return void
|
||||
*/
|
||||
public function deleteExpired( $truncate=FALSE )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_output_cache', ( ! $truncate ? array( 'cache_expire<?', time() ) : NULL ) );
|
||||
}
|
||||
catch ( \IPS\Db\Exception $e ) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Method: Clear All Caches
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_output_cache' );
|
||||
}
|
||||
catch ( \IPS\Db\Exception $e ){}
|
||||
}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Redis 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 12 November 2018
|
||||
*/
|
||||
|
||||
namespace IPS\Output\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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redis Cache Class
|
||||
*/
|
||||
class _Redis extends \IPS\Output\Cache
|
||||
{
|
||||
/**
|
||||
* Turn on debugging which logs stats about cache hits and misses in Redis
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $debug = FALSE;
|
||||
|
||||
/**
|
||||
* Server supports this method?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function supported()
|
||||
{
|
||||
if ( class_exists('Redis') )
|
||||
{
|
||||
try
|
||||
{
|
||||
$connection = \IPS\Redis::i()->connection('read');
|
||||
|
||||
if( !$connection )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch( \RedisException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redis key
|
||||
*/
|
||||
protected $_redisKey;
|
||||
|
||||
/**
|
||||
* Get random string used in the keys to identify this site compared to other sites
|
||||
*
|
||||
* @return string|FALSE Value from the _datastore; FALSE if key doesn't exist
|
||||
*/
|
||||
protected function _getRedisKey()
|
||||
{
|
||||
if ( !$this->_redisKey )
|
||||
{
|
||||
if ( !( $this->_redisKey = \IPS\Redis::i()->get( 'redisKeyOutputCache' ) ) )
|
||||
{
|
||||
$this->_redisKey = md5( mt_rand() ) . '_pg_';
|
||||
\IPS\Redis::i()->setex( 'redisKeyOutputCache', 604800, $this->_redisKey );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_redisKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Method: Get
|
||||
*
|
||||
* @param string $key
|
||||
* @return array|FALSE Value from the _datastore; FALSE if key doesn't exist
|
||||
*/
|
||||
protected function _get( $key )
|
||||
{
|
||||
try
|
||||
{
|
||||
$value = \IPS\Redis::i()->get( $this->_getRedisKey() . '_' . $key );
|
||||
|
||||
if ( ! $value )
|
||||
{
|
||||
if ( $this->debug )
|
||||
{
|
||||
\IPS\Redis::i()->zRemRangeByScore('guest_page_failures_key_gone', 0, time() - \IPS\CACHE_PAGE_TIMEOUT );
|
||||
\IPS\Redis::i()->zAdd( 'guest_page_failures_key_gone', time(), md5(microtime()), \IPS\CACHE_PAGE_TIMEOUT );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ! $decrypted = \IPS\Text\Encrypt::fromTag( $value )->decrypt() )
|
||||
{
|
||||
if ( $this->debug )
|
||||
{
|
||||
\IPS\Redis::i()->zRemRangeByScore('guest_page_failures_decrypt', 0, time() - \IPS\CACHE_PAGE_TIMEOUT );
|
||||
\IPS\Redis::i()->zAdd( 'guest_page_failures_decrypt', time(), md5(microtime()), \IPS\CACHE_PAGE_TIMEOUT );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ! $unzipped = @gzdecode( $decrypted ) )
|
||||
{
|
||||
if ( $this->debug )
|
||||
{
|
||||
\IPS\Redis::i()->zRemRangeByScore('guest_page_failures_gz', 0, time() - \IPS\CACHE_PAGE_TIMEOUT );
|
||||
\IPS\Redis::i()->zAdd( 'guest_page_failures_gz', time(), md5(microtime()), \IPS\CACHE_PAGE_TIMEOUT );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ! $data = json_decode( $unzipped, TRUE ) )
|
||||
{
|
||||
if ( $this->debug )
|
||||
{
|
||||
\IPS\Redis::i()->zRemRangeByScore('guest_page_failures_json_decode', 0, time() - \IPS\CACHE_PAGE_TIMEOUT );
|
||||
\IPS\Redis::i()->zAdd( 'guest_page_failures_json_decode', time(), md5(microtime()), \IPS\CACHE_PAGE_TIMEOUT );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( $this->debug )
|
||||
{
|
||||
\IPS\Redis::i()->zRemRangeByScore('guest_page_hits', 0, time() - \IPS\CACHE_PAGE_TIMEOUT );
|
||||
\IPS\Redis::i()->zAdd( 'guest_page_hits', time(), md5(microtime()), \IPS\CACHE_PAGE_TIMEOUT );
|
||||
}
|
||||
|
||||
return array( 'output' => $data['value'], 'meta' => $data['meta'], 'expires' => $data['expires'] );
|
||||
}
|
||||
catch( \RedisException $e )
|
||||
{
|
||||
\IPS\Redis::i()->resetConnection( $e );
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store value using cache method if available or falling back to the database
|
||||
*
|
||||
* @param string $key Key
|
||||
* @param mixed $value Value
|
||||
* @param mixed $meta Meta data (contentType, headers, etc)
|
||||
* @param \IPS\DateTime $expire Expiration if using database
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set( $key, $value, $meta, \IPS\DateTime $expire )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( $this->debug )
|
||||
{
|
||||
\IPS\Redis::i()->zRemRangeByScore('guest_page_created', 0, time() - \IPS\CACHE_PAGE_TIMEOUT );
|
||||
\IPS\Redis::i()->zAdd( 'guest_page_created', time(), md5(microtime()), \IPS\CACHE_PAGE_TIMEOUT );
|
||||
}
|
||||
|
||||
/* json_encode > gzencode > crypt */
|
||||
return (bool) \IPS\Redis::i()->setex( $this->_getRedisKey() . '_' . $key, $expire->getTimestamp() - time(), \IPS\Text\Encrypt::fromPlaintext( gzencode( json_encode( array( 'value' => $value, 'meta' => $meta, 'expires' => $expire->getTimestamp() ) ) ) )->tag() );
|
||||
}
|
||||
catch( \RedisException $e )
|
||||
{
|
||||
\IPS\Redis::i()->resetConnection( $e );
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all expired caches
|
||||
*
|
||||
* @param boolean $truncate Truncate the table
|
||||
* @return void
|
||||
*/
|
||||
public function deleteExpired( $truncate=FALSE )
|
||||
{
|
||||
/* Redis handles this for us automatically */
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Method: Clear All Caches
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearAll()
|
||||
{
|
||||
$this->_redisKey = md5( mt_rand() ) . '_pg_';
|
||||
\IPS\Redis::i()->setex( 'redisKeyOutputCache', 604800, $this->_redisKey );
|
||||
}
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Database Output Cache Storage 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 November 2018
|
||||
*/
|
||||
|
||||
namespace IPS\Output\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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote Database Output Cache Storage Class
|
||||
*/
|
||||
class _RemoteDatabase extends \IPS\Output\Cache
|
||||
{
|
||||
/**
|
||||
* @brief Unpacked config
|
||||
*/
|
||||
protected static $config = NULL;
|
||||
|
||||
/**
|
||||
* Server supports this method?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function supported()
|
||||
{
|
||||
static::getConfig();
|
||||
return ( static::$config === NULL ) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack the config
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function getConfig()
|
||||
{
|
||||
if ( \defined('\IPS\OUTPUT_CACHE_METHOD_CONFIG') and \IPS\OUTPUT_CACHE_METHOD_CONFIG !== NULL )
|
||||
{
|
||||
static::$config = json_decode( \IPS\OUTPUT_CACHE_METHOD_CONFIG, TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Connection
|
||||
* @return \IPS\Db
|
||||
*/
|
||||
public static function db()
|
||||
{
|
||||
return \IPS\Db::i( 'remoteOutputCache', array(
|
||||
'sql_host' => static::$config['sql_host'],
|
||||
'sql_user' => static::$config['sql_user'],
|
||||
'sql_pass' => static::$config['sql_pass'],
|
||||
'sql_database' => static::$config['sql_database'],
|
||||
'sql_port' => static::$config['sql_port'],
|
||||
'sql_socket' => static::$config['sql_socket'],
|
||||
'sql_tbl_prefix'=> ( ! empty( static::$config['sql_tbl_prefix'] ) ) ? static::$config['sql_tbl_prefix'] : '',
|
||||
'sql_utf8mb4' => TRUE
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the remote DB connection is closed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
static::db()->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix any SQL issues
|
||||
*
|
||||
* @param \Exception $exception The exception object
|
||||
* @return boolean
|
||||
*/
|
||||
protected static function handleException( $exception )
|
||||
{
|
||||
if ( $exception->getCode() == 1017 or $exception->getCode() == 1146 )
|
||||
{
|
||||
/* Table does not exist */
|
||||
static::db()->createTable( static::getSchema() );
|
||||
return TRUE;
|
||||
}
|
||||
else if ( $exception->getCode() == 1054 )
|
||||
{
|
||||
/* Column doesn't exist, so drop table and recreate */
|
||||
static::db()->dropTable( 'core_output_cache' );
|
||||
static::db()->createTable( static::getSchema() );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Other errors we can't auto fix */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Method: Get
|
||||
*
|
||||
* @param string $key Key
|
||||
* @return array
|
||||
* @throws \OutOfRangeException
|
||||
*/
|
||||
protected function _get( $key )
|
||||
{
|
||||
try
|
||||
{
|
||||
$data = static::db()->select( '*', 'core_output_cache', array( 'cache_key=?', $key,) )->first();
|
||||
$meta = array();
|
||||
|
||||
if ( ! empty( $data['cache_meta'] ) )
|
||||
{
|
||||
$meta = json_decode( $data['cache_meta'], TRUE );
|
||||
}
|
||||
|
||||
if ( $data['cache_expire'] <= time() )
|
||||
{
|
||||
throw new \UnderflowException;
|
||||
}
|
||||
|
||||
return array( 'output' => $data['cache_value'], 'meta' => $meta, 'expires' => $data['cache_expire'] );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
catch ( \IPS\Db\Exception $e )
|
||||
{
|
||||
if ( static::handleException( $e ) === TRUE )
|
||||
{
|
||||
return $this->_get( $key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store value using cache method if available or falling back to the database
|
||||
*
|
||||
* @param string $key Key
|
||||
* @param mixed $value Value
|
||||
* @param mixed $meta Meta data (contentType, headers, etc)
|
||||
* @param \IPS\DateTime $expire Expiration if using database
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set( $key, $value, $meta, \IPS\DateTime $expire )
|
||||
{
|
||||
try
|
||||
{
|
||||
static::db()->replace( 'core_output_cache', array(
|
||||
'cache_key' => $key,
|
||||
'cache_value' => $value,
|
||||
'cache_meta' => json_encode( $meta ),
|
||||
'cache_expire' => $expire->getTimestamp()
|
||||
) );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch ( \IPS\Db\Exception $e )
|
||||
{
|
||||
if ( static::handleException( $e ) === TRUE )
|
||||
{
|
||||
$this->_set( $key, $value, $meta, $expire );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all expired caches
|
||||
*
|
||||
* @param boolean $truncate Truncate the table
|
||||
* @return void
|
||||
*/
|
||||
public function deleteExpired( $truncate=FALSE )
|
||||
{
|
||||
try
|
||||
{
|
||||
static::db()->delete( 'core_output_cache', ( ! $truncate ? array( 'cache_expire<?', time() ) : NULL ) );
|
||||
}
|
||||
catch ( \IPS\Db\Exception $e )
|
||||
{
|
||||
if ( static::handleException( $e ) === TRUE )
|
||||
{
|
||||
$this->deleteExpired( $truncate );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Method: Clear All Caches
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
static::db()->delete( 'core_output_cache' );
|
||||
}
|
||||
catch ( \IPS\Db\Exception $e )
|
||||
{
|
||||
if ( static::handleException( $e ) === TRUE )
|
||||
{
|
||||
$this->clearAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the tables
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function recreateTable()
|
||||
{
|
||||
try
|
||||
{
|
||||
static::db()->dropTable( 'core_output_cache' );
|
||||
static::db()->createTable( static::getSchema() );
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get schema
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function getSchema()
|
||||
{
|
||||
$schema = <<<EOF
|
||||
{
|
||||
"name": "core_output_cache",
|
||||
"columns": {
|
||||
"cache_key": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"comment": "The key",
|
||||
"decimals": null,
|
||||
"default": "",
|
||||
"length": 100,
|
||||
"name": "cache_key",
|
||||
"type": "VARCHAR",
|
||||
"unsigned": false,
|
||||
"values": []
|
||||
},
|
||||
"cache_value": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"comment": "The output HTML",
|
||||
"decimals": null,
|
||||
"default": "",
|
||||
"length": 0,
|
||||
"name": "cache_value",
|
||||
"type": "LONGTEXT",
|
||||
"unsigned": false,
|
||||
"values": []
|
||||
},
|
||||
"cache_meta": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"comment": "JSON headers and meta data",
|
||||
"decimals": null,
|
||||
"default": "",
|
||||
"length": 0,
|
||||
"name": "cache_meta",
|
||||
"type": "MEDIUMTEXT",
|
||||
"unsigned": false,
|
||||
"values": []
|
||||
},
|
||||
"cache_expire": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"comment": "Unix timestamp of when the cache expires",
|
||||
"decimals": null,
|
||||
"default": "",
|
||||
"length": null,
|
||||
"name": "cache_expire",
|
||||
"type": "INT",
|
||||
"unsigned": false,
|
||||
"values": []
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"PRIMARY": {
|
||||
"type": "primary",
|
||||
"name": "PRIMARY",
|
||||
"length": [
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"cache_key"
|
||||
]
|
||||
},
|
||||
"cache_expire": {
|
||||
"type": "key",
|
||||
"name": "cache_expire",
|
||||
"length": [
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"cache_expire"
|
||||
]
|
||||
}
|
||||
},
|
||||
"collation": "utf8mb4_unicode_ci",
|
||||
"engine": "InnoDB"
|
||||
}
|
||||
EOF;
|
||||
return json_decode( $schema, TRUE );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
+654
-596
File diff suppressed because it is too large.
Load diff
@@ -11,25 +11,28 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Address formatting
|
||||
*/
|
||||
class _Address
|
||||
class Address
|
||||
{
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if( mb_substr( $data, 0, 1 ) === '\\' OR mb_substr( $data, 0, 1 ) === '$' )
|
||||
{
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Advertisement
|
||||
*/
|
||||
class _Advertisement
|
||||
class Advertisement
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,7 +37,7 @@ class _Advertisement
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
return "\IPS\core\Advertisement::loadByLocation( '{$data}' )";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Custom Template Plugin - Template
|
||||
* @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 28 April 2023
|
||||
*/
|
||||
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use function array_keys;
|
||||
use function defined;
|
||||
use function in_array;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Template
|
||||
*/
|
||||
class Customtemplate
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return array Code to eval
|
||||
*/
|
||||
public static function runPlugin( string $data, array $options ): array
|
||||
{
|
||||
$params = ( in_array( 'params', array_keys( $options ) ) ) ? $options['params'] : '';
|
||||
$hook = ( in_array( 'hook', array_keys( $options ) ) ) ? $options['hook'] : '';
|
||||
|
||||
if( mb_strpos( $data, '$' ) === 0 )
|
||||
{
|
||||
$data = '{' . $data . '}';
|
||||
}
|
||||
|
||||
return [ 'return' => "\\IPS\\Theme\\CustomTemplate::getCustomTemplatesForHookPoint( \"{$data}\", \"{$hook}\", [ {$params} ] )" ];
|
||||
}
|
||||
}
|
||||
@@ -11,30 +11,33 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - DateTime
|
||||
*/
|
||||
class _Datetime
|
||||
class Datetime
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @return array Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): array
|
||||
{
|
||||
$return = array();
|
||||
$return['pre'] = '$val = ( ' . $data . ' instanceof \IPS\DateTime ) ? ' . $data . ' : \IPS\DateTime::ts( ' . $data . ' );';
|
||||
|
||||
@@ -11,21 +11,25 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Theme;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Expression
|
||||
*/
|
||||
class _Expression
|
||||
class Expression
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,15 +38,15 @@ class _Expression
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if( isset( $options['raw'] ) AND $options['raw'] )
|
||||
{
|
||||
return \IPS\Theme::expandShortcuts( $data );
|
||||
return Theme::expandShortcuts( $data );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'htmlspecialchars( ' . \IPS\Theme::expandShortcuts( $data ) . ', ENT_QUOTES | ENT_DISALLOWED, \'UTF-8\', FALSE )';
|
||||
return '\IPS\Theme\Template::htmlspecialchars( ' . Theme::expandShortcuts( $data ) . ', ENT_QUOTES | ENT_DISALLOWED, \'UTF-8\', FALSE )';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,21 +11,26 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\File as SystemFile;
|
||||
use IPS\Request;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - File
|
||||
*/
|
||||
class _File
|
||||
class File
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,16 +39,16 @@ class _File
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
$extension = ( isset( $options['extension'] ) ? $options['extension'] : 'core_Attachment' );
|
||||
$scheme = ( isset( $options['scheme'] ) ? $options['scheme'] : NULL );
|
||||
$cacheBust = ( isset( $options['cb'] ) ? $options['cb'] : NULL );
|
||||
$extension = ( $options['extension'] ?? 'core_Attachment' );
|
||||
$scheme = ( $options['scheme'] ?? NULL );
|
||||
$cacheBust = ( $options['cb'] ?? NULL );
|
||||
$schemeString = $cbString = '';
|
||||
|
||||
if ( $scheme )
|
||||
{
|
||||
$fullScheme = ( \IPS\Request::i()->isSecure() ) ? 'https' : 'http';
|
||||
$fullScheme = ( Request::i()->isSecure() ) ? 'https' : 'http';
|
||||
$schemeString = ( $scheme == 'full' ) ? '->setScheme("' . $fullScheme .'")' : '->setScheme(NULL)';
|
||||
}
|
||||
|
||||
@@ -51,7 +56,8 @@ class _File
|
||||
{
|
||||
$cbString = "->setQueryString( 'v', " . $cacheBust . ")";
|
||||
}
|
||||
if ( $data instanceof \IPS\File )
|
||||
|
||||
if ( $data instanceof SystemFile )
|
||||
{
|
||||
return "(string) " . $data . "->url" . $schemeString . $cbString;
|
||||
}
|
||||
|
||||
@@ -11,30 +11,35 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Member;
|
||||
use function defined;
|
||||
use function floatval;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Filesize
|
||||
*/
|
||||
class _Filesize
|
||||
class Filesize
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return array array( 'pre' => Code to eval before 'return', 'return' => Code to eval to return desired value )
|
||||
* @return string array( 'pre' => Code to eval before 'return', 'return' => Code to eval to return desired value )
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
return '\IPS\Output\Plugin\Filesize::humanReadableFilesize( ' . $data . ( ( isset( $options['decimal'] ) and $options['decimal'] ) ? ', TRUE' : '' ) . ' )';
|
||||
}
|
||||
@@ -42,15 +47,15 @@ class _Filesize
|
||||
/**
|
||||
* Get human readable filesize (to 2SF)
|
||||
*
|
||||
* @param int $sizeInBytes Size in bytes
|
||||
* @param int|null $sizeInBytes Size in bytes
|
||||
* @param bool $decimal If TRUE, will calculate based on decimal figures rather than binary
|
||||
* @param bool $json If TRUE, will format for json
|
||||
* @param bool $get If TRUE, will get the language string rather than add to stack
|
||||
* @return string
|
||||
*/
|
||||
public static function humanReadableFilesize( $sizeInBytes, $decimal=FALSE, $json=FALSE, $get=FALSE )
|
||||
public static function humanReadableFilesize( ?int $sizeInBytes, bool $decimal=FALSE, bool $json=FALSE, bool $get=FALSE ) : string
|
||||
{
|
||||
$sizeInBytes = \floatval( $sizeInBytes );
|
||||
$sizeInBytes = floatval( $sizeInBytes );
|
||||
|
||||
foreach ( array( 'Y' => 80, 'Z' => 70, 'E' => 60, 'P' => 50, 'T' => 40, 'G' => 30, 'M' => 20, 'k' => 10 ) as $sig => $pow )
|
||||
{
|
||||
@@ -59,7 +64,7 @@ class _Filesize
|
||||
{
|
||||
if ( $get )
|
||||
{
|
||||
return sprintf( \IPS\Member::loggedIn()->language()->get( 'filesize_' . $sig ), round( ( $sizeInBytes / $raised ), 2 ) );
|
||||
return sprintf( Member::loggedIn()->language()->get( 'filesize_' . $sig ), round( ( $sizeInBytes / $raised ), 2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -70,14 +75,14 @@ class _Filesize
|
||||
$format['json'] = TRUE;
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'filesize_' . $sig, FALSE, $format );
|
||||
return Member::loggedIn()->language()->addToStack( 'filesize_' . $sig, FALSE, $format );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $get )
|
||||
{
|
||||
return sprintf( \IPS\Member::loggedIn()->language()->get( 'filesize_b' ), $sizeInBytes );
|
||||
return sprintf( Member::loggedIn()->language()->get( 'filesize_b' ), $sizeInBytes );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -88,7 +93,7 @@ class _Filesize
|
||||
$format['json'] = TRUE;
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'filesize_b', FALSE, $format );
|
||||
return Member::loggedIn()->language()->addToStack( 'filesize_b', FALSE, $format );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,21 +11,26 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
use function intval;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Font size
|
||||
* @note this is still required as the ACP relies on this
|
||||
*/
|
||||
class _Fontsize
|
||||
class Fontsize
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,21 +39,35 @@ class _Fontsize
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
$number = 14;
|
||||
|
||||
/* Create the array for the ACP based on v4 font-sizes @todo review this! */
|
||||
$sizes = [
|
||||
'font_base' => 16,
|
||||
'font_large' => 18,
|
||||
'font_medium' => 14,
|
||||
'font_small' => 13,
|
||||
'font_x_large' => 20,
|
||||
'font_x_small' => 12,
|
||||
'font_2x_large' => 24,
|
||||
'font_3x_large' => 30,
|
||||
'font_4x_large' => 36,
|
||||
'font_size' => 100,
|
||||
];
|
||||
|
||||
// Is this a theme setting or a number?
|
||||
if( preg_match('/^[0-9]+?$/', $data ) )
|
||||
{
|
||||
$number = \intval( $data );
|
||||
$number = intval( $data );
|
||||
}
|
||||
else if ( isset( \IPS\Theme::i()->settings[ 'font_' . $data ] ) )
|
||||
else if ( isset( $sizes[ 'font_' . $data ] ) )
|
||||
{
|
||||
$number = \IPS\Theme::i()->settings[ 'font_' . $data ];
|
||||
$number = $sizes[ 'font_' . $data ];
|
||||
}
|
||||
|
||||
$scale = isset( \IPS\Theme::i()->settings['font_size'] ) ? \intval( \IPS\Theme::i()->settings['font_size'] ) : 100;
|
||||
$scale = $sizes['font_size'];
|
||||
|
||||
// Should we be scaling?
|
||||
if( $scale !== 100 && ( !isset( $options['scale'] ) || $options['scale'] !== false ) )
|
||||
|
||||
@@ -11,21 +11,29 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Settings;
|
||||
use IPS\Theme;
|
||||
use function defined;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - hextorgb
|
||||
*/
|
||||
class _Hextorgb
|
||||
class Hextorgb
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in. Take #ffffff and returns 255,255,255, for example
|
||||
@@ -34,7 +42,7 @@ class _Hextorgb
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if( $data[0] !== '$' ){
|
||||
$data = "'" . $data . "'";
|
||||
@@ -52,62 +60,62 @@ class _Hextorgb
|
||||
/**
|
||||
* Convert Hex value to RGB
|
||||
*
|
||||
* @param string $data Hex color code
|
||||
* @param string $opacity Opacity (0-1) or Setting/Theme Setting name
|
||||
* @param string $data Hex color code
|
||||
* @param string $opacity Opacity (0-1) or Setting/Theme Setting name
|
||||
* @return string
|
||||
*/
|
||||
public static function convertToRGB( $data, $opacity )
|
||||
public static function convertToRGB( string $data, string $opacity ): string
|
||||
{
|
||||
$output = array();
|
||||
|
||||
/* If a theme setting key has been passed in, then use that as the value */
|
||||
if ( isset( \IPS\Theme::i()->settings[ $data ] ) )
|
||||
if ( isset( Theme::i()->settings[ $data ] ) )
|
||||
{
|
||||
$data = \IPS\Theme::i()->settings[ $data ];
|
||||
$data = Theme::i()->settings[ $data ];
|
||||
}
|
||||
|
||||
/* If a regular setting key has been passed in, then use that as the value */
|
||||
if ( isset( \IPS\Settings::i()->$data ) )
|
||||
if ( isset( Settings::i()->$data ) )
|
||||
{
|
||||
$data = \IPS\Settings::i()->$data;
|
||||
$data = Settings::i()->$data;
|
||||
}
|
||||
|
||||
/* If a theme setting key has been passed in, then use that as the opacity */
|
||||
if ( isset( \IPS\Theme::i()->settings[ $opacity ] ) )
|
||||
if ( isset( Theme::i()->settings[ $opacity ] ) )
|
||||
{
|
||||
$opacity = \IPS\Theme::i()->settings[ $opacity ];
|
||||
$opacity = Theme::i()->settings[ $opacity ];
|
||||
}
|
||||
|
||||
/* If a regular setting key has been passed in, then use that as the opacity */
|
||||
if ( isset( \IPS\Settings::i()->$opacity ) )
|
||||
if ( isset( Settings::i()->$opacity ) )
|
||||
{
|
||||
$opacity = \IPS\Settings::i()->$opacity;
|
||||
$opacity = Settings::i()->$opacity;
|
||||
}
|
||||
|
||||
/* Basic validation */
|
||||
if( !preg_match( "/^#?[0-9a-fA-F]+$/", $data ) OR ( \strlen( str_replace( '#', '', $data ) ) !== 3 AND \strlen( str_replace( '#', '', $data ) ) !== 6 ) )
|
||||
if( !preg_match( "/^#?[0-9a-fA-F]+$/", $data ) OR ( strlen( str_replace( '#', '', $data ) ) !== 3 AND strlen( str_replace( '#', '', $data ) ) !== 6 ) )
|
||||
{
|
||||
return "htmlspecialchars( '" . $data . "', ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE )";
|
||||
}
|
||||
|
||||
$data = str_replace( '#', '', $data );
|
||||
|
||||
if ( \strlen( $data ) == 3 )
|
||||
if ( strlen( $data ) == 3 )
|
||||
{
|
||||
$output[] = hexdec( \substr( $data, 0, 1 ) . \substr( $data, 0, 1 ) ); // R
|
||||
$output[] = hexdec( \substr( $data, 1, 1 ) . \substr( $data, 1, 1 ) ); // G
|
||||
$output[] = hexdec( \substr( $data, 2, 1 ) . \substr( $data, 2, 1 ) ); // B
|
||||
$output[] = hexdec( substr( $data, 0, 1 ) . substr( $data, 0, 1 ) ); // R
|
||||
$output[] = hexdec( substr( $data, 1, 1 ) . substr( $data, 1, 1 ) ); // G
|
||||
$output[] = hexdec( substr( $data, 2, 1 ) . substr( $data, 2, 1 ) ); // B
|
||||
}
|
||||
else
|
||||
{
|
||||
$output[] = hexdec( \substr( $data, 0, 2 ) ); // R
|
||||
$output[] = hexdec( \substr( $data, 2, 2 ) ); // G
|
||||
$output[] = hexdec( \substr( $data, 4, 2 ) ); // B
|
||||
$output[] = hexdec( substr( $data, 0, 2 ) ); // R
|
||||
$output[] = hexdec( substr( $data, 2, 2 ) ); // G
|
||||
$output[] = hexdec( substr( $data, 4, 2 ) ); // B
|
||||
}
|
||||
|
||||
if( isset( $opacity ) && $opacity !== '1' )
|
||||
{
|
||||
return "rgba(" . implode( ',', $output ) . "," . \str_replace( ',', '.', $opacity ) . ")";
|
||||
return "rgba(" . implode( ',', $output ) . "," . str_replace( ',', '.', $opacity ) . ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Include PHP file
|
||||
*/
|
||||
class _Insert
|
||||
class Insert
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,7 +37,7 @@ class _Insert
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
return '\IPS\Output::safeInclude( "' . $data . '" )';
|
||||
}
|
||||
|
||||
@@ -11,21 +11,28 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Theme;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Lang
|
||||
*/
|
||||
class _Lang
|
||||
class Lang
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,17 +41,17 @@ class _Lang
|
||||
* @param array $options Array of options
|
||||
* @return array array( 'pre' => Code to eval before 'return', 'return' => Code to eval to return desired value )
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): array
|
||||
{
|
||||
$return = array();
|
||||
$return['pre'] = null;
|
||||
$params = array();
|
||||
|
||||
$data = \IPS\Theme::expandShortcuts( $data );
|
||||
$data = Theme::expandShortcuts( $data );
|
||||
|
||||
if( \substr( $data, 0, 1 ) !== '\\' and \strpos( $data, '$' ) !== FALSE )
|
||||
if( substr( $data, 0, 1 ) !== '\\' and strpos( $data, '$' ) !== FALSE )
|
||||
{
|
||||
if ( \strpos( $data, '$' ) === 0 )
|
||||
if ( strpos( $data, '$' ) === 0 )
|
||||
{
|
||||
|
||||
$data = '{' . $data . '}';
|
||||
@@ -109,7 +116,7 @@ class _Lang
|
||||
|
||||
$vle = 'TRUE';
|
||||
|
||||
if( \count( $params ) )
|
||||
if( count( $params ) )
|
||||
{
|
||||
$vle = 'FALSE';
|
||||
}
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Member Data
|
||||
*/
|
||||
class _Member
|
||||
class Member
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,14 +37,14 @@ class _Member
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if ( $data !== 'link()' and isset( $options['group'] ) )
|
||||
{
|
||||
$data = "group['{$data}']";
|
||||
}
|
||||
|
||||
$raw = ( isset( $options['raw'] ) AND $options['raw'] ) ? TRUE : FALSE;
|
||||
$raw = ( isset( $options['raw'] ) AND $options['raw'] );
|
||||
|
||||
if ( isset( $options['id'] ) )
|
||||
{
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Number
|
||||
*/
|
||||
class _Number
|
||||
class Number
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,7 +37,7 @@ class _Number
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if ( isset( $options['format'] ) and $options['format'] === 'short' )
|
||||
{
|
||||
|
||||
@@ -11,35 +11,39 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
use function in_array;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Vendor prefix
|
||||
*/
|
||||
class _Prefix
|
||||
class Prefix
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Defined here so that we can remove names later as browser support for the non-prefixed version improves, without changing our css.
|
||||
*
|
||||
* @brief The styles this plugin will prefix
|
||||
*/
|
||||
protected static $supportedStyles = array(
|
||||
protected static array $supportedStyles = array(
|
||||
'user-select'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Supported vendor prefixes
|
||||
*/
|
||||
protected static $prefixes = array( '-webkit-', '-moz-', '-ms-', '-o-', '' );
|
||||
protected static array $prefixes = array( '-webkit-', '-moz-', '-ms-', '-o-', '' );
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -49,9 +53,9 @@ class _Prefix
|
||||
* @return string Code to eval
|
||||
* @note Occasionally a style isn't consistent between browsers, so simply adding a prefix isn't always sufficient - you may need other CSS to resolve browser inconsistencies
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if ( \in_array( $data, static::$supportedStyles ) )
|
||||
if ( in_array( $data, static::$supportedStyles ) )
|
||||
{
|
||||
$output = array();
|
||||
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Request
|
||||
*/
|
||||
class _Request
|
||||
class Request
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,15 +37,15 @@ class _Request
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if( isset( $options['raw'] ) AND $options['raw'] )
|
||||
{
|
||||
return "\IPS\Request::i()->$data";
|
||||
return "isset( \IPS\Widget\Request::i()->$data ) ? \IPS\Widget\Request::i()->$data : NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "htmlspecialchars( \IPS\Request::i()->$data, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE )";
|
||||
return "isset( \IPS\Widget\Request::i()->$data ) ? htmlspecialchars( \IPS\Widget\Request::i()->$data, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ): NULL";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,37 +11,67 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\Application;
|
||||
use IPS\Data\Cache;
|
||||
use IPS\IPS;
|
||||
use IPS\Member;
|
||||
use IPS\Theme;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Theme Resource (image, font, theme-specific JS, etc)
|
||||
*/
|
||||
class _Resource
|
||||
class Resource
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param string $context The name of the calling function
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param string $context The name of the calling function
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options, $context )
|
||||
public static function runPlugin( string $data, array $options, string $context ): string
|
||||
{
|
||||
$exploded = explode( '_', $context );
|
||||
$app = ( isset( $options['app'] ) ? $options['app'] : ( isset( $exploded[1] ) ? $exploded[1] : '' ) );
|
||||
$location = ( isset( $options['location'] ) ? $options['location'] : ( isset( $exploded[2] ) ? $exploded[2] : '' ) );
|
||||
$app = ( $options['app'] ?? ( $exploded[1] ?? 'core' ) );
|
||||
$location = ( $options['location'] ?? ( $exploded[2] ?? 'front' ) );
|
||||
$noProtocol = ( isset( $options['noprotocol'] ) ) ? $options['noprotocol'] : "false";
|
||||
|
||||
if ( ( ! \IPS\IN_DEV or Application::areWeBuilding() ) and isset( $options['inCss'] ) and $options['inCss'] and $app and in_array( $app, IPS::$ipsApps ) )
|
||||
{
|
||||
/* We can use a relative path */
|
||||
$paths = explode( '/', $data );
|
||||
$name = array_pop( $paths );
|
||||
$path = ( count( $paths ) ) ? ( '/' . implode( '/', $paths ) . '/' ) : '/';
|
||||
$hash = Theme::makeBuiltTemplateLookupHash( $app, $location, $path );
|
||||
|
||||
if ( $location === 'interface' )
|
||||
{
|
||||
return '"../../applications/' . $app . '/interface/' . $data . '"';
|
||||
}
|
||||
|
||||
return '"../resources/' . $app . '_' . $hash . '_' . $name . '"';
|
||||
}
|
||||
|
||||
return "\\IPS\\Theme::i()->resource( \"{$data}\", \"{$app}\", '{$location}', {$noProtocol} )";
|
||||
}
|
||||
}
|
||||
@@ -11,22 +11,25 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Setting
|
||||
*/
|
||||
class _Setting
|
||||
class Setting
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
* @note Using setting in plugins will require a rebuild of the CSS file they're used in when the setting is changed
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -35,7 +38,7 @@ class _Setting
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if ( isset( $options['escape'] ) )
|
||||
{
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Strip HTML tags
|
||||
*/
|
||||
class _Striptags
|
||||
class Striptags
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,7 +37,7 @@ class _Striptags
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
return "strip_tags( $data )";
|
||||
}
|
||||
|
||||
@@ -11,32 +11,39 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Theme;
|
||||
use function defined;
|
||||
use function in_array;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Template
|
||||
*/
|
||||
class _Template
|
||||
class Template
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param string|null $functionName
|
||||
* @param string $calledClass
|
||||
* @return array|string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options, $functionName=NULL, $calledClass='IPS\Theme' )
|
||||
public static function runPlugin( string $data, array $options, ?string $functionName=NULL, string $calledClass='IPS\Theme' ): array|string
|
||||
{
|
||||
$params = ( \in_array( 'params', array_keys( $options ) ) ) ? $options['params'] : '';
|
||||
$params = ( in_array( 'params', array_keys( $options ) ) ) ? $options['params'] : '';
|
||||
if( mb_strpos( $data, '$' ) === 0 )
|
||||
{
|
||||
$data = '{' . $data . '}';
|
||||
@@ -63,7 +70,7 @@ class _Template
|
||||
|
||||
if ( isset( $options['if'] ) )
|
||||
{
|
||||
$it['pre'] = "if ( " . \IPS\Theme::expandShortcuts( $options['if'] ) . " ):\n";
|
||||
$it['pre'] = "if ( " . Theme::expandShortcuts( $options['if'] ) . " ):\n";
|
||||
$it['post'] = "\nendif;";
|
||||
}
|
||||
|
||||
|
||||
@@ -11,49 +11,94 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use InvalidArgumentException;
|
||||
use IPS\cloud\extensions\core\AccountSettings\Expert;
|
||||
use IPS\Log;
|
||||
use IPS\Theme as SystemTheme;
|
||||
use IPS\Theme\Editor\Setting;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use function mb_substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Theme settings
|
||||
*/
|
||||
class _Theme
|
||||
class Theme
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @return mixed Code to eval
|
||||
* @note Using this plugin to call the sharer logos or favicon is deprecated and will be removed in a future version
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): mixed
|
||||
{
|
||||
switch( $data )
|
||||
{
|
||||
case 'headerHtml':
|
||||
return \IPS\Theme::i()->getHeaderAndFooter()['header'];
|
||||
break;
|
||||
return "\IPS\Theme::i()->getHeaderAndFooter( 'header' )";
|
||||
|
||||
case 'footerHtml':
|
||||
return \IPS\Theme::i()->getHeaderAndFooter()['footer'];
|
||||
break;
|
||||
return "\IPS\Theme::i()->getHeaderAndFooter( 'footer' )";
|
||||
|
||||
case 'logo_front':
|
||||
return "\IPS\Theme::i()->logo_front";
|
||||
break;
|
||||
|
||||
case 'logo_height':
|
||||
return ( isset( \IPS\Theme::i()->logo['front']['height'] ) ) ? '\IPS\Theme::i()->logo[\'front\'][\'height\']' : 100;
|
||||
break;
|
||||
return ( isset( SystemTheme::i()->logo['front']['height'] ) ) ? '\IPS\Theme::i()->logo[\'front\'][\'height\']' : 100;
|
||||
|
||||
case 'custom_css_for_output':
|
||||
return "\IPS\Theme::i()->getCustomCssForOutput()";
|
||||
|
||||
case 'custom_css':
|
||||
return "\IPS\Theme::i()->custom_css";
|
||||
|
||||
case "scheme":
|
||||
return "\IPS\Theme::i()->getCurrentCSSScheme()";
|
||||
|
||||
case 'id':
|
||||
return "\IPS\Theme::i()->id";
|
||||
default:
|
||||
return ( isset( \IPS\Theme::i()->settings[ $data ] ) ) ? "\IPS\Theme::i()->settings['{$data}']" : '';
|
||||
break;
|
||||
try
|
||||
{
|
||||
if ( mb_substr( $data, 0, 4 ) === 'css.' or mb_substr( $data, 0, 4 ) === 'var.' )
|
||||
{
|
||||
$variable = mb_substr( $data, 4 );
|
||||
$cssVariables = SystemTheme::i()->getCssVariables();
|
||||
|
||||
if( array_key_exists( $variable, $cssVariables ) )
|
||||
{
|
||||
return "\IPS\Theme::i()->getParsedCssVariableFromKey( '{$variable}' )";
|
||||
}
|
||||
return '';
|
||||
}
|
||||
else if ( mb_substr( $data, 0, 5 ) === 'view.' )
|
||||
{
|
||||
$variable = mb_substr( $data, 5 );
|
||||
return "\IPS\Theme::i()->getLayoutValue('{$variable}')";
|
||||
}
|
||||
|
||||
return ( array_key_exists( $data, SystemTheme::i()->settings ) ) ? "\IPS\Theme::i()->settings['{$data}']" : '';
|
||||
}
|
||||
catch( InvalidArgumentException $e )
|
||||
{
|
||||
Log::log( $e, 'template_error' );
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Truncate
|
||||
*/
|
||||
class _Truncate
|
||||
class Truncate
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,7 +37,7 @@ class _Truncate
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
if( !$options['length'] )
|
||||
{
|
||||
|
||||
@@ -11,21 +11,27 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Http\Url as HttpUrl;
|
||||
use function defined;
|
||||
use function in_array;
|
||||
use function substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - URL
|
||||
*/
|
||||
class _Url
|
||||
class Url
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -34,7 +40,7 @@ class _Url
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
$csrf = '';
|
||||
|
||||
@@ -43,7 +49,7 @@ class _Url
|
||||
$csrf = ' . "&csrfKey=" . \IPS\Session::i()->csrfKey';
|
||||
}
|
||||
|
||||
$location = ( \in_array( 'base', array_keys( $options ) ) ) ? '"' . $options['base'] . '"' : 'null';
|
||||
$location = ( in_array( 'base', array_keys( $options ) ) ) ? '"' . $options['base'] . '"' : 'null';
|
||||
|
||||
if ( !isset( $options['seoTemplate'] ) )
|
||||
{
|
||||
@@ -60,7 +66,7 @@ class _Url
|
||||
|
||||
if ( !isset( $options['protocol'] ) )
|
||||
{
|
||||
$options['protocol'] = \IPS\Http\Url::PROTOCOL_AUTOMATIC;
|
||||
$options['protocol'] = HttpUrl::PROTOCOL_AUTOMATIC;
|
||||
}
|
||||
|
||||
$fragment = "";
|
||||
@@ -74,7 +80,7 @@ class _Url
|
||||
if ( isset( $options['ref'] ) )
|
||||
{
|
||||
/* Is this a variable or other dynamic thing? */
|
||||
if ( \in_array( \substr( $options['ref'], 0, 1 ), array( '(', '$', '\\' ) ) )
|
||||
if ( in_array( substr( $options['ref'], 0, 1 ), array( '(', '$', '\\' ) ) )
|
||||
{
|
||||
$ref = "->addRef(";
|
||||
$ref .= $options['ref'];
|
||||
|
||||
@@ -11,21 +11,24 @@
|
||||
namespace IPS\Output\Plugin;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Truncate
|
||||
*/
|
||||
class _Wordbreak
|
||||
class Wordbreak
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
@@ -35,7 +38,7 @@ class _Wordbreak
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string
|
||||
{
|
||||
return "htmlspecialchars( {$data}, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE )";
|
||||
}
|
||||
|
||||
+177
-31
@@ -11,48 +11,61 @@
|
||||
namespace IPS\Output;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Dispatcher;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Output;
|
||||
use IPS\Theme;
|
||||
use function defined;
|
||||
use function strstr;
|
||||
use function uniqid;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output Class
|
||||
*/
|
||||
class _System extends \IPS\Output
|
||||
class System extends Output
|
||||
{
|
||||
/**
|
||||
* Display Error Screen
|
||||
*
|
||||
* @param string $message language key for error message
|
||||
* @param mixed $code Error code
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param string $adminMessage language key for error message to show to admins
|
||||
* @param array $httpHeaders Additional HTTP Headers
|
||||
* @param string $extra Additional information (such as API error)
|
||||
* @return void
|
||||
* @param string $message language key for error message
|
||||
* @param mixed $code Error code
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param string|null $adminMessage language key for error message to show to admins
|
||||
* @param array $httpHeaders Additional HTTP Headers
|
||||
* @param string|null $extra Additional information (such as API error)
|
||||
* @param int|string|null $faultyAppOrHookId
|
||||
* @return void
|
||||
*/
|
||||
public function error( $message, $code, $httpStatusCode=500, $adminMessage=NULL, $httpHeaders=array(), $extra=NULL )
|
||||
public function error( string $message, mixed $code, int $httpStatusCode=500, string $adminMessage=NULL, array $httpHeaders=array(), string $extra=NULL, int|string $faultyAppOrHookId=NULL ) : void
|
||||
{
|
||||
/* Send output */
|
||||
$this->sendOutput( \IPS\Theme\System\Theme::i()->getTemplate('global', 'core', 'global')->error( $message ), $httpStatusCode, 'text/html', $httpHeaders );
|
||||
$this->sendOutput( Theme::i()->getTemplate('global', 'core', 'global')->error( $message ), $httpStatusCode, 'text/html', $httpHeaders );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send output
|
||||
*
|
||||
* @param string $output Content to output
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param string $contentType HTTP Content-type
|
||||
* @param array $httpHeaders Additional HTTP Headers
|
||||
* @param bool $cache Allows the page to be cached - set to FALSE when sending a cached page
|
||||
* @return void
|
||||
* @param string $output Content to output
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param string $contentType HTTP Content-type
|
||||
* @param array $httpHeaders Additional HTTP Headers
|
||||
* @param bool $cacheThisPage
|
||||
* @param bool $pageIsCached
|
||||
* @param bool $parseFileObjects
|
||||
* @param bool $parseEmoji
|
||||
* @return void
|
||||
*/
|
||||
public function sendOutput( $output='', $httpStatusCode=200, $contentType='text/html', $httpHeaders=array(), $cache=TRUE )
|
||||
public function sendOutput(string $output='', int $httpStatusCode=200, string $contentType='text/html', array $httpHeaders=array(), bool $cacheThisPage=TRUE, bool $pageIsCached=FALSE, bool $parseFileObjects=TRUE, bool $parseEmoji=TRUE ) : void
|
||||
{
|
||||
/* Set HTTP status */
|
||||
if( isset( $_SERVER['SERVER_PROTOCOL'] ) and \strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) !== false )
|
||||
if( isset( $_SERVER['SERVER_PROTOCOL'] ) and strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) !== false )
|
||||
{
|
||||
header( "HTTP/1.0 {$httpStatusCode} " . static::$httpStatuses[ $httpStatusCode ] );
|
||||
}
|
||||
@@ -64,7 +77,7 @@ class _System extends \IPS\Output
|
||||
/* Buffer output */
|
||||
if ( $output )
|
||||
{
|
||||
if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) and \strstr( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) !== false and (bool) ini_get('zlib.output_compression') === false )
|
||||
if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) and strstr( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) !== false and (bool) ini_get('zlib.output_compression') === false )
|
||||
{
|
||||
ob_start('ob_gzhandler');
|
||||
}
|
||||
@@ -73,7 +86,7 @@ class _System extends \IPS\Output
|
||||
ob_start();
|
||||
}
|
||||
|
||||
print \IPS\Theme\System\Theme::i()->getTemplate('global', 'core', 'global')->globalTemplate( $output, static::i()->title, array( 'app' => \IPS\Dispatcher::i()->application->directory, 'module' => \IPS\Dispatcher::i()->module->key, 'controller' => \IPS\Dispatcher::i()->controller ) );
|
||||
print Theme::i()->getTemplate('global', 'core', 'global')->globalTemplate( $output, static::i()->title, array( 'app' => Dispatcher::i()->application->directory, 'module' => Dispatcher::i()->module->key, 'controller' => Dispatcher::i()->controller ) );
|
||||
}
|
||||
|
||||
/* Send headers */
|
||||
@@ -91,23 +104,156 @@ class _System extends \IPS\Output
|
||||
flush();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Redirect
|
||||
*
|
||||
* @param \IPS\Http\Url $url URL to redirect to
|
||||
* @param string $message Optional message to display
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param bool $forceScreen If TRUE, an intermeditate screen will be shown
|
||||
* @return void
|
||||
* @param Url|string $url URL to redirect to
|
||||
* @param string|null $message Optional message to display
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param bool $forceScreen If TRUE, an intermeditate screen will be shown
|
||||
* @return void
|
||||
*/
|
||||
public function redirect( $url, $message='', $httpStatusCode=303, $forceScreen=FALSE )
|
||||
public function redirect( Url|string $url, ?string $message='', int $httpStatusCode=301, bool $forceScreen=FALSE ) : void
|
||||
{
|
||||
if ( $forceScreen === TRUE )
|
||||
{
|
||||
$this->sendOutput( \IPS\Theme\System\Theme::i()->getTemplate( 'global', 'core', 'global' )->redirect( $url, $message ), $httpStatusCode );
|
||||
$this->sendOutput( Theme::i()->getTemplate( 'global', 'core', 'global' )->redirect( $url, $message ), $httpStatusCode );
|
||||
}
|
||||
|
||||
$this->sendOutput( '', $httpStatusCode, '', array( "Location: {$url}" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HTML file of the MySQL debug backtrace
|
||||
*
|
||||
* @param array $debug
|
||||
* @return string
|
||||
*/
|
||||
public static function generateDbLogHtml( array $debug ): string
|
||||
{
|
||||
$queryCount = count( $debug ) - 1; # The first query is the connection
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MySQL Debug Log</title>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
table {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: left;
|
||||
}
|
||||
td.query {
|
||||
font-family: monospace;
|
||||
word-wrap: break-word;
|
||||
font-size: 14px;
|
||||
text-wrap: wrap;
|
||||
}
|
||||
|
||||
td.details {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
tr.collapsible-content {
|
||||
display: none;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.toggle-button {
|
||||
cursor: pointer;
|
||||
color: blue;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function toggleRow(id) {
|
||||
const rows = document.querySelectorAll(`[data-row="content-\${id}"]`);
|
||||
// Loop through each row and toggle visibility
|
||||
rows.forEach(row => {
|
||||
if (row.style.display === "none") {
|
||||
document.querySelector(`td[data-query="\${id}"]`).style.backgroundColor = "lightblue";
|
||||
// If the row is hidden, show it
|
||||
row.style.display = "table-row";
|
||||
} else {
|
||||
// If the row is visible, hide it
|
||||
document.querySelector(`td[data-query="\${id}"]`).style.backgroundColor = "transparent";
|
||||
row.style.display = "none";
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>{$queryCount} Queries</h1>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Function</th>
|
||||
<th>File</th>
|
||||
<th>Line</th>
|
||||
<th style="width:150px">Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
HTML;
|
||||
|
||||
foreach ($debug as $index => $data)
|
||||
{
|
||||
$unique = md5( $data['query'] . uniqid() );
|
||||
$html .= <<<HTML
|
||||
<tr>
|
||||
<td data-query="{$unique}" colspan="3" class="query">{$data['query']}</td>
|
||||
<td class="details"><span class="toggle-button" onclick="toggleRow('{$unique}')">Expand/Collapse</span></td>
|
||||
</tr>
|
||||
HTML;
|
||||
|
||||
foreach( $data['backtrace'] as $id => $trace )
|
||||
{
|
||||
$trace['file'] = isset( $trace['file'] ) ? str_replace( \IPS\ROOT_PATH, '', $trace['file'] ) : '';
|
||||
$trace['line'] = $trace['line'] ?? '';
|
||||
$html .= <<<HTML
|
||||
<tr data-row="content-{$unique}" style="display: none" class="collapsible-content">
|
||||
<td>
|
||||
{$trace['function']}
|
||||
</td>
|
||||
<td>
|
||||
{$trace['file']}
|
||||
</td>
|
||||
<td>
|
||||
{$trace['line']}
|
||||
</td>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
||||
$html .= <<<HTML
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace IPS\Output\UI;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
|
||||
use IPS\Content\Comment as BaseComment;
|
||||
use IPS\Content\Item as BaseItem;
|
||||
use IPS\Helpers\Form\FormAbstract;
|
||||
use IPS\Helpers\Menu\MenuItem;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
abstract class Comment
|
||||
{
|
||||
/**
|
||||
* This needs to be declared in any child classes as well
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
public static ?string $class = NULL;
|
||||
|
||||
/**
|
||||
* Can be used to add additional css classes to the comment
|
||||
*
|
||||
* @param BaseComment $comment
|
||||
* @return string
|
||||
*/
|
||||
public function css( BaseComment $comment ): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to add additional data attributes to the comment
|
||||
*
|
||||
* @param BaseComment $comment
|
||||
* @return string
|
||||
*/
|
||||
public function dataAttributes( BaseComment $comment ): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to attach additional content to the author panel
|
||||
*
|
||||
* @param BaseComment $comment
|
||||
* @return string
|
||||
*/
|
||||
public function authorPanel( BaseComment $comment ): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns additional menu items for the comment menu
|
||||
*
|
||||
* @param BaseComment $comment
|
||||
* @return array<string,MenuItem>
|
||||
*/
|
||||
public function menuItems( BaseComment $comment ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add elements to the comment form
|
||||
*
|
||||
* @param BaseComment|null $comment
|
||||
* @param BaseItem $item
|
||||
* @return array<string,FormAbstract>
|
||||
*/
|
||||
public function formElements( ?BaseComment $comment, BaseItem $item ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after the comment form is saved
|
||||
*
|
||||
* @param BaseComment $comment
|
||||
* @param array $values
|
||||
* @return void
|
||||
*/
|
||||
public function formPostSave( BaseComment $comment, array $values ): void
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace IPS\Output\UI;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
|
||||
use IPS\Content\Item as BaseItem;
|
||||
use IPS\Helpers\Badge\Icon;
|
||||
use IPS\Helpers\Form\FormAbstract;
|
||||
use IPS\Helpers\Table\Content;
|
||||
use IPS\Node\Model;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
abstract class Item
|
||||
{
|
||||
/**
|
||||
* This needs to be declared in any child classes as well
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public static ?string $class = NULL;
|
||||
|
||||
/**
|
||||
* Can be used to add additional css classes to the item
|
||||
*
|
||||
* @param BaseItem $item
|
||||
* @return string
|
||||
*/
|
||||
public function css( BaseItem $item ): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to add additional data attributes to the item
|
||||
*
|
||||
* @param BaseItem $item
|
||||
* @return string
|
||||
*/
|
||||
public function dataAttributes( BaseItem $item ): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns additional menu items for the moderation menu
|
||||
*
|
||||
* @param BaseItem $item
|
||||
* @return array
|
||||
*/
|
||||
public function menuItems( BaseItem $item ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional badge icons to display in the header
|
||||
*
|
||||
* @param BaseItem $item
|
||||
* @return array<Icon>
|
||||
*/
|
||||
public function badges( BaseItem $item ) : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add elements to the item form.
|
||||
* This method returns all elements that will be added.
|
||||
* By default, all elements will be added in order at the end of the form.
|
||||
* To specify placement within the form, @see FormAbstract::setPosition().
|
||||
*
|
||||
* @param BaseItem|null $item
|
||||
* @param Model|null $container
|
||||
* @return array<string,FormAbstract>
|
||||
*/
|
||||
public function formElements( ?BaseItem $item, ?Model $container ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the Item form is saved
|
||||
*
|
||||
* @param BaseItem $item
|
||||
* @param array $values
|
||||
* @return void
|
||||
*/
|
||||
public function formPostSave( BaseItem $item, array $values ): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display content in the contextual sidebar
|
||||
*
|
||||
* @param BaseItem $item
|
||||
* @return string
|
||||
*/
|
||||
public function sidebar( BaseItem $item ) : string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom sort options to the content table for this class
|
||||
* @note $item will ALWAYS be null.
|
||||
*
|
||||
* @param BaseItem|null $item
|
||||
* @param Content $table
|
||||
* @return array
|
||||
*/
|
||||
public function contentTableSortOptions( ?BaseItem $item, Content $table ) : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sort direction for the selected sort option,
|
||||
* or NULL to use the default parent method.
|
||||
*
|
||||
* @note $item will ALWAYS be null.
|
||||
*
|
||||
* @param BaseItem|null $item
|
||||
* @param Content $table
|
||||
* @param string $sortBy
|
||||
* @return string|null
|
||||
*/
|
||||
public function contentTableSortDirection( ?BaseItem $item, Content $table, string $sortBy ) : string|null
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom filters to the content table for this class
|
||||
* @note $item will ALWAYS be null.
|
||||
*
|
||||
* @param BaseItem|null $item
|
||||
* @param Content $table
|
||||
* @return array
|
||||
*/
|
||||
public function contentTableFilters( ?BaseItem $item, Content $table ) : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom conditions to the where clause for a content table.
|
||||
* @note $item will ALWAYS be null.
|
||||
*
|
||||
* @param BaseItem|null $item
|
||||
* @param Content $table
|
||||
* @return array
|
||||
*/
|
||||
public function contentTableWhere( ?BaseItem $item, Content $table ) : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace IPS\Output\UI;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Helpers\Menu\MenuItem;
|
||||
use IPS\Member as MemberClass;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
abstract class MenuExtension
|
||||
{
|
||||
/**
|
||||
* Used to add additional links to the user account menu
|
||||
*
|
||||
* @param string $position ( can be content, settings, logout )
|
||||
* @return array<MenuItem>
|
||||
*/
|
||||
public function accountMenu( string $position = 'content' ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to add items to the mobile navigation Menu
|
||||
*
|
||||
* @param string $position (can be content, settings, logout)
|
||||
* @return array<MenuItem>
|
||||
*/
|
||||
public function mobileMenu( string $position = 'content' ) : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to add additional content to userbar
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function userNav(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to add content to the mobile navigation header
|
||||
*
|
||||
* @param string $position Where the code will be inserted (header/footer)
|
||||
* @param string $iconLocation Where the main icons are currently located (header/footer)
|
||||
* @return string
|
||||
*/
|
||||
public function mobileNav( string $position, string $iconLocation = 'footer' ) : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to add items to the user profile menu
|
||||
*
|
||||
* @param MemberClass $member Member whose profile is being viewed
|
||||
* @return array<MenuItem>
|
||||
*/
|
||||
public function editProfileMenu( MemberClass $member ) : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace IPS\Output\UI;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
|
||||
use IPS\Helpers\Form\FormAbstract;
|
||||
use IPS\Node\Model;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
abstract class Node
|
||||
{
|
||||
/**
|
||||
* This needs to be declared in any child classes as well
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public static ?string $class = NULL;
|
||||
|
||||
/**
|
||||
* Can be used to add additional css classes to the node
|
||||
*
|
||||
* @param Model $node
|
||||
* @return array
|
||||
*/
|
||||
public function css( Model $node ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to add additional data attributes to the node
|
||||
*
|
||||
* @param Model $node
|
||||
* @return string
|
||||
*/
|
||||
public function dataAttributes( Model $node ): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to add buttons to the ACP tree row
|
||||
* and to the view page in the ACP
|
||||
*
|
||||
* @param Model $node
|
||||
* @return array
|
||||
*/
|
||||
public function rowButtons( Model $node ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional HTML to be displayed in the ACP tree row
|
||||
*
|
||||
* @param Model $node
|
||||
* @return string
|
||||
*/
|
||||
public function rowHtml( Model $node ) : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a badge to be displayed in the ACP tree row
|
||||
*
|
||||
* @param Model $node
|
||||
* @return null|array Null for no badge, or an array of badge data (0 => CSS class type, 1 => language string, 2 => optional raw HTML to show instead of language string)
|
||||
*/
|
||||
public function rowBadge( Model $node ) : array|null
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add elements to the Node form
|
||||
* This method returns all elements that will be added.
|
||||
* By default, all elements will be added in order at the end of the form.
|
||||
* To specify placement within the form, @see FormAbstract::setPosition().
|
||||
*
|
||||
* @param Model $node
|
||||
* @return array<string,FormAbstract>
|
||||
*/
|
||||
public function formElements( Model $node ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the Node form is saved
|
||||
*
|
||||
* @param Model $node
|
||||
* @param array $values
|
||||
* @return void
|
||||
*/
|
||||
public function formPostSave( Model $node, array $values ): void
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace IPS\Output\UI;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
abstract class Review extends Comment
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace IPS\Output\UI;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
|
||||
use IPS\Application;
|
||||
use IPS\Content;
|
||||
use IPS\Node\Model;
|
||||
use IPS\Patterns\Singleton;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
class UiExtension extends Singleton
|
||||
{
|
||||
/**
|
||||
* @brief Singleton Instances
|
||||
* @note This needs to be declared in any child classes as well, only declaring here for editor code-complete/error-check functionality
|
||||
*/
|
||||
protected static ?Singleton $instance = NULL;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static array $extensions = [];
|
||||
|
||||
/**
|
||||
* Load all available extensions
|
||||
*
|
||||
* @param string $type
|
||||
* @return void
|
||||
*/
|
||||
protected function loadExtensions( string $type ) : void
|
||||
{
|
||||
if( !isset( static::$extensions[ $type ] ) )
|
||||
{
|
||||
static::$extensions[ $type ] = [];
|
||||
foreach ( Application::allExtensions( 'core', 'UI' . $type, FALSE, 'core' ) as $key => $extension )
|
||||
{
|
||||
static::$extensions[$type][ $key ] = $extension;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load extensions for this type
|
||||
*
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
protected function extensions( string $type ) : array
|
||||
{
|
||||
static::loadExtensions( $type );
|
||||
return static::$extensions[ $type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all UI extensions to verify that the classes are supported
|
||||
* Return a list of all unsupported classes, or NULL if all classes are valid
|
||||
*
|
||||
* @param Application $application
|
||||
* @return array|null
|
||||
*/
|
||||
public static function unsupportedExtensions( Application $application ) : ?array
|
||||
{
|
||||
$return = [];
|
||||
foreach( $application->extensions( 'core', 'UINode', false ) as $ext )
|
||||
{
|
||||
/* @var Model $nodeClass */
|
||||
$nodeClass = $ext::$class ?? null;
|
||||
if( $nodeClass AND !$nodeClass::$canBeExtended )
|
||||
{
|
||||
$return[] = $nodeClass;
|
||||
}
|
||||
}
|
||||
|
||||
return count( $return ) ? $return : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a UI extension method
|
||||
*
|
||||
* @param Content|Model|string $object
|
||||
* @param string $method
|
||||
* @param array|null $payload
|
||||
* @return array
|
||||
*/
|
||||
public function run( Content|Model|string $object, string $method, ?array $payload=array() ) : array
|
||||
{
|
||||
$className = is_string( $object ) ? $object : get_class( $object );
|
||||
$baseClass = null;
|
||||
switch( $className )
|
||||
{
|
||||
case '':
|
||||
default:
|
||||
return [];
|
||||
|
||||
case is_subclass_of( $className, Model::class ):
|
||||
|
||||
/* If this node class cannot be extended, just return and do nothing */
|
||||
if( !$className::$canBeExtended )
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$type = 'Node';
|
||||
$baseClass = Model::class;
|
||||
break;
|
||||
case is_subclass_of( $className, Content\Item::class ):
|
||||
$type = 'Item';
|
||||
$baseClass = Content\Item::class;
|
||||
break;
|
||||
case is_subclass_of( $className, Content\Review::class ):
|
||||
$type = 'Review';
|
||||
$baseClass = Content\Review::class;
|
||||
break;
|
||||
case is_subclass_of( $className, Content\Comment::class ):
|
||||
$type = 'Comment';
|
||||
$baseClass = Content\Comment::class;
|
||||
break;
|
||||
}
|
||||
|
||||
$return = [];
|
||||
|
||||
/* If we are working with an object (Item/Comment/Node), put it first in the parameter list */
|
||||
$params = is_array( $payload ) ? array_values( $payload ) : array();
|
||||
array_unshift( $params, is_string( $object ) ? null : $object );
|
||||
|
||||
foreach( $this->extensions( $type ) as $extension )
|
||||
{
|
||||
/* Use subclass to account for classes in Pages */
|
||||
if( isset( $extension::$class ) AND $className != $extension::$class AND !is_subclass_of( $className, $extension::$class ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Block extension of base classes */
|
||||
if( $baseClass !== null AND $extension::$class == $baseClass )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( $response = $extension->$method( ...$params ) )
|
||||
{
|
||||
if( is_array( $response ) )
|
||||
{
|
||||
$return = array_merge( $return, $response );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return[] = $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user