Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

+127 -36
View File
@@ -11,29 +11,45 @@
namespace IPS;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DomainException;
use ErrorException;
use IPS\Application\Module;
use IPS\Dispatcher\Controller;
use IPS\Platform\Bridge;
use RuntimeException;
use function defined;
use function dirname;
use function get_called_class;
use function strstr;
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;
}
/**
* Dispatcher
*
* @property Application $application
* @property Module $module
* @property string $controller
*/
abstract class _Dispatcher
abstract class Dispatcher
{
/**
* @brief Singleton Instance
*/
protected static $instance = NULL;
protected static mixed $instance = NULL;
/**
* Check if a dispatcher instance is available
*
* @return static
* @return bool
* @note This should be used sparingly, primarily for gateway scripts that do not need a dispatcher but still use the framework
*/
public static function hasInstance()
public static function hasInstance(): bool
{
return ( static::$instance !== NULL );
}
@@ -43,15 +59,15 @@ abstract class _Dispatcher
*
* @return static
*/
public static function i()
public static function i(): static
{
if( static::$instance === NULL )
{
$class = \get_called_class();
$class = get_called_class();
if( $class == 'IPS\\Dispatcher' )
{
throw new \RuntimeException( "Only subclasses of Dispatcher can be instantiated" );
throw new RuntimeException( "Only subclasses of Dispatcher can be instantiated" );
}
static::$instance = new $class;
@@ -60,13 +76,13 @@ abstract class _Dispatcher
{
$_redirect = FALSE;
if ( !file_exists( \IPS\SITE_FILES_PATH . '/conf_global.php' ) )
if ( !file_exists( SITE_FILES_PATH . '/conf_global.php' ) )
{
$_redirect = TRUE;
}
else
{
require \IPS\SITE_FILES_PATH . '/conf_global.php';
require SITE_FILES_PATH . '/conf_global.php';
if( !isset( $INFO['sql_database'] ) )
{
@@ -77,7 +93,7 @@ abstract class _Dispatcher
/* This looks weird, but there was a period of time where "installed" was misspelled as "instaled" on Community in the Cloud after install finished. So, if that is present, assume we're okay. */
if ( !isset( $INFO['instaled'] ) )
{
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 503 Service Unavailable" );
}
@@ -86,7 +102,7 @@ abstract class _Dispatcher
header( "HTTP/1.1 503 Service Unavailable" );
}
require \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . '/install/installing.html';
require ROOT_PATH . '/admin/install/installing.html';
exit;
}
}
@@ -95,14 +111,14 @@ abstract class _Dispatcher
if( $_redirect === TRUE )
{
/* conf_global.php does not exist, forward to installer - we'll do this manually to avoid any code in Output.php that anticipates the installation already being complete (such as setting CSP header in __construct()) */
$url = ( \IPS\Request::i()->isSecure() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . rtrim( \dirname( $_SERVER['SCRIPT_NAME'] ), '/' );
$url = ( Request::i()->isSecure() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . rtrim( dirname( $_SERVER['SCRIPT_NAME'] ), '/' );
header( "HTTP/1.1 307 Temporary Redirect" );
foreach( \IPS\Output::getNoCacheHeaders() as $headerKey => $headerValue )
foreach(Output::getNoCacheHeaders() as $headerKey => $headerValue )
{
header( "{$headerKey}: {$headerValue}" );
}
header( "Location: {$url}/" . \IPS\CP_DIRECTORY . "/install/" );
header( "Location: {$url}/admin/install/" );
exit;
}
}
@@ -116,37 +132,37 @@ abstract class _Dispatcher
/**
* @brief Controller Classname
*/
protected $classname;
protected ?string $classname = NULL;
/**
* @brief Controller instance
*/
public $dispatcherController;
public mixed $dispatcherController = NULL;
/**
* Init
*
* @return void
* @throws \DomainException
* @throws DomainException
*/
abstract public function init();
abstract public function init() : void;
/**
* Run
*
* @return void
*/
public function run()
public function run() : void
{
/* Init class */
if( !class_exists( $this->classname ) )
{
\IPS\Output::i()->error( 'page_doesnt_exist', '2S100/1', 404 );
Output::i()->error( 'page_doesnt_exist', '2S100/1', 404 );
}
$this->dispatcherController = new $this->classname;
if( !( $this->dispatcherController instanceof \IPS\Dispatcher\Controller ) )
if( !( $this->dispatcherController instanceof Controller ) )
{
\IPS\Output::i()->error( 'page_not_found', '5S100/3', 500, '' );
Output::i()->error( 'page_not_found', '5S100/3', 500, '' );
}
/* Execute */
@@ -154,23 +170,26 @@ abstract class _Dispatcher
$this->finish();
}
/**
* Finish
*
* @return void
* @return void
* @throws ErrorException
*/
public function finish()
public function finish() : void
{
Bridge::i()->dispatcherFinish();
/* If we're still here - output */
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( \IPS\Output::i()->output ), 200, 'text/html' );
Output::i()->sendOutput( Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( Output::i()->output ), 200, 'text/html' );
}
else
{
/* Just prefetch this to save a query later */
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( \IPS\Output::i()->title, \IPS\Output::i()->output, $this->getLocationData() ), 200, 'text/html' );
Output::i()->sendOutput( Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( Output::i()->title, Output::i()->output, $this->getLocationData() ), 200, 'text/html' );
}
}
@@ -178,15 +197,87 @@ abstract class _Dispatcher
* Get an array of data representing the user's current location
* This gets passed to the templates in order to apply some attributes to the body tag
*
* @return array
* @return array{app:string,module:string,controller:string,id?:int|null}
*/
public function getLocationData()
public function getLocationData(): array
{
return array(
'app' => \IPS\Dispatcher::i()->application->directory,
'module' => \IPS\Dispatcher::i()->module->key,
'controller' => \IPS\Dispatcher::i()->controller,
'id' => \IPS\Request::i()->id ? (int) \IPS\Request::i()->id : NULL
'app' => Dispatcher::i()->application->directory,
'module' => Dispatcher::i()->module->key,
'controller' => Dispatcher::i()->controller,
'id' => Request::i()->id ? (int) Request::i()->id : NULL
);
}
/**
* Check the current location to determine if it's a match
*
* @param string $location
* @param string|null $app
* @param string|null $module
* @param string|null $controller
* @return bool
*/
public static function checkLocation( string $location, ?string $app = null, ?string $module = null, ?string $controller = null ) : bool
{
/* If we have no instance it's always false */
if( !static::hasInstance() )
{
return false;
}
/* This is required */
if( static::i()->controllerLocation != $location )
{
return false;
}
/* If we specified an application, check that first */
if( $app !== null )
{
if( isset( static::i()->application ) )
{
if( static::i()->application->directory != $app )
{
return false;
}
}
elseif( isset( Request::i()->app ) and Request::i()->app != $app )
{
return false;
}
}
/* Repeat for module */
if( $module !== null )
{
if( isset( static::i()->module ) )
{
if( static::i()->module->key != $module )
{
return false;
}
}
elseif( isset( Request::i()->module ) and Request::i()->module != $module )
{
return false;
}
}
/* And finally the controller */
if( $controller !== null )
{
if( isset( static::i()->controller ) and static::i()->controller != $controller )
{
return false;
}
elseif( isset( Request::i()->controller ) and Request::i()->controller != $controller )
{
return false;
}
}
/* Still here? All good */
return true;
}
}