Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

+131 -52
View File
@@ -12,7 +12,7 @@
namespace IPS\core\Setup;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -30,6 +30,12 @@ class _Upgrade
*/
public static function systemRequirements()
{
/* We don't need to check the CIC platform */
if( \IPS\CIC )
{
return array( 'recommendations' => array(), 'requirements' => array() );
}
$return = Install::systemRequirements();
/* MySQL Requirements */
@@ -41,6 +47,13 @@ class _Upgrade
if( \IPS\Db::i()->checkForTable('core_file_storage') )
{
$fileSystemItems = array();
$successfulStorage = FALSE;
$maxChunkSize = \IPS\Helpers\Form\Upload::maxChunkSize();
if ( $maxChunkSize = \IPS\Helpers\Form\Upload::maxChunkSize() )
{
$maxChunkSize = $maxChunkSize / 1048576;
}
foreach ( \IPS\Application::allExtensions( 'core', 'FileStorage', FALSE ) as $k => $v )
{
@@ -66,6 +79,23 @@ class _Upgrade
'success' => TRUE,
'message' => ( $class instanceof \IPS\File\FileSystem ) ? \IPS\Member::loggedIn()->language()->addToStack( 'requirements_file_writable', FALSE, array( 'sprintf' => array( str_replace( '{root}', \IPS\ROOT_PATH, $class->configuration['dir'] ) ) ) ) : $class->displayName( $class->configuration )
);
if ( $maxChunkSize and $class::$supportsChunking and isset( $class::$minChunkSize ) and $class::$minChunkSize > $maxChunkSize )
{
$maxChunkSizeValues = [];
foreach ( \IPS\Helpers\Form\Upload::maxChunkSizeValues() as $k => $v )
{
if ( ( $v / 1048576 ) < $class::$minChunkSize )
{
$maxChunkSizeValues[] = \IPS\Member::loggedIn()->language()->addToStack( 'file_storage_test_chunk_mismatch_value', FALSE, array( 'sprintf' => array( $k, \IPS\Output\Plugin\Filesize::humanReadableFilesize( $v ) ) ) );
}
}
$maxChunkSizeValues = \IPS\Member::loggedIn()->language()->formatList( $maxChunkSizeValues );
$return['advice']["filesystem{$class->configurationId}"] = \IPS\Member::loggedIn()->language()->addToStack( 'file_storage_test_chunk_mismatch', FALSE, array( 'sprintf' => array( $class->displayName( $class->configuration ), \IPS\Output\Plugin\Filesize::humanReadableFilesize( $maxChunkSize * 1048576 ), \IPS\Output\Plugin\Filesize::humanReadableFilesize( $class::$minChunkSize * 1048576 ), $maxChunkSizeValues ) ) );
}
$successfulStorage = TRUE;
}
}
catch ( \Exception $e )
@@ -80,7 +110,15 @@ class _Upgrade
}
}
}
/* Flag a storage issue in upgrader/system check since zero storage methods are working */
if( !$successfulStorage )
{
array_walk( $fileSystemItems, function( &$item ) {
$item['success'] = FALSE;
} );
}
array_splice( $return['requirements'][ $writeablesKey ], array_search( 'uploads', array_keys( $return['requirements'][ $writeablesKey ] ) ), 1, $fileSystemItems );
}
@@ -96,7 +134,6 @@ class _Upgrade
{
unset( $return['requirements'][ $writeablesKey ]['datastore'] );
}
return $return;
}
@@ -109,8 +146,15 @@ class _Upgrade
*/
public static function mysqlRequirements( $db=NULL )
{
/* We don't need to check the CIC platform */
if( \IPS\CIC )
{
return array( 'recommendations' => array(), 'requirements' => array() );
}
/* MySQL Version */
$return = array();
$db ? $db->checkConnection() : \IPS\Db::i()->checkConnection();
$mysqlVersion = $db ? $db->server_info : \IPS\Db::i()->server_info;
$requirements = json_decode( file_get_contents( \IPS\ROOT_PATH . '/applications/core/data/requirements.json' ), TRUE );
if ( version_compare( $mysqlVersion, $requirements['mysql']['required'] ) >= 0 )
@@ -182,7 +226,7 @@ class _Upgrade
/**
* Process
*
* @param array Multiple-Redirector Data
* @param array $data Multiple-Redirector Data
* @return array|null Multiple-Redirector Data or NULL indicates done
*/
public function process( $data )
@@ -200,26 +244,26 @@ class _Upgrade
}
/* Run the step */
$step = intval( $data[0] );
$step = \intval( $data[0] );
if ( $step === 1 )
{
/* Set the we're setting up flag */
static::setUpgradingFlag( TRUE );
if ( function_exists('opcache_reset') )
if ( \function_exists('opcache_reset') )
{
@opcache_reset();
}
}
/* Write the log */
@file_put_contents( \IPS\ROOT_PATH . '/uploads/logs/upgrader_data.cgi', json_encode( array(
/* Write the upgrade data */
$upgraderData = json_encode( array(
'session' => $_SESSION,
'step' => $step,
'data' => $data
) ) );
@chmod( \IPS\ROOT_PATH . '/uploads/logs/upgrader_data.cgi', \IPS\IPS_FILE_PERMISSION );
) );
\IPS\Db::i()->replace( 'upgrade_temp', array( 'id' => 1, 'upgrade_data' => $upgraderData, 'lastaccess' => time() ) );
if ( $step == 11 )
{
@@ -232,10 +276,6 @@ class _Upgrade
/* Clear widget caches */
\IPS\Widget::deleteCaches();
/* Clear store */
\IPS\Data\Cache::i()->clearAll();
\IPS\Data\Store::i()->clearAll();
/* Clear theme cache for default theme */
try
{
@@ -252,6 +292,10 @@ class _Upgrade
/* Make all disk template caches stale */
\IPS\Theme::resetAllCacheKeys();
/* Clear store */
\IPS\Data\Cache::i()->clearAll();
\IPS\Data\Store::i()->clearAll();
/* Remove the flag */
static::setUpgradingFlag( FALSE );
@@ -263,7 +307,8 @@ class _Upgrade
throw new \BadMethodCallException( 'NO_STEP' );
}
$response = call_user_func( array( $this, "step{$step}" ), $data );
$stepFunc = array( $this, "step{$step}" );
$response = $stepFunc( $data );
return array( $response, \IPS\Member::loggedIn()->language()->addToStack( ( $this->customTitle ) ? $this->customTitle : 'upgrade_step_' . $step ), ( ( ( 100/10 ) * $data[0] + ( ( 100/10 ) / 100 * $this->stepProgress ) ) ) ?: 1 );
}
@@ -281,13 +326,13 @@ class _Upgrade
$upgradeSteps = \IPS\Application::load( $app )->getUpgradeSteps( $current ? $current : $currentVersion );
/* Grab next upgrade step to run */
if ( ! count( $upgradeSteps ) )
if ( ! \count( $upgradeSteps ) )
{
return NULL;
}
$next = array_shift( $upgradeSteps );
$next = intval( $next );
$next = \intval( $next );
if( !isset( $_SESSION['upgrade_steps'] ) )
{
@@ -308,7 +353,7 @@ class _Upgrade
/**
* App Looper
*
* @param array data Multiple-Redirector Data
* @param array $data Multiple-Redirector Data
* @param callback $code Code to execute for each app
* @return array Data to Multiple-Redirector Data
*/
@@ -319,7 +364,7 @@ class _Upgrade
$returnNext = FALSE;
foreach ( $this->apps as $app )
{
$this->stepProgress += ( 100 / count( $this->apps ) );
$this->stepProgress += ( 100 / \count( $this->apps ) );
if ( !isset( $data[1] ) )
{
@@ -327,9 +372,9 @@ class _Upgrade
}
elseif ( $data[1] == $app )
{
$val = call_user_func( $code, $app );
$val = $code( $app );
if ( is_array( $val ) OR is_string( $val ) )
if ( \is_array( $val ) OR \is_string( $val ) )
{
return $val;
}
@@ -351,12 +396,13 @@ class _Upgrade
* Step 1
* Upgrade database
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step1( $data )
{
$this->stepProgress = 0;
$perAppProgress = floor( 100 / count( $this->apps ) );
$perAppProgress = floor( 100 / \count( $this->apps ) );
$returnNext = FALSE;
$extra = array();
@@ -419,7 +465,7 @@ class _Upgrade
}
/* What step in the upgrader file are we on? */
$upgradeStep = ( isset($data['extra']['_upgradeStep']) ) ? intval($data['extra']['_upgradeStep']) : 1;
$upgradeStep = ( isset($data['extra']['_upgradeStep']) ) ? \intval($data['extra']['_upgradeStep']) : 1;
/* We're on the first step of the current version's upgrade.php, so run the raw queries yet, do so */
if( $upgradeStep == 1 AND ! isset( $data['extra']['_upgradeData'] ) and ( ! ( isset( $_SESSION['sqlFinished'][ $app ][ $extra['_current'] ] ) AND $_SESSION['sqlFinished'][ $app ][ $extra['_current'] ] ) ) )
@@ -434,6 +480,19 @@ class _Upgrade
try
{
if( file_exists( \IPS\ROOT_PATH . "/applications/{$app}/setup/upg_{$extra['_current']}/lang.json" ) )
{
$langChanges = json_decode( \file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/setup/upg_{$extra['_current']}/lang.json" ), TRUE );
if ( isset( $langChanges['normal']['removed'] ) and $langChanges['normal']['removed'] )
{
\IPS\Db::i()->delete( 'core_sys_lang_words', array( array( 'word_app=?', $app ), array( 'word_js=0' ), array( \IPS\Db::i()->in( 'word_key', $langChanges['normal']['removed'] ) ) ) );
}
if ( isset( $langChanges['js']['removed'] ) and $langChanges['js']['removed'] )
{
\IPS\Db::i()->delete( 'core_sys_lang_words', array( array( 'word_app=?', $app ), array( 'word_js=1' ), array( \IPS\Db::i()->in( 'word_key', $langChanges['js']['removed'] ) ) ) );
}
}
$fetched = \IPS\Application::load( $app )->installDatabaseUpdates( $extra['_current'], ( \IPS\Request::i()->run_anyway ) ? $lastSqlId - 0.1 : $lastSqlId, 10, !\IPS\Request::i()->run_anyway );
if( isset( \IPS\Request::i()->mr_continue ) AND \IPS\Request::i()->mr_continue )
@@ -465,7 +524,7 @@ class _Upgrade
}
/* Queries to run manually */
if( is_array( $fetched['queriesToRun'] ) and count( $fetched['queriesToRun'] ) )
if( \is_array( $fetched['queriesToRun'] ) and \count( $fetched['queriesToRun'] ) )
{
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => $app, 'extra' => array( 'lastSqlId' => $_SESSION['lastJsonIndex'], '_current' => $extra['_current'] ) ) );
@@ -583,7 +642,7 @@ class _Upgrade
}
}
/* If the result is an array with 'html' key, we show that */
else if( is_array( $result ) AND isset( $result['html'] ) )
else if( \is_array( $result ) AND isset( $result['html'] ) )
{
return $result['html'];
}
@@ -636,7 +695,7 @@ class _Upgrade
} # Foreach
/* We're done, look for finish methods for this upgrade ID */
if ( $lastAppToRun === $app AND isset( $_SESSION['upgrade_steps'] ) AND count( $_SESSION['upgrade_steps'] ) )
if ( $lastAppToRun === $app AND isset( $_SESSION['upgrade_steps'] ) AND \count( $_SESSION['upgrade_steps'] ) )
{
$this->customTitle = "Running finish step (" . ucfirst( $app ) . ': Upgrade ID ' . $extra['_current'] . ')';
@@ -644,6 +703,7 @@ class _Upgrade
{
foreach( $_versionApps as $_versionApp )
{
\IPS\Application::installNewFeatures( $_versionApp, $_versionId );
\IPS\Log::debug( "Running finish step for: {$_versionApp} version {$_versionId}", 'upgrade' );
/* Get the object */
@@ -679,6 +739,7 @@ class _Upgrade
* Step 2
* Run a database check
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step2( $data )
@@ -687,10 +748,10 @@ class _Upgrade
{
$this->customTitle = sprintf( \IPS\Member::loggedIn()->language()->get('upgrade_step_2_app'), $app );
$changesToMake = \IPS\Application::load( $app )->databaseCheck();
if ( count( $changesToMake ) )
if ( \count( $changesToMake ) )
{
$toRun = \IPS\core\Setup\Upgrade::runManualQueries( $changesToMake );
if ( count( $toRun ) )
if ( \count( $toRun ) )
{
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => $app, 'extra' => array( '_upgradeStep' => 2 ) ) );
return \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr ) ) );
@@ -704,19 +765,34 @@ class _Upgrade
* Step 3
* Insert app data
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step3( $data )
{
/* Set administrator new features flags - if none were added, then it'll automatically reset back */
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( \IPS\Db::i()->in('member_id', \array_keys( \IPS\Member::administrators()['m'] ) ) . " OR " . \IPS\Db::i()->in( 'member_group_id', \array_keys( \IPS\Member::administrators()['g'] ) ) . " OR " . \IPS\Db::i()->findInSet( 'mgroup_others', \array_keys( \IPS\Member::administrators()['g'] ) ) ) ), 'IPS\Member' ) AS $admin )
{
$admin->members_bitoptions['has_new_acp_features'] = TRUE;
$admin->save();
}
return $this->appLoop( $data, function( $app )
{
if( !file_exists( \IPS\ROOT_PATH . '/plugins/hooks.php' ) )
if ( !file_exists( \IPS\SITE_FILES_PATH . '/plugins/hooks.php' ) )
{
@touch( \IPS\ROOT_PATH . '/plugins/hooks.php' );
@chmod( \IPS\ROOT_PATH . '/plugins/hooks.php', 0777 );
if ( \IPS\CIC2 )
{
\IPS\Cicloud\file( 'hooks.php', '', 'plugins' );
}
else
{
@touch( \IPS\SITE_FILES_PATH . '/plugins/hooks.php' );
@chmod( \IPS\SITE_FILES_PATH . '/plugins/hooks.php', 0777 );
}
}
if( !is_writable( \IPS\ROOT_PATH . '/plugins/hooks.php' ) )
if( !\IPS\CIC2 AND !is_writable( \IPS\SITE_FILES_PATH . '/plugins/hooks.php' ) )
{
throw new \RuntimeException( sprintf( \IPS\Member::loggedIn()->language()->get("hook_file_not_writable"), \IPS\ROOT_PATH . '/plugins/hooks.php' ) );
}
@@ -732,7 +808,7 @@ class _Upgrade
$longVersions = array_keys( $versions );
$humanVersions = array_values( $versions );
if( count($versions) )
if( \count($versions) )
{
$latestLVersion = array_pop( $longVersions );
$latestHVersion = array_pop( $humanVersions );
@@ -780,6 +856,7 @@ class _Upgrade
* Step 4
* Update settings, tasks, etc.
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step4( $data )
@@ -798,6 +875,7 @@ class _Upgrade
* Step 5
* Update Languages
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step5( $data )
@@ -839,6 +917,7 @@ class _Upgrade
* Step 6
* Update Email Templates
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step6( $data )
@@ -854,6 +933,7 @@ class _Upgrade
* Step 7
* Update theme settings
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step7( $data )
@@ -882,6 +962,7 @@ class _Upgrade
* Step 8
* Clear existing templates
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step8( $data )
@@ -889,6 +970,13 @@ class _Upgrade
/* Clear old caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Data\Store::i()->clearAll();
if ( \IPS\CIC )
{
/* If this is CiC, make sure the core_store and core_cache tables are empty in case the primary caching engines fail, so we're not serving old data when it falls back to database storage */
\IPS\Db::i()->delete( 'core_store' );
\IPS\Db::i()->delete( 'core_cache' );
}
\IPS\Theme::clearFiles( \IPS\Theme::IMAGES );
@@ -911,6 +999,7 @@ class _Upgrade
* Step 9
* Update templates
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step9( $data )
@@ -959,6 +1048,7 @@ class _Upgrade
* Step 10
* Update Javascript
*
* @param array $data Multi-redirector data
* @return array Multiple-Redirector Data
*/
protected function step10( $data )
@@ -1031,7 +1121,7 @@ class _Upgrade
\IPS\Db::i()->insert( 'core_sys_conf_settings', $insert );
}
\IPS\Settings::i()->changeValues( array( 'setup_in_progress' => intval( $value ) ) );
\IPS\Settings::i()->changeValues( array( 'setup_in_progress' => \intval( $value ) ) );
}
/**
@@ -1058,7 +1148,7 @@ class _Upgrade
{
require( $queryFile );
if ( is_array( $SQL ) )
if ( \is_array( $SQL ) )
{
foreach( $SQL as $k => $query )
{
@@ -1075,7 +1165,7 @@ class _Upgrade
}
catch( \IPS\Db\Exception $e )
{
if ( ! in_array( $e->getCode(), array( 1007, 1008, 1050, 1060, 1061, 1062, 1091, 1051 ) ) )
if ( ! \in_array( $e->getCode(), array( 1007, 1008, 1050, 1060, 1061, 1062, 1091, 1051 ) ) )
{
throw $e;
}
@@ -1088,7 +1178,7 @@ class _Upgrade
/**
* Add SQL Prefix to Query
*
* @param string SQL Query
* @param string $query SQL Query
* @return string
*/
public static function addPrefixToQuery( $query )
@@ -1137,23 +1227,12 @@ class _Upgrade
}
$toReturn = array();
$tableCounts = array();
foreach( $queries as $id => $data )
{
$database = ( isset( $data['db'] ) ) ? $data['db'] : \IPS\Db::i();
if ( ! isset( $tableCounts[ $data['table'] ] ) and $database->checkForTable( $data['table'] ) )
{
$tableCounts[ $data['table'] ] = $database->select( 'count(*)', $data['table'] )->first();
}
}
foreach( $queries as $id => $data )
{
$database = ( isset( $data['db'] ) ) ? $data['db'] : \IPS\Db::i();
if( !\IPS\Request::i()->run_anyway and isset( $tableCounts[ $data['table'] ] ) AND $tableCounts[ $data['table'] ] > \IPS\UPGRADE_MANUAL_THRESHOLD )
if( !\IPS\Request::i()->run_anyway and $database->recommendManualQuery( $data['table'] ) )
{
\IPS\Log::debug( "Big table " . $data['table'] . ", storing query to run manually", 'upgrade' );
@@ -1170,7 +1249,7 @@ class _Upgrade
catch( \IPS\Db\Exception $e )
{
/* If the error isn't important we should ignore it and is consistent with \Application::installDatabaseUpdates() */
if( !in_array( $e->getCode(), array( 1007, 1008, 1050, 1060, 1061, 1062, 1069, 1091 ) ) )
if( !\in_array( $e->getCode(), array( 1007, 1008, 1050, 1060, 1061, 1062, 1069, 1091 ) ) )
{
throw $e;
}
@@ -1255,7 +1334,7 @@ class _Upgrade
foreach( $changes as $k => $v )
{
if( is_array( $v ) )
if( \is_array( $v ) )
{
foreach( $v as $_k => $_v )
{