<?php
/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.2.3
 * Diagnostic tools
 * Last Updated: $Date: 2011-09-13 21:55:41 -0400 (Tue, 13 Sep 2011) $
 * </pre>
 *
 * @author 		$Author: bfarber $
 * @copyright	(c) 2001 - 2009 Invision Power Services, Inc.
 * @license		http://www.invisionpower.com/community/board/license.html
 * @package		IP.Board
 * @subpackage	Core
 * @link		http://www.invisionpower.com
 * @since		1st march 2002
 * @version		$Revision: 9487 $
 */

if ( ! defined( 'IN_ACP' ) )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded 'admin.php'.";
	exit();
}


class admin_core_diagnostics_diagnostics extends ipsCommand
{
	/**
	 * Skin object
	 *
	 * @var		object			Skin templates
	 */
	protected $html;
	
	/**
	 * Shortcut for url
	 *
	 * @var		string			URL shortcut
	 */
	protected $form_code;
	
	/**
	 * Shortcut for url (javascript)
	 *
	 * @var		string			JS URL shortcut
	 */
	protected $form_code_js;
	
	/**
	 * Db tools
	 *
	 * @var		object
	 */
	protected $dbTools;
	
	/**
	 * Main class entry point
	 *
	 * @param	object		ipsRegistry reference
	 * @return	@e void		[Outputs to screen]
	 */
	public function doExecute( ipsRegistry $registry ) 
	{
		/* Load skin and setup stuff */
		$this->html			= $this->registry->output->loadTemplate('cp_skin_diagnostics');
		$this->form_code	= $this->html->form_code	= 'module=diagnostics&amp;section=diagnostics';
		$this->form_code_js	= $this->html->form_code_js	= 'module=diagnostics&section=diagnostics';
		
		//-----------------------------------------
		// Some of these functions can take a while..
		//-----------------------------------------
		
		@set_time_limit(0);
		
		//-----------------------------------------
		// Load lang
		//-----------------------------------------
				
		ipsRegistry::getClass('class_localization')->loadLanguageFile( array( 'admin_system' ), 'core' );

		///----------------------------------------
		// What to do...
		//-----------------------------------------
		
		switch( $this->request['do'] )
		{
			case 'dbindex':
				$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'index_checker' );
				$this->_indexCheck();
			break;
				
			case 'dbchecker':
				$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'database_checker' );
				$this->_dbCheck();
			break;			
				
			case 'whitespace':
				$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'whitespace_checker' );
				$this->_whitespaceCheck();
			break;
			
			case 'connections':
				$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'connection_checker' );
				$this->_checkConnections();
			break;
				
			case 'filepermissions':
				$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'permission_checker' );
				$this->_permissionsCheck();
			break;
				
			case 'fileversions':
				$this->registry->getClass('class_permissions')->checkPermissionAutoMsg( 'version_checker' );
				$this->_versionCheck();
			break;
			
			/* Topic Marking */
			case 'tm_index':
				$this->_tmIndex();
			break;
			case 'tm_memberindex':
				$this->_tmMemberIndex();
			break;
			case 'tm_viewLog':
				$this->_tmViewLog();
			break;
			
			default:
				$this->_listFunctions();
			break;
		}
		
		//-----------------------------------------
		// Pass to CP output hander
		//-----------------------------------------
		
		$this->registry->getClass('output')->html_main .= $this->registry->getClass('output')->global_template->global_frame_wrapper();
		$this->registry->getClass('output')->sendOutput();
	}
	
	/**
	 * Test outbound connections
	 *
	 * @return	@e void		[Outputs to screen]
	 */
	public function _checkConnections()
	{
		//-----------------------------------------
		// Turn errors on so we can view them
		//-----------------------------------------
		
		@ini_set( 'display_errors', 1 );
		error_reporting( E_ALL ^ E_NOTICE );
		
		$classToLoad = IPSLib::loadLibrary( IPS_KERNEL_PATH . 'classFileManagement.php', 'classFileManagement' );
		$_files = new $classToLoad();
		
		$_test		= $_files->getFileContents( "http://www.google.com/" );
		$_headers	= $_files->raw_headers;
		
		$_test1		= $_files->getFileContents( "https://www.google.com/" );
		$_headers1	= $_files->raw_headers;
		
		$this->registry->output->html .= $this->html->connectionCheckerResult( $_headers, $_test, $_headers1, $_test1 );
	}
	
	/**
	 * Check file versions
	 *
	 * @return	@e void		[Outputs to screen]
	 */
	public function _versionCheck()
	{
		$file_versions		= array();
		$upgrade_history	= array();
		$latest_version		= array( 'upgrade_version_id' => '' );
		$file_versions		= $this->_versionDirRecurse( rtrim( DOC_IPS_ROOT_PATH, '/\\' ) );

   		$this->DB->build( array( 'select' => '*', 'from' => 'upgrade_history', 'where' => "upgrade_app='core'", 'order' => 'upgrade_version_id DESC', 'limit' => array(0, 5) ) );
   		$this->DB->execute();
   		
   		while( $r = $this->DB->fetch() )
   		{
   			if ( $r['upgrade_version_id'] > $latest_version['upgrade_version_id'] )
   			{
   				$latest_version = $r;
   			}
   			
   			$upgrade_history[] = $r;
   		}
   		
		//-----------------------------------------
		// Got real version number?
		//-----------------------------------------

		$version['version']			= ( IPB_VERSION == '3.2.3' ) ? $latest_version['upgrade_version_human'] : IPB_VERSION;
		$version['version_full']	= ( IPB_LONG_VERSION == '32006' ) ? $latest_version['upgrade_version_id'] : IPB_LONG_VERSION;

		//-----------------------------------------
		// Version History
		//-----------------------------------------
			
		if( count($upgrade_history) )
		{
			foreach( $upgrade_history as $r )
			{
				$r['_date']		= ipsRegistry::getClass( 'class_localization')->getDate( $r['upgrade_date'], 'SHORT' );
				
				$thiscontent	.= $this->html->acp_version_history_row( $r );
			}
		}
				
		$this->registry->output->html .= $this->html->versionCheckerResults( $version, $thiscontent, $file_versions );
	}
	
	/**
	 * Check file versions
	 *
	 * @param	string		Directory to check
	 * @return	array 		Files => Versions
	 */
	public function _versionDirRecurse($dir)
	{
		/* Init some vars */
		$files     = array();
		$skip_dirs = array( PUBLIC_DIRECTORY, 
							'cache',  
							'uploads', 
							'images', 
							'i18n', 
							'PEAR', 
							rtrim( str_replace( DOC_IPS_ROOT_PATH, '', IPS_HOOKS_PATH ), '/\\' ), 
							'facebook-client', 
							'FirePHPCore', 
							'facebook', 
							'resources',
							'applications_addon', 
							'js', 
							'skin_cp',
							'install',
							'upgrade',
							'Auth'
							);

		$skip_files	= array('conf_global.php', 
							'conf.php',
							$this->settings['sql_driver'] . '_updates.php',
							$this->settings['sql_driver'] . '_install.php',
							$this->settings['sql_driver'] . '_fulltext.php',
							'classGraph.php',		// This is Wizzy's
							);
		
		/* Check files */
		try
		{
			foreach( new DirectoryIterator( $dir ) as $directory )
			{
				if( $directory->isDot() )
				{
					continue;
				}
        	
	    		if ( strpos( $directory->getFilename(), '_' ) === 0 OR strpos( $directory->getFilename(), '.' ) === 0 )
	    		{
			    	continue;
			    }
        	
				$newpath = $dir . '/' . $directory->getFilename();
				$level   = explode( '/', $newpath );
        	
				if ( is_dir($newpath) && !in_array( $directory->getFilename(), $skip_dirs ) )
				{
					$files = array_merge( $files, $this->_versionDirRecurse($newpath) );
				}
				else
				{
					if ( strpos( $directory->getFilename(), ".php" ) !== false && !is_dir( $newpath ) && !in_array( $directory->getFilename(), $skip_files ) )
					{
						$file = file_get_contents($newpath);
        	
						preg_match( "#@version\s+?v(.+?)\\n#i", $file, $matches );
						
						$files[ $newpath ] = isset($matches[1]) ? $matches[1] : '';
					}
				}
			}
		} catch ( Exception $e ) {}

		return $files;
	}
	
	/**
	 * Check file permissions
	 *
	 * @return	@e void		[Outputs to screen]
	 */
	public function _permissionsCheck()
	{
		$checkdirs = array( PUBLIC_DIRECTORY . '/style_images', 
							PUBLIC_DIRECTORY . '/style_css', 
							PUBLIC_DIRECTORY . '/style_emoticons', 
							'cache', 
							'cache/skin_cache', 
							'cache/lang_cache', 
							'cache/tmp', 
							'cache/openid', 
							'uploads',
							'uploads/profile', 
							rtrim( str_replace( DOC_IPS_ROOT_PATH, '', IPS_HOOKS_PATH ), '/\\' ),
							);
		
		//-----------------------------------------		
		// Get language directories
		//-----------------------------------------

		if( is_array( $this->cache->getCache('lang_data') ) && count( $this->cache->getCache('lang_data') ) )
		{
			foreach( $this->cache->getCache('lang_data') as $v )
			{
				$this_lang   = 'cache/lang_cache/' . $v['lang_id'];
				$checkdirs[] = $this_lang;
				
				try
				{
					foreach( new DirectoryIterator( rtrim( DOC_IPS_ROOT_PATH, '/\\' ) . '/' . $this_lang ) as $file )
					{
						if( $file->isFile() )
						{
							$checkdirs[] = $this_lang . '/' . $file->getFilename();
						}
					}
				} catch ( Exception $e ) {}
			}
		}
		else
		{
			$this->DB->build( array( 'select' => 'lang_id', 'from' => 'core_sys_lang' ) );
			$this->DB->execute();
			
			while( $v = $this->DB->fetch() )
			{
				$this_lang		= 'cache/lang_cache/' . $v['lang_id'];
				$checkdirs[]	= $this_lang;
				
				try
				{
					foreach( new DirectoryIterator( rtrim( DOC_IPS_ROOT_PATH, '/\\' ) . '/' . $this_lang ) as $file )
					{
						if( $file->isFile() )
						{
							$checkdirs[] = $this_lang . '/' . $file->getFilename();
						}
					}
				} catch ( Exception $e ) {}		
			}
		}
		
		//-----------------------------------------		
		// Get emoticon directories
		//-----------------------------------------
				
		if( is_array( $this->cache->getCache('emoticons') ) && count( $this->cache->getCache('emoticons') ) )
		{
			foreach( $this->cache->getCache('emoticons') as $v )
			{
				$checkdirs[] = PUBLIC_DIRECTORY . '/style_emoticons/' . $v['emo_set'];
			}
		}
		else
		{
			$this->DB->build( array( 'select' => 'emo_set', 'from' => 'emoticons' ) );
			$this->DB->execute();
			
			while( $v = $this->DB->fetch() )
			{
				$checkdirs[] = PUBLIC_DIRECTORY . '/style_emoticons/' . $v['emo_set'];
			}
		}
		
		//-----------------------------------------		
		// Get skin directories
		//-----------------------------------------
				
		$skin_dirs = array();
		
		if( is_array( $this->cache->getCache('skin_id_cache') ) && count( $this->cache->getCache('skin_id_cache') ) )
		{
			foreach( $this->cache->getCache('skin_id_cache') as $k => $v )
			{
				if( $k == 1 && !IN_DEV )
				{
					continue;
				}
				
				$checkdirs[]	= 'cache/skin_cache/cacheid_' . $v['set_id'];
				$skin_dirs[]	= $v['set_skin_set_id'];
			}
		}
		else
		{
			$this->DB->build( array( 'select' => 'set_id', 'from' => 'skin_collections' ) );
			$this->DB->execute();
			
			while( $v = $this->DB->fetch() )
			{
				$checkdirs[]	= 'cache/skin_cache/cacheid_' . $v['set_id'];
				$skin_dirs[]	= $v['set_skin_set_id'];
			}
		}
		
		//-----------------------------------------		
		// Get skin files
		//-----------------------------------------
		
		$this->DB->build( array( 'select' => $this->DB->buildDistinct( 'template_group' ),
								 'from'   => 'skin_templates',
								 'group'  => 'template_group',
						 )		);
		$this->DB->execute();
		
		while( $v = $this->DB->fetch() )
		{
			foreach( $skin_dirs as $dir )
			{
				$checkdirs[] = 'cache/skin_cache/cacheid_' . $dir . '/' . $v['group_name'] . '.php';
			}
		}
		
		$checkdirs	= array_unique($checkdirs);
		$output		= array();
		
		foreach( $checkdirs as $dir_to_check )
		{
			if( !file_exists( rtrim( DOC_IPS_ROOT_PATH, '/\\' ) . '/' . $dir_to_check ) )
			{
				# Could be skin files from custom skins for components they don't own
				# or they could be using safe_mode skins
				# Make sure skin_cache still shows up though...
				
				if( !strpos( $dir_to_check, 'skin_' ) OR !strpos( $dir_to_check, '.php' ) )
				{
					$output[] = "<span style='color:red;font-weight:bold;'>{$this->lang->words['d_p404']} ". rtrim( DOC_IPS_ROOT_PATH, '/\\' ) . "/{$dir_to_check}</span>";
				}
			}
			else 
			{
				$output[] = ( is_writable( DOC_IPS_ROOT_PATH . '/' . $dir_to_check ) ) ? "<span style='color:green;'>" . rtrim( DOC_IPS_ROOT_PATH, '/\\' ) . "/{$dir_to_check} {$this->lang->words['d_pyes']}</span>" : "<span style='color:red;font-weight:bold;'>{$this->lang->words['d_pno']} ". rtrim( DOC_IPS_ROOT_PATH, '/\\' ) . "/{$dir_to_check}</span>";;
			}
		}
		
		$this->registry->output->html .= $this->html->permissionsResults( $output );
	}
	
	/**
	 * Whitespace checking
	 *
	 * @return	@e void		[Outputs to screen]
	 */
	public function _whitespaceCheck()
	{
		$files_with_junk = $this->_whitespaceDirRecurse( rtrim( DOC_IPS_ROOT_PATH, '/\\' ) );
		
		$this->registry->output->html .= $this->html->whitespaceResults( $files_with_junk );
	}
	
	/**
	 * Recurse over a directory
	 *
	 * @param	string		Directory to check
	 * @return	array 		Array of files with whitespace in them
	 */
	public function _whitespaceDirRecurse( $dir )
	{
		$skip_dirs = array( 'uploads',
							PUBLIC_DIRECTORY,
							'js',
							'images',
							);
		
		$files	= array();
		
		try
		{
			foreach( new DirectoryIterator( $dir ) as $directory )
			{
				if( $directory->isDot() )
				{
					continue;
				}
        	
	    		if ( strpos( $directory->getFilename(), '_' ) === 0 OR strpos( $directory->getFilename(), '.' ) === 0 )
	    		{
			    	continue;
			    }
        	
				$newpath	= $dir . '/' . $directory->getFilename();
				$level		= explode( '/', $newpath );
        	
				if ( is_dir($newpath) && !in_array( $directory->getFilename(), $skip_dirs ) )
				{
					$files = array_merge( $files, $this->_whitespaceDirRecurse($newpath) );
				}
				else
				{
					if ( strpos( $directory->getFilename(), ".php" ) !== false && !is_dir( $newpath ) )
					{
						$file			= file_get_contents($newpath);
						$has_whitespace	= false;
						
						if( substr( ltrim($file), 0, 3 ) == '<?php' AND substr( $file, 0, 3 ) != '<?php' )
						{
							$has_whitespace	= true;
						}
						else if( substr( rtrim($file), -2 ) == '?>' AND substr( $file, -2 ) != '?>' )
						{
							//-----------------------------------------
							// PHP explicitly allows one newline after closing tag
							//-----------------------------------------
							
							if( substr( rtrim($file), -2 ) == '?>' AND substr( $file, -3 ) != "?>\n" )
							{
								$has_whitespace	= true;
							}
						}
        	
						if( $has_whitespace )
						{
							$files[] = $newpath;
						}
					}
				}
			}
		} catch ( Exception $e ) {}
		
		return $files;
	}
	
	/**
	 * Table and index checker basic stuff
	 *
	 * @param	void
	 * @return	array 	Table files
	 */
	public function _getDbTools()
	{
		//-----------------------------------------
		// First we get the SQL definitions for each app
		//-----------------------------------------
		
		$sql_table_files = array();
		
		foreach( $this->registry->getApplications() as $app )
		{
			$_file = IPSLib::getAppDir( $app['app_directory'] ) . '/setup/versions/install/sql/' . $app['app_directory'] . '_' . strtolower( ipsRegistry::$settings['sql_driver'] ) . '_tables.php';
			
			if( is_file( $_file ) )
			{
				$sql_table_files[ $app['app_title'] ] = $_file;
			}
		}
		
		//-----------------------------------------
		// Get the library to run the checks
		//-----------------------------------------
		
		$classToLoad = IPSLib::loadLibrary( IPS_KERNEL_PATH . 'db_lib/' . strtolower( ipsRegistry::$settings['sql_driver'] ) . '_tools.php', 'db_tools' );
		$this->dbTools = new $classToLoad();
		
		return $sql_table_files;
	}

	/**
	 * Check the database for missing indexes
	 *
	 * @return	@e void		[Outputs to screen]
	 */
	public function _indexCheck()
	{
		//-----------------------------------------
		// First we get the SQL definitions for each app
		//-----------------------------------------
		
		$sql_table_files = $this->_getDbTools();

		//-----------------------------------------
		// Now let's loop
		//-----------------------------------------
		
		$errors_array = array();
		$tables_array = array();
		
		foreach( $sql_table_files as $app_title => $sql_file )
		{
			$TABLE = array();
			require_once( $sql_file );/*noLibHook*/
			
			if ( is_array( $TABLE ) AND count( $TABLE ) )
			{
				$output = $this->dbTools->dbIndexDiag( $TABLE, $this->request['fix'] );
			
				if( !$output )
				{
					continue;
				}

				if( $output['error_count'] > 0 )
				{
					$errors_array[] = $app_title;
				}
			
				$tables_array[$app_title] = $output['results'];
			}
		}

		/* Output */
		$this->registry->output->html .= $this->html->indexChecker( $errors_array, $tables_array );
    }
    
	/**
	 * Check the database for missing tables/columns
	 *
	 * @return	@e void		[Outputs to screen]
	 * @todo 	[Future] Functionality to show EXTRA columns/tables?
	 */
	public function _dbCheck()
	{
		//-----------------------------------------
		// First we get the SQL definitions for each app
		//-----------------------------------------
		
		$sql_table_files = $this->_getDbTools();
		
		//-----------------------------------------
		// Now let's loop
		//-----------------------------------------
		
		$errors_array = array();
		$tables_array = array();
		
		foreach( $sql_table_files as $app_title => $sql_file )
		{
			$TABLE = array();
			require_once( $sql_file );/*noLibHook*/
			
			$output = $this->dbTools->dbTableDiag( $TABLE, $this->request['fix'] );

			if( !$output )
			{
				continue;
			}

			if( $output['error_count'] > 0 )
			{
				$errors_array[] = $app_title;
			}
			
			$tables_array[$app_title] = $output['results'];
		}

		//-----------------------------------------
		// And output
		//-----------------------------------------
		
		$this->registry->output->html .= $this->html->dbChecker( $errors_array, $tables_array );
    }    
	
	/**
	 * Show the overview page
	 *
	 * @return	@e void		[Outputs to screen]
	 */
	public function _listFunctions()
	{
		//-----------------------------------------
		// Stats
		//-----------------------------------------

		$reg	= $this->DB->buildAndFetch( array(
													'select' 	=> 'COUNT(*) as reg'  ,
													'from' 		=> array( 'validating' => 'v' ),
													'where' 	=> 'v.lost_pass <> 1 AND m.member_group_id=' . $this->settings['auth_group'],
													'add_join'	=> array( array(
																				'from'	=> array( 'members' => 'm' ),
																 				'where'	=> 'm.member_id=v.member_id',
																 				'type'	=> 'left'
																 			) ) )	);

		if( $this->settings['ipb_bruteforce_attempts'] )
		{
			$lock	= $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as mems'  , 'from' => 'members', 'where' => 'failed_login_count >= ' . $this->settings['ipb_bruteforce_attempts'] ) );
		}

		$my_timestamp = time() - $this->settings['au_cutoff'] * 60;

		$online	 = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as sessions', 'from' => 'sessions', 'where' => 'running_time>' . $my_timestamp ) );

		$pending = $this->DB->buildAndFetch( array( 'select' => 'SUM(queued_topics) as topics, SUM(queued_posts) as posts', 'from' => 'forums' ) );

		$spammers = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as count',
													 'from'   => 'members',
													 'where'  => "members_bitoptions = '1'" ) );

		$statsbox = $this->html->acp_stats_wrapper( array( 'topics'      => ipsRegistry::getClass('class_localization')->formatNumber($this->caches['stats']['total_topics']),
														   'replies'     => ipsRegistry::getClass('class_localization')->formatNumber($this->caches['stats']['total_replies']),
														   'topics_mod'	 => ipsRegistry::getClass('class_localization')->formatNumber($pending['topics']),
														   'posts_mod'	 => ipsRegistry::getClass('class_localization')->formatNumber($pending['posts']),
														   'members'     => ipsRegistry::getClass('class_localization')->formatNumber($this->caches['stats']['mem_count']),
														   'validate'    => ipsRegistry::getClass('class_localization')->formatNumber( $reg['reg'] ),
														   'spammer'     => ipsRegistry::getClass('class_localization')->formatNumber( $spammers['count'] ),
														   'locked'		 => ipsRegistry::getClass('class_localization')->formatNumber( $lock['mems'] ),
														   'sql_driver'  => strtoupper(SQL_DRIVER),
														   'sql_version' => $this->DB->true_version,
														   'php_version' => phpversion(),
														   'sessions'	 => ipsRegistry::getClass('class_localization')->formatNumber($online['sessions']),
														   'php_sapi'    => @php_sapi_name(),
														   'ipb_version' => ipsRegistry::$version,
														   'ipb_id'      => ipsRegistry::$vn_full ) );
		
		//-----------------------------------------
		// PHP INFO?
		//-----------------------------------------
		
		if ( $this->request['phpinfo'] AND $this->request['phpinfo'] )
		{
			@ob_start();
			phpinfo();
			$parsed = @ob_get_contents();
			@ob_end_clean();
			
			preg_match( "#<body>(.*)</body>#is" , $parsed, $match1 );
			
			$php_body  = $match1[1];
			
			# PREVENT WRAP: Most cookies
			$php_body  = str_replace( "; " , ";<br />"   , $php_body );
			# PREVENT WRAP: Very long string cookies
			$php_body  = str_replace( "%3B", "<br />"    , $php_body );
			# PREVENT WRAP: Serialized array string cookies
			$php_body  = str_replace( ";i:", ";<br />i:" , $php_body );
			# PREVENT WRAP: LS_COLORS env
			$php_body  = str_replace( ":*.", "<br />:*." , $php_body );
			# PREVENT WRAP: PATH env
			$php_body  = str_replace( "bin:/", "bin<br />:/" , $php_body );
			# PREVENT WRAP: Cookie %2C split
			$php_body  = str_replace( "%2C", "%2C<br />" , $php_body );
			#PREVENT WRAP: Cookie , split
			$php_body  = preg_replace( "#,(\d+),#", ",<br />\\1," , $php_body );
		  
			$this->registry->output->html .= $this->html->phpInfo( $php_body );
			return;
		}

		//-----------------------------------------
		// Server stuff
		//-----------------------------------------
        
		$this->DB->getSqlVersion();

		$sql_version		= strtoupper($this->settings['sql_driver']) . " " . $this->DB->true_version;
		
		$php_version		= phpversion() . " (" . @php_sapi_name() . ")  ( <a href='{$this->settings['base_url']}{$this->form_code}&amp;phpinfo=1'>{$this->lang->words['d_aphpinfo']}</a> )";
		$server_software	= @php_uname();
		
		$load_limit			= IPSDebug::getServerLoad();
        $server_load_found	= 0;
        $total_memory		= "--";
        $avail_memory		= "--";
        $_disabled			= @ini_get('disable_functions') ? explode( ',', @ini_get('disable_functions') ) : array();
        $_shellExecAvail	= in_array( 'shell_exec', $_disabled ) ? false : true;

		//-----------------------------------------
		// Check memory
		//-----------------------------------------

		if( strpos( strtolower( PHP_OS ), 'win' ) === 0 )
		{
			$mem = $_shellExecAvail ? @shell_exec('systeminfo') : null;
			
			if( $mem )
			{
				$server_reply = explode( "\n", str_replace( "\r", "", $mem ) );
				
				if( count($server_reply) )
				{
					foreach( $server_reply as $info )
					{
						if( strstr( $info, $this->lang->words['d_atotal'] ) )
						{
							$total_memory =  trim( str_replace( ":", "", strrchr( $info, ":" ) ) );
						}
						
						if( strstr( $info, $this->lang->words['d_aavail']) )
						{
							$avail_memory =  trim( str_replace( ":", "", strrchr( $info, ":" ) ) );
						}
					}
				}
			}
		}
		else
		{
			$mem			= $_shellExecAvail ? @shell_exec("free -m") : null;
			
			if( $mem )
			{
				$server_reply	= explode( "\n", str_replace( "\r", "", $mem ) );
				$mem			= array_slice( $server_reply, 1, 1 );
				$mem			= preg_split( "#\s+#", $mem[0] );
	
				$total_memory	= ( $mem[1] ) ? $mem[1] . ' MB' : '--';
				$avail_memory	= ( $mem[3] ) ? $mem[3] . ' MB' : '--';
			}
			else
			{
				$total_memory	= '--';
				$avail_memory	= '--';
			}
		}
		
		$disabled_functions	= ( is_array($_disabled) && count($_disabled) ) ? implode( ', ', $_disabled ) : $this->lang->words['d_anoinfo'];
		$extensions			= get_loaded_extensions();
		$extensions			= array_combine( $extensions, $extensions );
		sort( $extensions, SORT_STRING );
		
   		//-----------------------------------------
   		// Upgrade history?
   		//-----------------------------------------
   		
		$upgrade_history	= array();
   		$latest_version		= array( 'upgrade_version_id' => NULL );
   		
   		$this->DB->build( array( 'select' => '*', 'from' => 'upgrade_history', 'where' => "upgrade_app='core'", 'order' => 'upgrade_version_id DESC', 'limit' => array( 0, 5 ) ) );
   		$this->DB->execute();
   		
   		while( $r = $this->DB->fetch() )
   		{
   			if ( $r['upgrade_version_id'] > $latest_version['upgrade_version_id'] )
   			{
   				$latest_version = $r;
   			}
   			
   			$upgrade_history[] = $r;
   		}
   		
		//-----------------------------------------
		// Got real version number?
		//-----------------------------------------

		$version['version']			= (IPB_VERSION == '3.0.0 RC 1') ? $latest_version['upgrade_version_human'] : IPB_VERSION;
		$version['version_full']	= (IPB_LONG_VERSION == '30005') ? $latest_version['upgrade_version_id'] : IPB_LONG_VERSION;

		//-----------------------------------------
		// Version History
		//-----------------------------------------
		
		foreach( $upgrade_history as $r )
		{
			$r['_date']		= ipsRegistry::getClass( 'class_localization')->getDate( $r['upgrade_date'], 'SHORT' );
			
			$thiscontent	.= $this->html->acp_version_history_row( $r );
		}
		
		//-----------------------------------------
		// Set variables and pass to skin
		//-----------------------------------------
		
		$data = array(
						'version'			=> 'v' . $version['version'],
						'version_full'		=> $version['version_full'],
						'version_sql'		=> $sql_version,
						'driver_type'		=> strtoupper($this->settings['sql_driver']),
						'version_php'		=> $php_version,
						'disabled'			=> $disabled_functions,
						'extensions'		=> str_replace( "suhosin", "<strong>suhosin</strong>", implode( ", ", $extensions ) ),
						'safe_mode'			=> SAFE_MODE_ON == 1 ? "<span style='color:red;font-weight:bold;'>{$this->lang->words['d_aon']}</span>" : "<span style='color:green;font-weight:bold;'>{$this->lang->words['d_aoff']}</span>",
						'server'			=> $server_software,
						'load'				=> $load_limit,
						'total_memory'		=> $total_memory,
						'avail_memory'		=> $avail_memory,
					);

		if( $_shellExecAvail )
		{
			if( strpos( strtolower( PHP_OS ), 'win' ) === 0 )
			{
				$tasks = @shell_exec( "tasklist" );
				$tasks = str_replace( " ", "&nbsp;", $tasks );
			}
			else if( strtolower( PHP_OS ) == 'darwin' )
			{
				$tasks = @shell_exec( "top -l 1" );
				$tasks = str_replace( " ", "&nbsp;", $tasks );
			}
			else
			{
				$tasks = @shell_exec( "top -b -n 1" );
				$tasks = str_replace( " ", "&nbsp;", $tasks );
			}
		}
		else
		{
			$tasks	= '';
		}
		
		if( !$tasks )
		{
			$tasks = $this->lang->words['d_aunable'];
		}
		else
		{
			$tasks = "<pre>".$tasks."</pre>";
		}
		
		$data['tasks']	= $tasks;
		
		$this->registry->output->html .= $this->html->diagnosticsOverview( $data, $statsbox );
		
		$this->registry->output->html .= $this->html->acp_version_history_wrapper( $thiscontent );
	}
}