Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Error Logs
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 06 Aug 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -30,7 +30,7 @@ class _errorLogs extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'support_dashboard' );
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'system_logs_view' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief hookedFiles
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
|
||||
* @since 11 Nov 2016
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\support;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* hookedFiles
|
||||
*/
|
||||
class _hookedFiles extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'app_manage' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* ...
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_hooks', \IPS\Http\Url::internal( 'app=core&module=support&controller=hookedFiles' ) );
|
||||
$table->langPrefix = 'hooks_';
|
||||
$table->quickSearch = array( 'class', 'hook_class' );
|
||||
$table->include = array( 'hooks_app', 'hooks_plugin', 'hooks_type', 'hooks_class', 'hooks_file' );
|
||||
|
||||
$table->parsers = array(
|
||||
'hooks_app' => function( $val, $row )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Application::load($row['app'])->_title;
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('hook_class_none');
|
||||
}
|
||||
},
|
||||
'hooks_plugin' => function( $val, $row )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Plugin::load($row['plugin'])->name;
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('hook_class_none');
|
||||
}
|
||||
},
|
||||
'hooks_type' => function( $val, $row )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'plugin_hook_type_' . mb_strtolower( $row['type'] ) );
|
||||
},
|
||||
'hooks_class' => function( $val, $row )
|
||||
{
|
||||
return $row['class'];
|
||||
},
|
||||
'hooks_file' => function( $val, $row )
|
||||
{
|
||||
if ( $row['app'] )
|
||||
{
|
||||
return '/applications/' . $row['app'] . '/hooks/' . $row['filename'] . '.php';
|
||||
}
|
||||
else if ( $row['plugin'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
$plugin = \IPS\Plugin::load($row['plugin']);
|
||||
return '/plugins' . ( $plugin->location ? '/' . $plugin->location . '/hooks/' : '/' ) . $row['filename'] . '.php';
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('hook_class_none');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'hooked_classes' );
|
||||
\IPS\Output::i()->output = $table;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief recovery
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
|
||||
* @since 03 Nov 2016
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\support;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* recovery
|
||||
*/
|
||||
class _recovery extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* Recover
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
/* Are we even in recovery mode? */
|
||||
if ( \IPS\RECOVERY_MODE === FALSE )
|
||||
{
|
||||
\IPS\Output::i()->error( 'recovery_mode_disabled', '1C342/1', 403, '' );
|
||||
}
|
||||
|
||||
if ( \IPS\NO_WRITES === TRUE )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_writes', '1C342/2', 403, '' );
|
||||
}
|
||||
|
||||
/* We are, let's set up a multi-redirect to disable things. At the end of the process, we'll list everything we did. */
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'recovery_mode' );
|
||||
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=recovery' ), function( $step )
|
||||
{
|
||||
$step = intval( $step );
|
||||
|
||||
switch( $step )
|
||||
{
|
||||
case 0: # Applications
|
||||
$appsDisabled = array();
|
||||
|
||||
/* Disable All non-IPS Applications */
|
||||
foreach( \IPS\Application::applications() AS $app )
|
||||
{
|
||||
if ( !in_array( $app->directory, \IPS\Application::$ipsApps ) )
|
||||
{
|
||||
$app->_enabled = FALSE;
|
||||
$appDisabled[] = $app->_id;
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION['recoveryApps'] = $appsDisabled;
|
||||
|
||||
return array( 1, \IPS\Member::loggedIn()->language()->addToStack( 'disabled_applications' ), 25 );
|
||||
break;
|
||||
|
||||
case 1: # Plugins
|
||||
$pluginsDisabled = array();
|
||||
|
||||
/* Disable All Plugins */
|
||||
foreach( \IPS\Plugin::plugins() AS $plugin )
|
||||
{
|
||||
$plugin->_enabled = FALSE;
|
||||
$plugin->save();
|
||||
$pluginsDisabled[] = $plugin->_id;
|
||||
}
|
||||
|
||||
$_SESSION['recoveryPlugins'] = $pluginsDisabled;
|
||||
|
||||
return array( 2, \IPS\Member::loggedIn()->language()->addToStack( 'disabled_plugins' ), 50 );
|
||||
break;
|
||||
|
||||
case 2: # Reset Theme
|
||||
$themeReset = FALSE;
|
||||
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', array( "template_set_id>?", 0 ) )->first() OR \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_css', array( "css_set_id>?", 0 ) )->first() )
|
||||
{
|
||||
/* Create a new theme */
|
||||
$theme = new \IPS\Theme;
|
||||
$theme->permissions = \IPS\Member::loggedIn()->member_group_id;
|
||||
$theme->save();
|
||||
$theme->installThemeSettings();
|
||||
$theme->copyResourcesFromSet();
|
||||
|
||||
\IPS\Lang::saveCustom( 'core', "core_theme_set_title_" . $theme->id, "IPS Support" );
|
||||
|
||||
/* Set this account to use that theme */
|
||||
\IPS\Member::loggedIn()->skin = $theme->id;
|
||||
\IPS\Member::loggedIn()->acp_skin = $theme->id;
|
||||
\IPS\Member::loggedIn()->save();
|
||||
|
||||
$themeReset = TRUE;
|
||||
}
|
||||
|
||||
$_SESSION['recoveryTheme'] = $themeReset;
|
||||
|
||||
return array( 3, \IPS\Member::loggedIn()->language()->addToStack( 'reset_theme_to_default' ), 75 );
|
||||
break;
|
||||
|
||||
case 3: # Login Handlers
|
||||
$handlersDisabled = array();
|
||||
|
||||
/* Disable all login handlers other than Internal */
|
||||
foreach( \IPS\Login::handlers( TRUE ) AS $key => $handler )
|
||||
{
|
||||
if ( $key != 'Internal' )
|
||||
{
|
||||
$handler->_enabled = FALSE;
|
||||
$handler->save();
|
||||
|
||||
$handlersDisabled[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION['recoveryLogins'] = $handlersDisabled;
|
||||
|
||||
return array( 4, \IPS\Member::loggedIn()->language()->addToStack( 'disabled_login_handlers' ), 100 );
|
||||
break;
|
||||
|
||||
case 4: # Done
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
}, function()
|
||||
{
|
||||
\IPS\IPS::resyncIPSCloud();
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=recovery&do=done' ) );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* "Done" Screen
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function done()
|
||||
{
|
||||
/* Did we disable any apps? */
|
||||
$apps = array();
|
||||
foreach( $_SESSION['recoveryApps'] AS $app )
|
||||
{
|
||||
$apps[] = \IPS\Application::load( $app );
|
||||
}
|
||||
|
||||
/* Did we disable any plugins? */
|
||||
$plugins = array();
|
||||
foreach( $_SESSION['recoveryPlugins'] AS $plugin )
|
||||
{
|
||||
$plugins[] = \IPS\Plugin::load( $plugin );
|
||||
}
|
||||
|
||||
/* Did we reset the theme? */
|
||||
$theme = $_SESSION['recoveryTheme'];
|
||||
|
||||
/* Did we disable any login handlers? */
|
||||
$logins = array();
|
||||
foreach( $_SESSION['recoveryLogins'] AS $handler )
|
||||
{
|
||||
$logins[] = \IPS\Login\LoginAbstract::constructFromData( \IPS\Db::i()->select( '*', 'core_login_handlers', array( "login_key=?", $handler ) )->first() );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'recovery_mode' );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->recovery( $apps, $plugins, $theme, $logins );
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief sql
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 22 May 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -124,7 +124,7 @@ class _sql extends \IPS\Dispatcher\Controller
|
||||
try
|
||||
{
|
||||
/* Strip quotes */
|
||||
$q = trim( preg_replace( '#(--.*)|(((/\*)+?[\w\W]+?(\*/)+))#', '', $q ) );
|
||||
$q = trim( preg_replace( '@(--.*)|(#.*)|(((/\*)+?[\w\W]+?(\*/)+))@', '', $q ) );
|
||||
|
||||
/* Check it's okay */
|
||||
if ( preg_match( "/^(DROP|FLUSH)/i", $q ) )
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Support Wizard
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 21 May 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -40,15 +40,16 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
{
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('get_support');
|
||||
\IPS\Output::i()->output = \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->support( new \IPS\Helpers\Wizard( array( 'type_of_problem' => array( $this, '_typeOfProblem' ), 'self_service' => array( $this, '_selfService' ), 'contact_support' => array( $this, '_contactSupport' ) ), \IPS\Http\Url::internal('app=core&module=support&controller=support') ) );
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_support.js', 'core', 'admin') );
|
||||
\IPS\Output::i()->output = \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->support( new \IPS\Helpers\Wizard( array( 'type_of_problem' => array( $this, '_typeOfProblem' ), 'self_service' => array( $this, '_selfService' ), 'contact_support' => array( $this, '_contactSupport' ) ), \IPS\Http\Url::internal('app=core&module=support&controller=support') ), \IPS\Db::i()->select( 'COUNT(*)', 'core_hooks' )->first() );
|
||||
|
||||
\IPS\Output::i()->sidebar['actions']['systemcheck'] = array(
|
||||
'icon' => 'search',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=support&do=systemCheck' ),
|
||||
'title' => 'requirements_checker',
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,14 +110,14 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
public function _selfService( $data )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->next ) )
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/* Advice */
|
||||
if ( $data['type'] === 'advice' )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->next ) )
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
{
|
||||
$searchResults = array();
|
||||
if ( $data['keyword'] )
|
||||
{
|
||||
@@ -143,65 +144,31 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
|
||||
/* Issue */
|
||||
else
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->serviceDone ) )
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
{
|
||||
/* Get requirements and suggestions */
|
||||
$requirementsCheck = \IPS\core\Setup\Upgrade::systemRequirements();
|
||||
|
||||
$this->_clearCaches();
|
||||
|
||||
$baseUrl = \IPS\Http\Url::internal('app=core&module=support&controller=support&_step=self_service');
|
||||
|
||||
$overrideThingToTry = NULL;
|
||||
if ( isset( \IPS\Request::i()->next ) )
|
||||
{
|
||||
$overrideThingToTry = \IPS\Request::i()->next;
|
||||
$baseUrl = $baseUrl->setQueryString( 'next', $overrideThingToTry );
|
||||
}
|
||||
|
||||
$possibleSolutions = array( '_requirementsChecker', '_databaseChecker', '_clearCaches', '_connectionChecker', '_md5sumChecker', '_upgradeCheck', '_disableAdvertisements', '_disableThirdParty', '_knowledgebase' );
|
||||
$self = $this;
|
||||
|
||||
return new \IPS\Helpers\MultipleRedirect(
|
||||
$baseUrl,
|
||||
function( $thingToTry ) use ( $self, $possibleSolutions, $overrideThingToTry )
|
||||
{
|
||||
if ( !is_null( $overrideThingToTry ) and $overrideThingToTry > $thingToTry )
|
||||
{
|
||||
$thingToTry = $overrideThingToTry;
|
||||
}
|
||||
|
||||
if ( isset( $possibleSolutions[ $thingToTry ] ) )
|
||||
{
|
||||
$test = call_user_func( array( $self, $possibleSolutions[ $thingToTry ] ), $thingToTry );
|
||||
if ( is_string( $test ) )
|
||||
{
|
||||
return array( $test );
|
||||
}
|
||||
else
|
||||
{
|
||||
return array( $thingToTry + 1, \IPS\Member::loggedIn()->language()->addToStack( 'looking_for_problems' ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
},
|
||||
function() use ( $baseUrl )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'serviceDone', 1 ) );
|
||||
}
|
||||
);
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->diagnostics(
|
||||
(bool) $this->_requirementsChecker( $requirementsCheck ),
|
||||
$this->_upgradeCheck(),
|
||||
(bool) $this->_md5sumChecker(),
|
||||
(bool) $this->_databaseChecker(),
|
||||
$this->_connectionChecker(),
|
||||
$this->_thirdPartyCustomizations(),
|
||||
$this->_adviceChecker( $requirementsCheck ),
|
||||
$requirementsCheck
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Clear Caches
|
||||
*
|
||||
* @param int $thingToTry The current ID
|
||||
* @return string|NULL
|
||||
* @return NULL
|
||||
*/
|
||||
public function _clearCaches( $thingToTry )
|
||||
protected function _clearCaches()
|
||||
{
|
||||
/* Clear JS Maps first */
|
||||
\IPS\Output::clearJsFiles();
|
||||
@@ -216,269 +183,323 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
|
||||
\IPS\Data\Store::i()->clearAll();
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( ++$thingToTry, 'support_caches_cleared' );
|
||||
|
||||
\IPS\Member::clearCreateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Database Checker
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
* @return array Changes necessary
|
||||
*/
|
||||
public function _databaseChecker( $id )
|
||||
protected function _databaseChecker()
|
||||
{
|
||||
$changesToMake = array();
|
||||
$db = \IPS\Db::i();
|
||||
|
||||
/* Loop Apps */
|
||||
foreach ( \IPS\Application::applications() as $app )
|
||||
{
|
||||
$changesToMake = array_merge( $changesToMake, $app->databaseCheck() );
|
||||
}
|
||||
|
||||
/* Display */
|
||||
if ( $changesToMake )
|
||||
return $changesToMake;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Check for Uprade / known issues
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function _upgradeCheck()
|
||||
{
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: "Help me fix this" for database check fail
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function databasefail()
|
||||
{
|
||||
$changesToMake = $this->_databaseChecker();
|
||||
|
||||
\IPS\Output::i()->httpHeaders['X-IPS-FormNoSubmit'] = "true";
|
||||
|
||||
if ( isset( \IPS\Request::i()->run ) )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->run ) )
|
||||
$erroredQueries = array();
|
||||
$errors = array();
|
||||
foreach ( $changesToMake as $query )
|
||||
{
|
||||
$erroredQueries = array();
|
||||
$errors = array();
|
||||
foreach ( $changesToMake as $query )
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->query( $query['query'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$erroredQueries[] = $query['query'];
|
||||
$errors[] = $e->getMessage();
|
||||
}
|
||||
\IPS\Db::i()->query( $query['query'] );
|
||||
}
|
||||
if ( count( $erroredQueries ) )
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->databaseChecker( $id, ++$id, $erroredQueries, $errors );
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( ++$id, 'database_changes_made' );
|
||||
$erroredQueries[] = $query['query'];
|
||||
$errors[] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
if ( count( $erroredQueries ) )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->fixDatabase( $erroredQueries, $errors );
|
||||
}
|
||||
else
|
||||
{
|
||||
$queries = array();
|
||||
foreach ( $changesToMake as $query )
|
||||
{
|
||||
$queries[] = $query['query'];
|
||||
}
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->databaseChecker( $id, ++$id, $queries );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
|
||||
}
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->recheck ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( ++$id, 'database_changes_made' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
$queries = array();
|
||||
foreach ( $changesToMake as $query )
|
||||
{
|
||||
$queries[] = $query['query'];
|
||||
}
|
||||
|
||||
if ( count( $queries ) )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->fixDatabase( $queries, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - md5sum Checker
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
* @return array Modified files
|
||||
*/
|
||||
public function _md5sumChecker( $id )
|
||||
protected function _md5sumChecker()
|
||||
{
|
||||
try
|
||||
{
|
||||
$files = \IPS\Application::md5Check();
|
||||
if ( count( $files ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->md5sum( $files, $id );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: "Help me fix this" for md5sum fail
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function md5fail()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Requirements Checker (Includes File Permissions)
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
* @param array $requirements Requirements to check
|
||||
* @return array Necessary changes
|
||||
*/
|
||||
public function _requirementsChecker( $id )
|
||||
{
|
||||
$check = \IPS\core\Setup\Upgrade::systemRequirements();
|
||||
protected function _requirementsChecker( $check )
|
||||
{
|
||||
$return = array();
|
||||
foreach ( $check['requirements'] as $group => $requirements )
|
||||
{
|
||||
foreach ( $requirements as $requirement )
|
||||
{
|
||||
if ( !$requirement['success'] )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( $id, $requirement['message'], '', FALSE );
|
||||
$return[] = $requirement['message'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Check advice and look for recommendations
|
||||
*
|
||||
* @param array $requirements Requirements to check
|
||||
* @return array Necessary changes
|
||||
*/
|
||||
protected function _adviceChecker( $check )
|
||||
{
|
||||
$return = array();
|
||||
if( isset( $check['advice'] ) )
|
||||
{
|
||||
foreach ( $check['advice'] as $suggestion )
|
||||
{
|
||||
$return[] = $suggestion;
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') !== TRUE )
|
||||
{
|
||||
$return[] = \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_generic_explain');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Connection Checker
|
||||
* Step 2: Self Service - Connection and server clock checker
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
* @return int or string with error
|
||||
*/
|
||||
public function _connectionChecker( $id )
|
||||
protected function _connectionChecker()
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Http\Url::ips( 'connectionCheck' )->request()->get();
|
||||
return NULL;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->connectionChecker( ++$id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Check for Uprade
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function _upgradeCheck( $id )
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = \IPS\Http\Url::ips('updateCheck')->request()->get()->decodeJson();
|
||||
if ( $response['longversion'] > \IPS\Application::load('core')->long_version )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->upgrade( ++$id, $response['updateurl'] );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Disable advertisements
|
||||
* Step 2: "Help me fix this" for connection check fail
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
* @return void
|
||||
*/
|
||||
public function _disableAdvertisements( $id )
|
||||
protected function connectionfail()
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->enableAds ) )
|
||||
{
|
||||
foreach ( explode( ',', \IPS\Request::i()->enableAds ) as $ad )
|
||||
{
|
||||
try
|
||||
{
|
||||
$ad = \IPS\core\Advertisement::load( $ad );
|
||||
$ad->active = 1;
|
||||
$ad->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$disabledAds = array();
|
||||
|
||||
/* Loop ads */
|
||||
foreach( \IPS\Db::i()->select( '*' ,'core_advertisements', array( 'ad_active=?', 1 ) ) as $ad )
|
||||
{
|
||||
$ad = \IPS\core\Advertisement::constructFromData( $ad );
|
||||
|
||||
$ad->active = 0;
|
||||
$disabledAds[] = $ad->id;
|
||||
}
|
||||
|
||||
/* Do any? */
|
||||
if ( count( $disabledAds ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->disabledAdvertisements( $id, '&enableAds=' . implode( ',', $disabledAds ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Disable 3rd party apps/plugins
|
||||
* Step 2: "Help me fix this" for server time fail
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
* @return void
|
||||
*/
|
||||
public function _disableThirdParty( $id )
|
||||
protected function servertimefail()
|
||||
{
|
||||
/* Button to put stuff back */
|
||||
if ( isset( \IPS\Request::i()->deleteTheme ) or isset( \IPS\Request::i()->enableApps ) or isset( \IPS\Request::i()->enablePlugins ) )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Are there any third party customizations?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _thirdPartyCustomizations()
|
||||
{
|
||||
return ( count( $this->_thirdPartyApps() ) or count( $this->_thirdPartyPlugins() ) or $this->_thirdPartyTheme() or $this->_thirdPartyEditor() or count( $this->_thirdPartyAds() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Get third-party applications
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _thirdPartyApps()
|
||||
{
|
||||
if ( \IPS\NO_WRITES )
|
||||
{
|
||||
/* Theme */
|
||||
if ( isset( \IPS\Request::i()->deleteTheme ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Theme::load( \IPS\Request::i()->deleteTheme )->delete();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
if( isset( $_SESSION['old_acp_theme'] ) )
|
||||
{
|
||||
\IPS\Member::loggedIn()->acp_skin = $_SESSION['old_acp_theme'];
|
||||
\IPS\Member::loggedIn()->save();
|
||||
|
||||
unset( $_SESSION['old_acp_theme'] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Apps */
|
||||
foreach ( explode( ',', \IPS\Request::i()->enableApps ) as $app )
|
||||
{
|
||||
try
|
||||
{
|
||||
$app = \IPS\Application::load( $app );
|
||||
$app->enabled = TRUE;
|
||||
$app->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
/* Plugins */
|
||||
foreach ( explode( ',', \IPS\Request::i()->enablePlugins ) as $plugin )
|
||||
{
|
||||
try
|
||||
{
|
||||
$plugin = \IPS\Plugin::load( $plugin );
|
||||
$plugin->enabled = TRUE;
|
||||
$plugin->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return array();
|
||||
}
|
||||
|
||||
$apps = array();
|
||||
|
||||
foreach ( \IPS\Application::applications() as $app )
|
||||
{
|
||||
if ( $app->enabled and !in_array( $app->directory, \IPS\Application::$ipsApps ) )
|
||||
{
|
||||
$apps[] = $app;
|
||||
}
|
||||
}
|
||||
|
||||
return $apps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Get third-party plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _thirdPartyPlugins()
|
||||
{
|
||||
if ( \IPS\NO_WRITES )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$plugins = array();
|
||||
|
||||
foreach ( \IPS\Plugin::plugins() as $plugin )
|
||||
{
|
||||
if ( $plugin->enabled )
|
||||
{
|
||||
$plugins[] = $plugin;
|
||||
}
|
||||
}
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Has the theme been customised?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _thirdPartyTheme()
|
||||
{
|
||||
return (bool) \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', 'template_set_id>0' )->first() or \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_css', 'css_set_id>0' )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Has the editor been customised?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _thirdPartyEditor()
|
||||
{
|
||||
return ( \IPS\Settings::i()->ckeditor_extraPlugins or \IPS\Settings::i()->ckeditor_toolbars != \IPS\Db::i()->select( 'conf_default', 'core_sys_conf_settings', array( 'conf_key=?', 'ckeditor_toolbars' ) )->first() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Get third-party advertisements
|
||||
*
|
||||
* @return \IPS\Db\Select
|
||||
*/
|
||||
protected function _thirdPartyAds()
|
||||
{
|
||||
return \IPS\Db::i()->select( '*' ,'core_advertisements', array( 'ad_active=?', 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Disable Third Party Customizations
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function thirdparty()
|
||||
{
|
||||
/* Init */
|
||||
$restoredDefaultTheme = FALSE;
|
||||
$disabledApps = array();
|
||||
$disabledPlugins = array();
|
||||
$disabledAppNames = array();
|
||||
$disabledPluginNames = array();
|
||||
$restoredDefaultTheme = FALSE;
|
||||
$restoredEditor = FALSE;
|
||||
$disabledAds = array();
|
||||
|
||||
/* Do we need to disable any third party apps/plugins? */
|
||||
if ( !\IPS\NO_WRITES )
|
||||
{
|
||||
/* Loop Apps */
|
||||
foreach ( $this->_thirdPartyApps() as $app )
|
||||
{
|
||||
$app->enabled = FALSE;
|
||||
$app->save();
|
||||
|
||||
$disabledApps[] = $app->directory;
|
||||
$disabledAppNames[ $app->directory ] = $app->_title;
|
||||
}
|
||||
|
||||
/* Look Plugins */
|
||||
foreach ( $this->_thirdPartyPlugins() as $plugin )
|
||||
{
|
||||
$plugin->enabled = FALSE;
|
||||
$plugin->save();
|
||||
|
||||
$disabledPlugins[] = $plugin->id;
|
||||
$disabledPluginNames[ $plugin->id ] = $plugin->_title;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we need to restore the default theme? */
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', 'template_set_id>0' )->first() or \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_css', 'css_set_id>0' )->first() )
|
||||
if ( $this->_thirdPartyTheme() )
|
||||
{
|
||||
$newTheme = new \IPS\Theme;
|
||||
$newTheme->permissions = \IPS\Member::loggedIn()->member_group_id;
|
||||
@@ -486,7 +507,7 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
$newTheme->installThemeSettings();
|
||||
$newTheme->copyResourcesFromSet();
|
||||
|
||||
\IPS\Lang::saveCustom( 'core', "core_theme_set_title_" . $newTheme->id, "IPS Support" );
|
||||
\IPS\Lang::saveCustom( 'core', "core_theme_set_title_" . $newTheme->id, "IPS Default" );
|
||||
|
||||
\IPS\Member::loggedIn()->skin = $newTheme->id;
|
||||
|
||||
@@ -501,67 +522,135 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
$restoredDefaultTheme = TRUE;
|
||||
}
|
||||
|
||||
/* Do we need to disable any third party apps/plugins? */
|
||||
if ( !\IPS\NO_WRITES )
|
||||
{
|
||||
/* Loop Apps */
|
||||
foreach ( \IPS\Application::applications() as $app )
|
||||
{
|
||||
if ( $app->enabled and !in_array( $app->directory, \IPS\Application::$ipsApps ) )
|
||||
{
|
||||
$app->enabled = FALSE;
|
||||
$app->save();
|
||||
|
||||
$disabledApps[] = $app->directory;
|
||||
$disabledAppNames[] = $app->_title;
|
||||
}
|
||||
}
|
||||
/* Do we need to revert the editor? */
|
||||
if ( $this->_thirdPartyEditor() )
|
||||
{
|
||||
\IPS\Data\Store::i()->editorConfiguationToRestore = array(
|
||||
'extraPlugins' => \IPS\Settings::i()->ckeditor_extraPlugins,
|
||||
'toolbars' => \IPS\Settings::i()->ckeditor_toolbars,
|
||||
);
|
||||
|
||||
/* Look Plugins */
|
||||
foreach ( \IPS\Plugin::plugins() as $plugin )
|
||||
{
|
||||
if ( $plugin->enabled )
|
||||
{
|
||||
$plugin->enabled = FALSE;
|
||||
$plugin->save();
|
||||
|
||||
$disabledPlugins[] = $plugin->id;
|
||||
$disabledPluginNames[] = $plugin->_title;
|
||||
}
|
||||
}
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', 'ckeditor_toolbars' ) );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
|
||||
$restoredEditor = TRUE;
|
||||
}
|
||||
|
||||
/* Did we do anything? */
|
||||
if ( $restoredDefaultTheme or count( $disabledApps ) or count( $disabledPlugins ) )
|
||||
/* Do we need to disable any thid party ads? */
|
||||
foreach ( $this->_thirdPartyAds() as $ad )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->thirdParty( $id, $disabledAppNames, $disabledPluginNames, $restoredDefaultTheme, '&enableApps=' . implode( ',', $disabledApps ) . '&enablePlugins=' . implode( ',', $disabledPlugins ) . ( $restoredDefaultTheme ? '&deleteTheme=' . $newTheme->id : '' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
$ad = \IPS\core\Advertisement::constructFromData( $ad );
|
||||
$ad->active = 0;
|
||||
$ad->save();
|
||||
$disabledAds[] = $ad->id;
|
||||
}
|
||||
|
||||
/* Clear cache */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->thirdPartyDisabled(
|
||||
$disabledAppNames,
|
||||
$disabledPluginNames,
|
||||
$restoredDefaultTheme ? $newTheme->id : 0,
|
||||
$restoredEditor,
|
||||
$disabledAds,
|
||||
\IPS\Http\Url::internal('app=core&module=support&controller=support&do=thirdpartyEnable')->setQueryString( array(
|
||||
'enableApps' => implode( ',', $disabledApps ),
|
||||
'enablePlugins' => implode( ',', $disabledPlugins ),
|
||||
'deleteTheme' => $restoredDefaultTheme ? $newTheme->id : 0,
|
||||
'restoreEditor' => intval( $restoredEditor ),
|
||||
'enableAds' => implode( ',', $disabledAds )
|
||||
) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Self Service - Knowledgebase
|
||||
* Step 2: Re-Enable Third Party Customizations
|
||||
*
|
||||
* @param int $id The current ID
|
||||
* @return string|NULL
|
||||
* @return void
|
||||
*/
|
||||
public function _knowledgebase( $id )
|
||||
protected function thirdpartyEnable()
|
||||
{
|
||||
$kb = array();
|
||||
try
|
||||
/* Theme */
|
||||
if ( isset( \IPS\Request::i()->deleteTheme ) and \IPS\Request::i()->deleteTheme )
|
||||
{
|
||||
$kb = \IPS\Http\Url::ips('kb')->request()->get()->decodeJson();
|
||||
try
|
||||
{
|
||||
\IPS\Theme::load( \IPS\Request::i()->deleteTheme )->delete();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
if( isset( $_SESSION['old_acp_theme'] ) )
|
||||
{
|
||||
\IPS\Member::loggedIn()->acp_skin = $_SESSION['old_acp_theme'];
|
||||
\IPS\Member::loggedIn()->save();
|
||||
|
||||
unset( $_SESSION['old_acp_theme'] );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
if ( count( $kb ) )
|
||||
/* Apps */
|
||||
foreach ( explode( ',', \IPS\Request::i()->enableApps ) as $app )
|
||||
{
|
||||
try
|
||||
{
|
||||
$app = \IPS\Application::load( $app );
|
||||
$app->enabled = TRUE;
|
||||
$app->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
/* Plugins */
|
||||
foreach ( explode( ',', \IPS\Request::i()->enablePlugins ) as $plugin )
|
||||
{
|
||||
try
|
||||
{
|
||||
$plugin = \IPS\Plugin::load( $plugin );
|
||||
$plugin->enabled = TRUE;
|
||||
$plugin->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
/* Editor Plugins */
|
||||
if ( isset( \IPS\Request::i()->restoreEditor ) and \IPS\Request::i()->restoreEditor )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'support' )->knowledgebase( ++$id, $kb );
|
||||
$editorConfigutation = \IPS\Data\Store::i()->editorConfiguationToRestore;
|
||||
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $editorConfigutation['extraPlugins'] ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $editorConfigutation['toolbars'] ), array( 'conf_key=?', 'ckeditor_toolbars' ) );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
|
||||
unset( \IPS\Data\Store::i()->editorConfiguationToRestore );
|
||||
}
|
||||
|
||||
/* Ads Ads */
|
||||
foreach ( explode( ',', \IPS\Request::i()->enableAds ) as $ad )
|
||||
{
|
||||
try
|
||||
{
|
||||
$ad = \IPS\core\Advertisement::load( $ad );
|
||||
$ad->active = 1;
|
||||
$ad->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
/* Clear cache */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Output */
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->json( 'OK' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,167 +661,7 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
public function _contactSupport( $data )
|
||||
{
|
||||
$licenseData = \IPS\IPS::licenseKey();
|
||||
if ( !$licenseData or strtotime( $licenseData['expires'] ) < time() )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_no_license', 'warning' );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$supportedVerions = \IPS\Http\Url::ips('support/versions')->request()->get()->decodeJson();
|
||||
|
||||
if ( \IPS\Application::load('core')->long_version > $supportedVerions['max'] )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_unsupported_prerelease', 'warning' );
|
||||
}
|
||||
if ( \IPS\Application::load('core')->long_version < $supportedVerions['min'] )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_unsupported_obsolete', 'warning' );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
$form = new \IPS\Helpers\Form( 'contact_support', 'contact_support_submit' );
|
||||
$form->class = 'ipsForm_vertical ipsPad';
|
||||
|
||||
$extraOptions = array( 'admin' => 'support_request_admin' );
|
||||
if ( $this->_supportLog( TRUE ) )
|
||||
{
|
||||
$form->hiddenValues['_log'] = '1';
|
||||
$extraOptions['log'] = 'support_request_log';
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'support_request_title', NULL, TRUE, array( 'maxLength' => 128 ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'support_request_body', NULL, TRUE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'acp-support-request' ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'support_request_extra', array( 'admin', 'log' ), FALSE, array( 'options' => $extraOptions ) ) );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$admin = NULL;
|
||||
if ( in_array( 'admin', $values['support_request_extra'] ) )
|
||||
{
|
||||
$password = '';
|
||||
$length = rand( 8, 15 );
|
||||
for ( $i = 0; $i < $length; $i++ )
|
||||
{
|
||||
do {
|
||||
$key = rand( 33, 126 );
|
||||
} while ( in_array( $key, array( 34, 39, 60, 62, 92 ) ) );
|
||||
$password .= chr( $key );
|
||||
}
|
||||
|
||||
$supportAccount = \IPS\Member::load( 'nobody@invisionpower.com', 'email' );
|
||||
if ( !$supportAccount->member_id )
|
||||
{
|
||||
$name = 'IPS Support';
|
||||
$_supportAccount = \IPS\Member::load( $name, 'name' );
|
||||
if ( $_supportAccount->member_id )
|
||||
{
|
||||
$number = 2;
|
||||
while ( $_supportAccount->member_id )
|
||||
{
|
||||
$name = "IPS Support {$number}";
|
||||
$_supportAccount = \IPS\Member::load( $name, 'name' );
|
||||
$number++;
|
||||
}
|
||||
}
|
||||
|
||||
$supportAccount = new \IPS\Member;
|
||||
$supportAccount->name = $name;
|
||||
$supportAccount->email = 'nobody@invisionpower.com';
|
||||
$supportAccount->member_group_id = \IPS\Settings::i()->admin_group;
|
||||
}
|
||||
|
||||
$supportAccount->members_pass_salt = $supportAccount->generateSalt();
|
||||
$supportAccount->members_pass_hash = $supportAccount->encryptedPassword( $password );
|
||||
$supportAccount->save();
|
||||
|
||||
$admin = json_encode( array( 'name' => $supportAccount->name, 'email' => $supportAccount->email, 'password' => $password, 'dir' => \IPS\CP_DIRECTORY ) );
|
||||
}
|
||||
|
||||
$log = NULL;
|
||||
if ( in_array( 'log', $values['support_request_extra'] ) )
|
||||
{
|
||||
$log = $this->_supportLog( FALSE );
|
||||
}
|
||||
|
||||
$key = md5( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
|
||||
unset( $_SESSION["wizard-{$key}-step"] );
|
||||
unset( $_SESSION["wizard-{$key}-data"] );
|
||||
|
||||
\IPS\Output::i()->parseFileObjectUrls( $values['support_request_body'] );
|
||||
|
||||
$response = \IPS\Http\Url::ips('support')->request()->login( \IPS\Settings::i()->ipb_reg_number, '' )->post( array(
|
||||
'title' => $values['support_request_title'],
|
||||
'message' => $values['support_request_body'],
|
||||
'admin' => $admin,
|
||||
'log' => $log,
|
||||
'_log' => intval( isset( $values['_log'] ) )
|
||||
) );
|
||||
|
||||
switch ( $response->httpResponseCode )
|
||||
{
|
||||
case 200:
|
||||
case 201:
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( \IPS\Member::loggedIn()->language()->addToStack( 'get_support_done', FALSE, array( 'pluralize' => array( intval( (string) $response ) ) ) ), 'success' );
|
||||
|
||||
case 401:
|
||||
case 403:
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_no_license', 'warning' );
|
||||
|
||||
case 429:
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_duplicate', 'error' );
|
||||
|
||||
case 502:
|
||||
default:
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_error', 'error' );
|
||||
}
|
||||
}
|
||||
return (string) $form;
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->message( '__ipbmafia__nulling_null_alert', 'error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the log that will be sent
|
||||
*
|
||||
* @param bool $checkOnly If TRUE, will just check if there is one to send
|
||||
* @return void
|
||||
*/
|
||||
protected function _supportLog( $checkOnly )
|
||||
{
|
||||
$log = array();
|
||||
$oneDayAgo = \IPS\DateTime::create()->sub( new \DateInterval('P1D') );
|
||||
foreach( \IPS\Log::getUsedMethods() as $method => $levels )
|
||||
{
|
||||
if ( $method != 'none' and $logs = \IPS\Log::i( $method )->getLatestTitles( $oneDayAgo ) and !empty( $logs ) )
|
||||
{
|
||||
$log[ $method ] = $logs;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $checkOnly )
|
||||
{
|
||||
return !empty( $log );
|
||||
}
|
||||
|
||||
$output = '';
|
||||
foreach ( $log as $method => $files )
|
||||
{
|
||||
foreach ( $files as $file )
|
||||
{
|
||||
$output = "/************************/\n" . $file . "\n/************************/\n\n";
|
||||
$output .= \IPS\Log::i( $method )->getLog( $file );
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* View the log that will be sent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function supportLog()
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('support')->logToSend( $this->_supportLog( FALSE ) );
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
/**
|
||||
* @brief System Logs
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 13 Nov 2013
|
||||
* @package IPS Community Suite
|
||||
* @since 29 Mar 2016
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -41,78 +41,293 @@ class _systemLogs extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
/* Fetch the data */
|
||||
$dataSource = array();
|
||||
|
||||
foreach( \IPS\Log::getUsedMethods() as $method => $levels )
|
||||
{
|
||||
$logs = \IPS\Log::i( $method )->getMostRecentLogsTitles( 50 );
|
||||
|
||||
foreach( $logs as $log )
|
||||
{
|
||||
$log['method'] = $method;
|
||||
$dataSource[ $log['date'] . '.' . $log['suffix'] ] = $log;
|
||||
}
|
||||
}
|
||||
|
||||
krsort( $dataSource );
|
||||
|
||||
/* Create the table */
|
||||
$table = new \IPS\Helpers\Table\Custom( $dataSource, \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs' ) );
|
||||
$table->langPrefix = 'systemlogs_';
|
||||
$table->mainColumn = 'title';
|
||||
|
||||
$table->widths = array( 'date' => 30, 'title' => 50, 'suffix' => 20 );
|
||||
$table->parsers = array(
|
||||
'suffix'=> function( $val )
|
||||
{
|
||||
return mb_strtoupper( $val );
|
||||
},
|
||||
'method'=> function( $val )
|
||||
{
|
||||
return ucfirst( $val );
|
||||
},
|
||||
'date' => function( $val )
|
||||
{
|
||||
return \IPS\DateTime::ts( $val );
|
||||
},
|
||||
'title' => function( $val, $row )
|
||||
{
|
||||
return "<a href='" . \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs&do=view&title=" . urlencode( $val ) . '&method=' . $row['method'] ) . "'>{$val}</a>";
|
||||
}
|
||||
);
|
||||
$table->sortBy = $table->sortBy ?: 'date';
|
||||
$table->sortDirection = $table->sortDirection ?: 'desc';
|
||||
|
||||
/* Button to settings */
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'support', 'diagnostic_log_settings' ) )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions'] = array(
|
||||
'settings' => array(
|
||||
'title' => 'prunesettings',
|
||||
'icon' => 'cog',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=logSettings' ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
|
||||
),
|
||||
'settings' => array(
|
||||
'title' => 'prunesettings',
|
||||
'icon' => 'cog',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=logSettings' ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/* Button to view filebased logs */
|
||||
$dir = \IPS\Log::fallbackDir();
|
||||
if ( !\IPS\NO_WRITES and is_dir( $dir ) )
|
||||
{
|
||||
$hasFiles = FALSE;
|
||||
$dir = new \DirectoryIterator( $dir );
|
||||
foreach ( $dir as $file )
|
||||
{
|
||||
if ( mb_substr( $file, 0, 1 ) !== '.' and $file != 'index.html' )
|
||||
{
|
||||
$hasFiles = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $hasFiles )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions']['files'] = array(
|
||||
'title' => 'log_view_file_logs',
|
||||
'icon' => 'search',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=fileLogs' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Create table */
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_log', \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs' ) );
|
||||
$table->langPrefix = 'log_';
|
||||
$table->include = array( 'time', 'category', 'message' );
|
||||
$table->parsers = array(
|
||||
'message' => function( $val, $row ) {
|
||||
if ( mb_strlen( $val ) > 100 )
|
||||
{
|
||||
$val = mb_substr( $val, 0, 100 ) . '...';
|
||||
}
|
||||
if ( $row['exception_class'] )
|
||||
{
|
||||
$val = "{$row['exception_class']} ({$row['exception_code']})\n{$val}";
|
||||
}
|
||||
|
||||
$val = htmlspecialchars( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
|
||||
|
||||
return $val;
|
||||
},
|
||||
'time' => function( $val ) {
|
||||
return \IPS\DateTime::ts( $val );
|
||||
},
|
||||
'member_id' => function ( $val ){
|
||||
return \IPS\Member::load( $val )->name;
|
||||
}
|
||||
);
|
||||
$table->sortBy = $table->sortBy ?: 'time';
|
||||
$table->sortDirection = $table->sortDirection ?: 'desc';
|
||||
$table->quickSearch = 'message';
|
||||
$table->advancedSearch = array(
|
||||
'category' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => iterator_to_array( \IPS\Db::i()->select( 'DISTINCT(category) AS cat', 'core_log' )->setKeyField( 'cat' )->setValueField( 'cat' ) ), 'multiple' => TRUE, 'parse' => 'normal' ) ),
|
||||
'message' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
|
||||
'time' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
|
||||
'member_id' => \IPS\Helpers\Table\SEARCH_MEMBER,
|
||||
'url' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT
|
||||
);
|
||||
$table->rowButtons = function( $row ) {
|
||||
return array(
|
||||
'view' => array(
|
||||
'title' => 'view',
|
||||
'icon' => 'search',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=view' )->setQueryString( 'id', $row['id'] )
|
||||
),
|
||||
'delete' => array(
|
||||
'title' => 'delete',
|
||||
'icon' => 'times-circle',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=delete' )->setQueryString( 'id', $row['id'] ),
|
||||
'data' => array( 'delete' => '' )
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('r__system_logs');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'r__system_logs', (string) $table );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('r__system_logs');
|
||||
\IPS\Output::i()->output = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* View a log file
|
||||
* View a log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function view()
|
||||
{
|
||||
/* Load */
|
||||
try
|
||||
{
|
||||
$log = \IPS\Log::load( \IPS\Request::i()->id );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C324/1', 404, '' );
|
||||
}
|
||||
|
||||
/* Delete button */
|
||||
\IPS\Output::i()->sidebar['actions']['delete'] = array(
|
||||
'icon' => 'times-circle',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=delete' )->setQueryString( 'id', $log->id ),
|
||||
'title' => 'delete',
|
||||
'data' => array( 'confirm' => '' )
|
||||
);
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/systemlogs.css', 'core', 'admin' ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('r__system_logs');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->systemLogView( \IPS\Request::i()->title, \IPS\Log::i( \IPS\Request::i()->method )->getLog( urldecode( \IPS\Request::i()->title ) ) );
|
||||
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs" ), \IPS\Member::loggedIn()->language()->addToStack('r__system_logs') );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->systemLogView( $log );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function delete()
|
||||
{
|
||||
/* Load */
|
||||
try
|
||||
{
|
||||
$log = \IPS\Log::load( \IPS\Request::i()->id );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C324/2', 404, '' );
|
||||
}
|
||||
|
||||
/* Make sure the user confirmed the deletion */
|
||||
\IPS\Request::i()->confirmedDelete();
|
||||
|
||||
/* Delete */
|
||||
$log->delete();
|
||||
|
||||
/* Log and redirect */
|
||||
if ( $log->category )
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplog__log_delete', array( $log->category => FALSE, ( (string) \IPS\DateTime::ts( $log->time ) ) => FALSE ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplog__log_delete_uncategoried', array( ( (string) \IPS\DateTime::ts( $log->time ) ) => FALSE ) );
|
||||
}
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs' ), 'deleted' );
|
||||
}
|
||||
|
||||
/**
|
||||
* View File-based Logs list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fileLogs()
|
||||
{
|
||||
/* NO_WRITES check */
|
||||
if ( \IPS\NO_WRITES )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_writes', '1C324/8', 403, '' );
|
||||
}
|
||||
|
||||
/* Get list of files */
|
||||
$dir = \IPS\Log::fallbackDir();
|
||||
$source = array();
|
||||
if ( is_dir( $dir ) )
|
||||
{
|
||||
$directoryIterator = new \DirectoryIterator( $dir );
|
||||
foreach ( $directoryIterator as $file )
|
||||
{
|
||||
if ( mb_substr( $file, 0, 1 ) !== '.' and $file != 'index.html' )
|
||||
{
|
||||
$source[] = array( 'time' => $file->getMTime(), 'file' => (string) $file );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create table */
|
||||
$table = new \IPS\Helpers\Table\Custom( $source, \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=fileLogs' ) );
|
||||
$table->langPrefix = 'log_';
|
||||
$table->parsers = array(
|
||||
'time' => function( $val ) {
|
||||
return \IPS\DateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
$table->sortBy = $table->sortBy ?: 'time';
|
||||
$table->sortDirection = $table->sortDirection ?: 'desc';
|
||||
$table->rowButtons = function( $row ) {
|
||||
return array(
|
||||
'view' => array(
|
||||
'title' => 'view',
|
||||
'icon' => 'search',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=viewFile' )->setQueryString( 'file', $row['file'] )
|
||||
),
|
||||
'delete' => array(
|
||||
'title' => 'delete',
|
||||
'icon' => 'times-circle',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=deleteFile' )->setQueryString( 'file', $row['file'] ),
|
||||
'data' => array( 'delete' => '' )
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs" ), \IPS\Member::loggedIn()->language()->addToStack('r__system_logs') );
|
||||
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('file_logs') );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('file_logs');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms' )->blurb( \IPS\Member::loggedIn()->language()->addToStack('log_view_file_logs_info', FALSE, array( 'sprintf' => $dir ) ) ) . $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* View File-based Log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function viewFile()
|
||||
{
|
||||
/* NO_WRITES check */
|
||||
if ( \IPS\NO_WRITES )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_writes', '1C324/3', 403, '' );
|
||||
}
|
||||
|
||||
/* Try to find it */
|
||||
$file = \IPS\Log::fallbackDir() . DIRECTORY_SEPARATOR . preg_replace( '/[^a-z_0-9\.]/i', '', \IPS\Request::i()->file );
|
||||
if ( !is_file( $file ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C324/5', 404, '' );
|
||||
}
|
||||
|
||||
/* Delete button */
|
||||
\IPS\Output::i()->sidebar['actions']['delete'] = array(
|
||||
'icon' => 'times-circle',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=deleteFile' )->setQueryString( 'file', \IPS\Request::i()->file ),
|
||||
'title' => 'delete',
|
||||
'data' => array( 'confirm' => '' )
|
||||
);
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->title = basename( $file );
|
||||
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs" ), \IPS\Member::loggedIn()->language()->addToStack('r__system_logs') );
|
||||
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs&do=fileLogs" ), \IPS\Member::loggedIn()->language()->addToStack('log_view_file_logs') );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->systemLogFileView( file_get_contents( $file ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* View File-based Log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function deleteFile()
|
||||
{
|
||||
/* NO_WRITES check */
|
||||
if ( \IPS\NO_WRITES )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_writes', '1C324/4', 403, '' );
|
||||
}
|
||||
|
||||
/* Try to find it */
|
||||
$file = \IPS\Log::fallbackDir() . DIRECTORY_SEPARATOR . preg_replace( '/[^a-z_0-9\.]/i', '', \IPS\Request::i()->file );
|
||||
if ( !is_file( $file ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C324/6', 404, '' );
|
||||
}
|
||||
|
||||
/* Delete it */
|
||||
if ( !@unlink( $file ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'log_file_could_not_delete', '1C324/7', 403, '' );
|
||||
}
|
||||
|
||||
/* Log and redirect */
|
||||
\IPS\Session::i()->log( 'acplog__log_delete_file', array( basename( $file ) => FALSE ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=fileLogs' ), 'deleted' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief utf8mb4 Converter
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 15 April 2016
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\support;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* utf8mb4 Converter
|
||||
*/
|
||||
class _utf8mb4 extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'sql_toolbox' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_converter');
|
||||
|
||||
/* Check it isn't utf8mb4 already */
|
||||
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global', 'core')->message( 'utf8mb4_converter_finished', 'success' );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Requires MySQL 5.5.3 */
|
||||
if ( version_compare( \IPS\Db::i()->server_info, '5.5.3', '<' ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'utf8mb4_converter_requires_553', '1C325/1', 403, '' );
|
||||
}
|
||||
|
||||
/* Display Wizard */
|
||||
$supportController = new support;
|
||||
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( array(
|
||||
'utf8mb4_converter_intro' => array( $this, '_introduction' ),
|
||||
'utf8mb4_converter_convert' => array( $this, '_convert' ),
|
||||
'utf8mb4_converter_finish' => array( $this, '_finish' ),
|
||||
), \IPS\Http\Url::internal( 'app=core&module=support&controller=utf8mb4' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Introduction
|
||||
*
|
||||
* @param mixed $data Wizard Data
|
||||
* @return mixed
|
||||
*/
|
||||
public function _introduction( $data )
|
||||
{
|
||||
$form = new \IPS\Helpers\Form( 'utf8mb4_converter_intro', 'continue' );
|
||||
$form->hiddenValues['continue'] = 1;
|
||||
$form->addMessage( 'utf8mb4_converter_explain' );
|
||||
|
||||
if ( $form->values() )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
return (string) $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert
|
||||
*
|
||||
* @param mixed $wizardData Wizard Data
|
||||
* @return mixed
|
||||
*/
|
||||
public function _convert( $wizardData )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->finished ) )
|
||||
{
|
||||
return $wizardData;
|
||||
}
|
||||
|
||||
$baseUrl = \IPS\Http\Url::internal( 'app=core&module=support&controller=utf8mb4' );
|
||||
|
||||
return new \IPS\Helpers\MultipleRedirect( $baseUrl,
|
||||
function( $mrData )
|
||||
{
|
||||
try
|
||||
{
|
||||
/* If this is the first run, do the database itself... */
|
||||
if ( !is_array( $mrData ) )
|
||||
{
|
||||
$databaseName = \IPS\Settings::i()->sql_database;
|
||||
\IPS\Db::i()->query("ALTER DATABASE `{$databaseName}` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;");
|
||||
|
||||
return array( array( 'done' => array() ), \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_converter_converting'), 0 );
|
||||
}
|
||||
|
||||
/* Set properties */
|
||||
\IPS\Db::i()->charset = 'utf8mb4';
|
||||
\IPS\Db::i()->collation = 'utf8mb4_unicode_ci';
|
||||
\IPS\Db::i()->binaryCollation = 'utf8mb4_bin';
|
||||
|
||||
/* Do each table */
|
||||
$select = \IPS\Settings::i()->sql_tbl_prefix ? ( new \IPS\Db\Select( "SHOW TABLES LIKE '" . \IPS\Db::i()->escape_string( \IPS\Settings::i()->sql_tbl_prefix ) . "%'", array(), \IPS\Db::i() ) ) : ( new \IPS\Db\Select( "SHOW TABLES", array(), \IPS\Db::i() ) );
|
||||
$totalCount = count( $select );
|
||||
$i = 0;
|
||||
foreach ( $select as $table )
|
||||
{
|
||||
$i++;
|
||||
$table = mb_substr( $table, mb_strlen( \IPS\Settings::i()->sql_tbl_prefix ) );
|
||||
|
||||
/* If we've already done it, skip to next */
|
||||
if ( in_array( $table, $mrData['done'] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check it belongs to us */
|
||||
$appName = mb_substr( $table, 0, mb_strpos( $table, '_' ) );
|
||||
try
|
||||
{
|
||||
$app = \IPS\Application::load( $appName );
|
||||
$schema = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app->directory}/data/schema.json" ), TRUE );
|
||||
if ( !array_key_exists( $table, $schema ) )
|
||||
{
|
||||
/* Make a special exception for CMS database tables */
|
||||
if( $app->directory !== 'cms' OR mb_strpos( $table, 'cms_custom_database_' ) !== 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If this is the search index table, clear it first. Some clients have timeouts on this step with the search index
|
||||
table because it is large and it has a primary key and a unique index, so the table work is too intensive. */
|
||||
if( $table == 'core_search_index' )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_search_index' );
|
||||
}
|
||||
|
||||
/* Get table definition */
|
||||
$tableDefinition = \IPS\Db::i()->getTableDefinition( $table, FALSE, TRUE );
|
||||
|
||||
/* Drop any potentially problematic indexes */
|
||||
$indexesToRecreate = array();
|
||||
$maxLen = \mb_strtolower( $tableDefinition['engine'] ) === 'innodb' ? 767 : 1000;
|
||||
foreach ( $tableDefinition['indexes'] as $indexName => $indexData )
|
||||
{
|
||||
/* If this is a fulltext index, we don't need to drop it and recreate it */
|
||||
if( mb_strtolower( $indexData['type'] ) == 'fulltext' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$length = 0;
|
||||
$hasText = false;
|
||||
foreach( $indexData['columns'] as $column )
|
||||
{
|
||||
if ( in_array( mb_strtolower( $tableDefinition['columns'][ $column ]['type'] ), array( 'mediumtext', 'text' ) ) )
|
||||
{
|
||||
$hasText = true;
|
||||
}
|
||||
if ( isset( $tableDefinition['columns'][ $column ]['length'] ) )
|
||||
{
|
||||
$length += $tableDefinition['columns'][ $column ]['length'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( $length * 4 > $maxLen ) or $hasText )
|
||||
{
|
||||
$indexesToRecreate[ $indexName ] = $indexData;
|
||||
\IPS\Db::i()->dropIndex( $table, $indexName );
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the table */
|
||||
$repair = false;
|
||||
|
||||
if( $tableDefinition['collation'] !== 'utf8mb4_unicode_ci' )
|
||||
{
|
||||
\IPS\Db::i()->query("ALTER TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
||||
\IPS\Db::i()->query("ALTER TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
||||
$repair = true;
|
||||
}
|
||||
|
||||
/* Do each column */
|
||||
foreach ( $tableDefinition['columns'] as $columnName => $columnData )
|
||||
{
|
||||
if( in_array( \strtoupper( $columnData['type'] ), array( 'CHAR', 'VARCHAR', 'TINYTEXT', 'TEXT', 'MEDIUMTEXT', 'LONGTEXT', 'ENUM', 'SET' ) ) )
|
||||
{
|
||||
if( $tableDefinition['columns'][ $columnName ]['collation'] !== 'utf8mb4_unicode_ci' )
|
||||
{
|
||||
\IPS\Db::i()->changeColumn( $table, $columnName, $columnData );
|
||||
$repair = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Recreate any indexes */
|
||||
foreach ( $indexesToRecreate as $indexName => $indexData )
|
||||
{
|
||||
\IPS\Db::i()->addIndex( $table, $indexData );
|
||||
$repair = true;
|
||||
}
|
||||
|
||||
/* Repair and optimize */
|
||||
if( $repair === true )
|
||||
{
|
||||
\IPS\Db::i()->query("REPAIR TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}`");
|
||||
\IPS\Db::i()->query("OPTIMIZE TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}`");
|
||||
}
|
||||
|
||||
/* If this is the search index table, initiate rebuild now. */
|
||||
if( $table == 'core_search_index' )
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->rebuild();
|
||||
}
|
||||
|
||||
/* Continue */
|
||||
$mrData['done'][] = $table;
|
||||
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_converter_converting'), floor( 100 / $totalCount * $i ) );
|
||||
}
|
||||
|
||||
/* If we get to this point, we're finished */
|
||||
return NULL;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'utf8mb4_converter_error', FALSE, array( 'sprintf' => array( $e->getMessage() ) ) ), '4C171/4', 403, '' );
|
||||
}
|
||||
|
||||
},
|
||||
function() use ( $baseUrl )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'finished', 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish
|
||||
*
|
||||
* @param mixed $data Wizard Data
|
||||
* @return mixed
|
||||
*/
|
||||
public function _finish( $data )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('support')->finishUtf8Mb4Conversion();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user