<?php
/**
 *
 * Plugin Name: ServerBuddy
 * Plugin URI: http://pluginbuddy.com/free-wordpress-plugins/serverbuddy/
 * Description: Tests server & hosting configuration to determine problems & compatibility with various WordPress themes and plugins. By PluginBuddy.
 * Version: 0.1.6
 * Author: Dustin Bolton
 * Author URI: http://dustinbolton.com
 *
 * Installation:
 * 
 * 1. Download and unzip the latest release zip file.
 * 2. If you use the WordPress plugin uploader to install this plugin skip to step 4.
 * 3. Upload the entire ServerBuddy directory to your `/wp-content/plugins/` directory.
 * 4. Activate the plugin through the 'Plugins' menu in WordPress Administration.
 * 
 * Usage:
 * 
 * 1. Navigate to the new ServerBuddy menu in the Wordpress Administration Panel.
  *
 */

 
if (!class_exists("iThemesServerBuddy")) {
    class iThemesServerBuddy {
		var $_version = '0.1.6';
	
		var $_url = 'http://pluginbuddy.com/free-wordpress-plugins/serverbuddy/';
		
		var $_php_versions_url = 'http://www.php.net/releases/index.php?serialize=1&max=9000'; // &version=5
		var $_var = 'ithemes-serverbuddy';
		var $_name = 'ServerBuddy';
		var $_timeformat = '%b %e, %Y, %l:%i%p';	// mysql time format
		var $_timestamp = 'M j, Y, g:iA';			// php timestamp format
		var $_usedInputs = array();
		var $_pluginPath = '';
		var $_pluginRelativePath = '';
		var $_pluginURL = '';
		var $_selfLink = '';
		var $_defaults = array(
		);
		var $_options = array();

		
		/**
		 * iThemesServerBuddy()
		 *
		 * Default Constructor
		 *
		 */
        function iThemesServerBuddy() {
			$this->_pluginPath = dirname( __FILE__ );
			$this->_pluginRelativePath = ltrim( str_replace( '\\', '/', str_replace( rtrim( ABSPATH, '\\\/' ), '', $this->_pluginPath ) ), '\\\/' );
			$this->_pluginURL = get_option( 'siteurl' ) . '/' . $this->_pluginRelativePath;
			$this->_selfLink = array_shift( explode( '?', $_SERVER['REQUEST_URI'] ) ) . '?page=' . $this->_var;
			
			// Admin.
			if ( is_admin() ) {
				add_action('admin_menu', array(&$this, 'admin_menu')); // Add menu in admin.
				add_action('wp_ajax_serverbuddy_ajax_mail_test', array(&$this, 'ajax_mail_test') );
			}
        }


		
		// PAGES //////////////////////////////

		/**
		 * iThemesServerBuddy::view_index()
		 *
		 * Displays default plugin page.
		 *
		 */		
		function view_index() {
			$this->load();
			$this->admin_scripts();
			
			wp_enqueue_style('dashboard');
			wp_print_styles('dashboard');
			wp_enqueue_script('dashboard');
			wp_print_scripts('dashboard');
			
			echo '<div class="wrap">';
			
			echo '<h2>'.$this->_name.'</h2>';
			
			$this->run_test();
			
			echo '</div>';
		}

		function admin_scripts() {
			// Load scripts and CSS used on this page.
			wp_enqueue_script( 'ithemes-tooltip-js', $this->_pluginURL . '/js/tooltip.js' );
			wp_print_scripts( 'ithemes-tooltip-js' );
			wp_enqueue_script( 'ithemes-'.$this->_var.'-admin-js', $this->_pluginURL . '/js/admin.js' );
			wp_print_scripts( 'ithemes-'.$this->_var.'-admin-js' );
			wp_enqueue_script( 'ithemes-swiftpopup-js', $this->_pluginURL . '/js/swiftpopup.js' );
			wp_print_scripts( 'ithemes-swiftpopup-js' );
			echo '<link rel="stylesheet" href="'.$this->_pluginURL . '/css/admin.css" type="text/css" media="all" />';
		}

		function view_wordpress() {
			$this->load();
			$this->admin_scripts();
			
			echo '<div class="wrap">';
			echo '<h2>'.$this->_name.' WordPress Information</h2>';
			
			echo '<textarea style="width: 100%; height: 400px;">';
			echo "ACTIVE PLUGINS -----------------------------\n\n";
			foreach ( (array) get_option( 'active_plugins' ) as $name => $val ) {
				echo $val . "\n";
			}
			echo "\nGENERAL SETTINGS -----------------------------\n\n";
			echo 'SiteURL: ' . get_option( 'siteurl' ) . "\n";
			echo 'BlogName: ' . get_option( 'blogname' ) . "\n";
			echo 'BlogDescription: ' . get_option( 'blogdescription' ) . "\n";
			echo 'Admin_Email: ' . get_option( 'admin_email' ) . "\n";
			echo 'Template: ' . get_option( 'template' ) . "\n";
			echo 'Stylesheet: ' . get_option( 'stylesheet' ) . "\n";
			echo 'Upload_Path: ' . get_option( 'upload_path' ) . "\n\n";

			echo "SECURITY RESULTS -----------------------------\n\n";
			echo $this->show_results('security', 'verbose'); // Verbose mode returns value so echo it.
			
			echo '</textarea>';
			
			
			echo '</div>';
		}
		
		function view_files() {
			$dir_array = array();
			$total_size = number_format( $this->dir_size( ABSPATH, ABSPATH, $dir_array ) / 1048576, 3);
			

			
			arsort( $dir_array );

			/*
			echo '<pre>';
			print_r( $dir_array );
			echo '</pre>';
			*/
			
			echo '<div class="wrap">';
			echo '<h2>'.$this->_name.' Directory Size Map</h2>';
			
			echo '<p><b>Total size of site:</b> ' . $total_size. 'MB</p>';
			
			?>
			<table class="widefat">
					<thead>
						<tr class="thead">
							<th>Directory</th>
							<th>Size with Children</th>
						</tr>
					</thead>
					<tfoot>
						<tr class="thead">
							<th>Directory</th>
							<th>Size with Children</th>
						</tr>
					</tfoot>
				<tbody>

			<?php
			foreach ( $dir_array as $id => $item ) {
				echo '<tr><td>' . $id . '/</td><td>' . number_format( $item, 3 ) . ' MB</td></tr>';
			}
			echo '</tbody>';
			echo '</table><br />';
			echo '<p><b>Total size of site:</b> ' . $total_size. 'MB</p>';
			echo '<br />';
			echo '</div>';
			
		}
		
		function dir_size( $dir, $base, &$dir_array ) {
			if( !$dir or !is_dir( $dir ) )
			{
				return 0;
			}

			$ret = 0;
			$sub = opendir( $dir );
			while( $file = readdir( $sub ) )
			{
				if( is_dir( $dir . '/' . $file ) && $file !== ".." && $file !== "." )
				{
					$this_size = $this->dir_size( $dir . '/' . $file, $base, $dir_array );
					
					//echo str_replace( $base, '', $dir . '/' . $file ) . ' = ' . ( $this_size / 1048576 ) . ' MB<br />';
					//array_push( $dir_array, array( str_replace( $base, '', $dir . '/' . $file ), ( $this_size / 1048576 ) ) );
					$dir_array[ str_replace( $base, '', $dir . '/' . $file ) ] = ( $this_size / 1048576 );
					
					$ret += $this_size;
					unset( $file );
				}
				elseif( !is_dir( $dir . '/' . $file ) )
				{
					$stats = stat( $dir . '/' . $file );
					$ret += $stats['size'];
					unset( $file );
				}
			}
			closedir( $sub );
			unset( $sub );
			return $ret;
		} 
			

		// TESTING //////////////////////////////
		
		function run_test() {
			$display_mode = $_POST['display_mode'];

				
			
			if ( !isset( $_POST['test_name'] ) ) {
				$test_name = 'general';
			} else {
				if ( $_POST['test_name'] != 'phpinfo' ) {
					$test_name = $_POST['test_name'];
					if ( !file_exists( dirname( __FILE__ ) . '/definitions/'.$test_name.'.txt' ) ) {
						$test_name = 'general';
					}
				}
			}

			// TODO: Check if latest version and compare dates
			// TODO: text if max_execution_time is changable.

			$test_list = array();
			$test_list[] = array( 'optgroup', 'Server & WordPress Testing' );
			$test_list[] = array( 'general', 'General Server Check' );
			$test_list[] = array( 'security', 'WordPress & Server Security' );
			$test_list[] = array( 'phpinfo', 'Display phpinfo Response' );
			$test_list[] = array( 'optgroup-end', '' );
			$test_list[] = array( 'optgroup', 'Plugin Compatibility Checks' );
			
			$fhandler = opendir( dirname( __FILE__ ) . '/definitions' );
			while ($file = readdir($fhandler)) {
				if ($file != '.' && $file != '..' && $file != 'general.txt' && $file != 'information.txt' && $file != 'security.txt') {
					$file = substr( $file, 0, -4 );
					$title = str_replace( '_', ' ', $file );
					$test_list[] = array( $file, $title );
				}
			}
			closedir($fhandler);

			?>

			<div class="postbox-container" style="width:70%;">
					<form method="post">
					
						<div style="float: left; margin-bottom: 3px;"><br />
								<select name="test_name">
									<?php
									foreach ( (array) $test_list as $item ) {
										if ( $item[0] == 'optgroup' ) {
											echo '<optgroup label="' . $item[1] . '">';
										} elseif ( $item[0] == 'optgroup-end' ) {
											echo '</optgroup>';
										} else {
											echo '<option value="'.$item[0].'"';
											if ( isset($_POST['test_name'])) {
												if ($_POST['test_name'] == $item[0]) { echo ' selected'; $this_test_title = $item[1]; }
											}
											echo '>'.$item[1].'</option>';
										}
									}
									echo '</optgroup>';
									if ( $this_test_title == '' ) {
										$this_test_title = $test_list[0][1];
									}
									?>
								</select>&nbsp;&nbsp;
								<?php
								if ( $display_mode == '' ) {
									$display_mode = 'table';
								}
								echo '<input type="radio" name="display_mode" id="display_mode_1" value="table"';
								if ( $display_mode == 'table' ) { echo 'checked'; }
								echo ' /><label for="display_mode_1">Detailed</label>&nbsp;&nbsp;';
								echo '<input type="radio" name="display_mode" id="display_mode_2" value="textbox"';
								if ( $display_mode != 'table' ) { echo 'checked'; }
								echo ' /><label for="display_mode_2">Text</label>&nbsp;&nbsp;';
								?>
								
								<input type="submit" name="submit" value="Run Test" class="button-primary" />
								
						</div>
					
						<input type="submit" href="ithemes-email_pop" id="email_pop_'.$file_i.'" class="ithemes_pop button-secondary" style="float: right; margin-top: 18px;" value="Email Report" />
					</form>
					
					<?php
					if ( isset( $_POST['test_name'] ) && ( $_POST['test_name'] == 'phpinfo' ) ) {
						echo '<p style="clear: both; text-align: center; font-weight: bold;">Displaying phpinfo() Response:</p>';
						phpinfo();
					} else {

						$this->show_results($test_name, $display_mode, $this_test_title);

						?>
						<div id="ithemes-email_pop" class="ithemes-popup" style="text-align: center;">
							<center><h3>Send Report by Email:</h3></center>
							<form method="post" id="email_form">
								<input type="hidden" name="report" value="<?php echo $test_name; ?>" id="ajax_mail_report" />
								
									<table><tr><td style="width: 150px; text-align: right;">
											Email Address:
										</td><td>
											<input type="text" name="ajax_mail_address" id="ajax_mail_address" style="width: 320px;" />
										</td></tr><tr><td colspan="2">&nbsp;</td></tr><tr><td style="width: 150px; text-align: right;" valign="top">
											Optional Message:
										</td><td>
											<textarea name="ajax_mail_message" id="ajax_mail_message" rows="4" style="width: 320px;">Below are the ServerBuddy test results for <?php echo get_option('siteurl'); ?> ...</textarea>
										</td></tr>
									</table>
								
								<p class="submit"><input value="Email Report" type="submit" name="email_report" id="ithemes_serverbuddy_ajax_mail_test" class="button-primary" alt="<?php echo admin_url('admin-ajax.php').'?action=serverbuddy_ajax_mail_test'; ?>" /></p>
								<span id="ithemes_serverbuddy_ajax_mail_testresponse"></span>
							</form>
						</div>
						<?php
						
					}
					?>

			</div>
			

			<div class="postbox-container" style="width:20%; margin-top: 35px; margin-left: 15px;">
				<div class="metabox-holder">	
					<div class="meta-box-sortables">
						
						<div id="breadcrumbslike" class="postbox">
							<div class="handlediv" title="Click to toggle"><br /></div>
							<h3 class="hndle"><span>Things to do...</span></h3>
							<div class="inside">
								<ul class="ithemes-serverbuddy-nodecor">
									<li>- <a href="http://twitter.com/home?status=<?php echo urlencode('Check out this awesome plugin! ' . $this->_url . ' @pluginbuddy'); ?>" title="Share on Twitter" onClick="window.open(jQuery(this).attr('href'),'ithemes_popup','toolbar=0,status=0,width=820,height=500,scrollbars=1'); return false;">Tweet about this plugin.</a></li>
									<li>- <a href="http://wordpress.org/extend/plugins/serverbuddy-by-pluginbuddy/">Rate this plugin on WordPress.org.</a></li>
									<li>- <a href="http://pluginbuddy.com/purchase/">Check out our other products.</a></li>
									<li>- <a href="http://secure.hostgator.com/cgi-bin/affiliates/clickthru.cgi?id=ithemes">Get HostGator web hosting.</a></li>
								</ul>
							</div>
						</div>

						<div id="breadcrumsnews" class="postbox">
							<div class="handlediv" title="Click to toggle"><br /></div>
							<h3 class="hndle"><span>Latest news from PluginBuddy</span></h3>
							<div class="inside">
								<p style="font-weight: bold;">PluginBuddy.com</p>
								<?php $this->get_feed( 'http://pluginbuddy.com/feed/', 5 );  ?>
								<p style="font-weight: bold;">Twitter @pluginbuddy</p>
								<?php
								$twit_append = '<li>&nbsp;</li>';
								$twit_append .= '<li><img src="'.$this->_pluginURL.'/images/twitter.png" style="vertical-align: -3px;" /> <a href="http://twitter.com/pluginbuddy/">Follow @pluginbuddy on Twitter.</a></li>';
								$twit_append .= '<li><img src="'.$this->_pluginURL.'/images/feed.png" style="vertical-align: -3px;" /> <a href="http://pluginbuddy.com/feed/">Subscribe to RSS news feed.</a></li>';
								$twit_append .= '<li><img src="'.$this->_pluginURL.'/images/email.png" style="vertical-align: -3px;" /> <a href="http://pluginbuddy.com/subscribe/">Subscribe to Email Newsletter.</a></li>';
								$this->get_feed( 'http://twitter.com/statuses/user_timeline/108700480.rss', 5, $twit_append, 'pluginbuddy: ' );
								?>
							</div>
						</div>
						
						<div id="breadcrumbssupport" class="postbox">
							<div class="handlediv" title="Click to toggle"><br /></div>
							<h3 class="hndle"><span>Need support?</span></h3>
							<div class="inside">
								<p>If you need any help with this plugin or run into any problems, please visit our <a href="http://pluginbuddy.com/support/">support forum</a>.</p>
							</div>
						</div>
						
					</div>
				</div>
			</div>
			<?php
		}

		function ajax_mail_test() {
			$to = $_POST['email'];
			$message_pre = $_POST['message'];
			
			$message = $this->show_results( $_POST['report'], 'verbose' );
			
			$headers = 'From: ServerBuddy <' . get_option('admin_email') . '>' . "\r\n";
			wp_mail($to, 'ServerBuddy Test Results', $message_pre . "\n\n" . $message, $headers);
			
			echo 'Success! Email Sent.';
			die();
		}
		
		// Modes: text, table, verbose (like text but no textarea)
		function show_results($test_name, $display_mode, $this_test_title = '') {
			if ( $test_name != 'phpinfo' ) {
				$info_file = explode("\n", file_get_contents( dirname( __FILE__ ) . '/definitions/information.txt' ) );
				//$info = split( ",", $info );
				foreach ( (array) $info_file as $item ) {
					$item = explode( ",", $item );
					$info[$item[0].','.$item[1]] = array( $item[2],$item[3]);
				}
				unset($info_file);
						
				$phpinfo = $this->phpinfo_array();
				// TODO: Check if curl is supported. If so, download PHP version data, else use built in copy
				// TODO: use major version number from current PHP version for the following version querystring parameter
				// TODO: Cache PHP.net response for a bit so it doesnt hit their server too much
				// TODO: check if zip command line function available
				$ch = curl_init($this->_php_versions_url . '&version=5');
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
				$response = curl_exec($ch);
				if(curl_errno($ch)) {
					curl_close($ch);
					// TODO: Unable to contact PHP.net so fall back to local PHP version information...
				} else {
					curl_close($ch);
					if ($response != '') {
						$php_versions = unserialize($response);
					}
				}
				// TODO: Get version url with same major version as current PHP version to get its date
				// TODO: http://www.php.net/releases/index.php?serialize=1&version=5&max=9000
				
				
				$test_file = explode("\n", file_get_contents( dirname( __FILE__ ) . '/definitions/'.$test_name.'.txt' ) );
				$test_file = explode("\n", file_get_contents( dirname( __FILE__ ) . '/definitions/'.$test_name.'.txt' ) );
				foreach( $test_file as $test_key => $test_line ) {
					if ( (substr($test_line, 0, 2) != '//') && ($test_line != '') ) {
						//$i++;
						
						$test = explode(",", $test_line);
						$test[3] = trim( $test[3] );

						if ( $test[1] == '' ) {
							$array_key = '$test[0]';
						} else {
							$array_key = '$test[0]][$test[1]';
						}

						$eval = '';
						$key1 = '';
						$key2 = '';
						$replace_text = '';
						$skip_parse = false;
						if ( array_key_exists( $test[0], $phpinfo ) ) {					
							$key1 = '$phpinfo['.$array_key.']'; // Key 1 is the test value.
						} else { // CUSTOM FUNCTION
							if ( $test[0] == 'class_exists' ) {
								$key1 = 'class_exists( \'' . $test[1] . '\' )';
							} elseif ( $test[0] == 'disabled_function' ) {
								$key1 = 'strpos( $phpinfo[\'PHP Core\'][\'disable_functions\'], $test[1])';
							} elseif ( $test[0] == 'php_release_date' ) {
								if ( $php_versions[phpversion()]['date'] == '' ) { // If blank then use source date.
									$php_versions[phpversion()]['date'] = $php_versions[phpversion()]['source'][0]['date'];
								}
								if ( strtotime($php_versions[phpversion()]['date']  . ' +' . $test[1]) > strtotime(date("Y-m-d")) ) {
									$key1 = 'true';
								} else {
									$key1 = 'false';
								}
								$key2 = '$php_versions[phpversion()][\'date\']';
								$test[1] = ''; // Clear for info text.
							} elseif ( $test[0] == 'php_build_date' ) {
								$key1 = '$phpinfo[\'PHP Configuration\'][\'Build Date\']';
							} elseif ( $test[0] == 'browser' ) {
								if ( isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], $test[1]) !== false) ) {
									$key1 = 'true';
								} else {
									$key1 = 'false';
								}
								$key2 = '$_SERVER[\'HTTP_USER_AGENT\']';
								$test[1] = ''; // Clear for info text.
							} elseif ( $test[0] == 'php_version' ) {
								$key1 = 'version_compare(PHP_VERSION,\''.$test[1].'\',\'>=\')';
								$key2 = 'PHP_VERSION';
								$test[1] = ''; // Clear for info text.
							} elseif ( $test[0] == 'mysql_version' ) {
								global $wpdb;
								$key1 = 'version_compare($wpdb->db_version(),\''.$test[1].'\',\'>=\')';
								$key2 = '$wpdb->get_var("SELECT VERSION() AS version")';
								$test[1] = ''; // Clear for info text.
							} elseif ( $test[0] == 'wp_version' ) {
								$key1 = 'version_compare(get_bloginfo("version"),\''.$test[1].'\',\'>=\')';
								$key2 = 'get_bloginfo("version")';
								$test[1] = ''; // Clear for info text.
							} elseif ( $test[0] == 'set_url' ) {
								$test_url = htmlentities( $test[1] );
								$skip_parse = true;
							} elseif ( $test[0] == 'memory_get_peak_usage' ) {
								if ( is_callable( 'memory_get_peak_usage' ) ) {
									$key1 = memory_get_peak_usage( $test[1] );
									$key2 = round( memory_get_peak_usage( $test[1] ) / 1048576, 2 );
								} else {
									$key1 = 'false';
									$key2 = '\'Unknown\'';
								}
							} elseif ( $test[0] == 'memory_get_usage' ) {
								$key1 = memory_get_usage( $test[1] );
								$key2 = round( memory_get_usage( $test[1] ) / 1048576, 2 );
							} elseif ( $test[0] == 'fileperms' ) {
								$key1 = substr( decoct( fileperms( ABSPATH . $test[1] ) ), 2 );
							} elseif ( $test[0] == 'user_exists' ) {
								global $wpdb;
								$user_exists = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login='" . $wpdb->escape( $test[1] ) . "'");
								if ( $user_exists == $wpdb->escape( $test[1] ) ){
									$key1 = 'true';
								} else {
									$key1 = 'false';
								}
								unset( $user_exists );
							} elseif ( $test[0] == 'is_readable' ) {
								$key1 = 'is_readable( ABSPATH . $test[1] )';
							} elseif ( $test[0] == 'file_exists' ) {
								$key1 = 'file_exists( ABSPATH . $test[1] )';
							} elseif ( $test[0] == 'is_callable' ) {
								$key1 = 'is_callable( \'' . $test[1] . '\' )';
							} elseif ( $test[0] == 'apache_module_loaded' ) {
								if ( function_exists( 'apache_get_modules' ) ) {
									$key1 = in_array(  $test[1], apache_get_modules() );
								} else {
									$key1 = 'false';
								}
							} else {
								//echo 'ERROR: UNKNOWN CUSTOM FUNCTION: ' . $test[0] . '<br />';
								$skip_parse = true;
							}
						}
						if ( $skip_parse != true ) {
							if ( $key2 == '' ) {
								$key2 = $key1; // Key 2 is the value displayed to user.
							}
								
							$eval .= '
							if ( '.$key1.' '.$test[2].' $test[3] ) { // GREEN COMPARE
								$results[] = array( ($test[0].",".$test[1]), '.$key2.', \'OK\', \'GREEN\' );
							';
							
							if ( isset( $test[4] ) ) { //If yellow condition available...
								$eval .= '
								} elseif ( '.$key1.' '.$test[4].' $test[5] ) { // YELLOW COMPARE IF SET
									$results[] = array( ($test[0].",".$test[1]), '.$key2.', \'WARNING\', \'YELLOW\' );
								';
							}

							$eval .= '
						} else {
							$results[] = array( ($test[0].",".$test[1]), '.$key2.', \'FAIL\', \'RED\' );
						}
						';
						
						eval($eval);

						
						if ( isset( $test[6] ) ) {
							$custom_info[$test[0].','.$test[1]][0] = $test[6];
						}
						if ( isset( $test[7] ) ) {
							$custom_info[$test[0].','.$test[1]][1] = $test[7];
						}
					}
				}
			}
		}
	
	
	

			
			if ( $display_mode == 'table' ) {
				?>
				<table class="widefat">
					<thead>
						<tr class="thead">
							<th></th>
							<th>Test Description</th>
							<th>Value</th>
							<th>Result</th>
							<th>Status</th>
						</tr>
					</thead>
					<tfoot>
						<tr class="thead">
							<th></th>
							<th>Test Description</th>
							<th>Value</th>
							<th>Result</th>
							<th>Status</th>
						</tr>
					</tfoot>
					<tbody>
				<?php
				
				foreach ( (array) $results as $item ) {
					echo '<tr><td><a class="ithemes_tip" title=" - ';
					
					
					
					if (isset($custom_info[$item[0]][1])) {
						echo $custom_info[$item[0]][1];
					} elseif (isset($info[$item[0]][1])) {
						echo $info[$item[0]][1];
					} else {
						echo '-INFORMATION NOT FOUND-';
					}
					
					echo '"><img src="'.$this->_pluginURL.'/images/information.png" /></a></td><td>';
					
					if (isset($custom_info[$item[0]][0])) {
						if ( isset( $results[$item[0]][5] ) ) {
							echo sprintf( $custom_info[$item[0]][0], $results[$item[0]][5] );
						} else {
							echo $custom_info[$item[0]][0];
						}
					} elseif (isset($info[$item[0]][0])) {
						if ( isset( $results[$item[0]][5] ) ) {
							echo sprintf( $info[$item[0]][0], $results[$item[0]][5] );
						} else {
							echo $info[$item[0]][0];
						}
					} else {
							echo '-TITLE NOT FOUND FOR "'.$item[0].'"-';
					}

					echo '</td><td>'.$item[1].'</td><td>'.$item[2].'</td><td>';
					if ($item[3] == 'GREEN') {
						echo '<div style="background-color: #22EE5B; border: 1px solid #E2E2E2;">&nbsp;&nbsp;&nbsp;</div>';
					} elseif ($item[3] == 'RED') {
						echo '<div style="background-color: #CF3333; border: 1px solid #E2E2E2;">&nbsp;&nbsp;&nbsp;</div>';
					} elseif ($item[3] == 'YELLOW') {
						echo '<div style="background-color: #FEFF7F; border: 1px solid #E2E2E2;">&nbsp;&nbsp;&nbsp;</div>';
					} else {
						echo $item[3];
					}
					echo '</td></tr>';
				}

				echo '	</tbody>';
				echo '</table><br />';
				
				if ( isset( $test_url ) ) {
					$this_test_title_linked = '<a href="' . $test_url . '" title="Visit this product\'s site. (external link)">' . $this_test_title . '</a>';
				} else {
					$this_test_title_linked = $this_test_title;
				}
				echo '<center>Completed running test "' . $this_test_title_linked . '".</center><br /><br />';
				
			} else { // NON TABLE MODE
				if ( $display_mode != 'verbose' ) {
					echo '<textarea style="width: 100%; height: 400px;">';
					echo 'ServerBuddy v' . $this->_version . ' results for test "' . $this_test_title . '" on ' . date($this->_timestamp) . ':';
					echo "\n\n";
				}
				$text_result = '';
				foreach ( (array) $results as $item ) {
					if (isset($info[$item[0]][0])) {
						$text_result .= $info[$item[0]][0];
					} else {
						if (isset($custom_info[$item[0]][0])) {
							$text_result .= $custom_info[$item[0]][0];
						} else {
							$text_result .= '-TITLE NOT FOUND FOR "'.$item[0].'"-';
						}
					}
					$text_result .= "\n";
					if ( $item[1] == '' ) { $text_result .= '-'; } else { $text_result .= $item[1]; }
					$text_result .= "\n";
					$text_result .= $item[2];
					$text_result .= "\n\n";
				}
				if ( $display_mode != 'verbose' ) { // Must be in text mode normal so just echo results...
					echo $text_result;
					echo '</textarea>';
				} else { // Return text if in verbose mode.
					return $text_result;
				}
			}
		}
		
		
		/**
		 *	get_feed()
		 *
		 *	Gets an RSS or other feed and inserts it as a list of links...
		 *
		 *	$feed		string		URL to the feed.
		 *	$limit		integer		Number of items to retrieve.
		 *	$append		string		HTML to include in the list. Should usually be <li> items including the <li> code.
		 *	$replace	string		String to replace in every title returned. ie twitter includes your own username at the beginning of each line.
		 */
		function get_feed( $feed, $limit, $append = '', $replace = '' ) {
			require_once(ABSPATH.WPINC.'/feed.php');  
			$rss = fetch_feed( $feed );
			if (!is_wp_error( $rss ) ) {
				$maxitems = $rss->get_item_quantity( $limit ); // Limit 
				$rss_items = $rss->get_items(0, $maxitems); 
				
				echo '<ul class="pluginbuddy-nodecor">';

				$feed_html = get_transient( md5( $feed ) );
				if ( $feed_html == '' ) {
					foreach ( (array) $rss_items as $item ) {
						$feed_html .= '<li>- <a href="' . $item->get_permalink() . '">';
						$title =  $item->get_title(); //, ENT_NOQUOTES, 'UTF-8');
						if ( $replace != '' ) {
							$title = str_replace( $replace, '', $title );
						}
						if ( strlen( $title ) < 30 ) {
							$feed_html .= $title;
						} else {
							$feed_html .= substr( $title, 0, 32 ) . ' ...';
						}
						$feed_html .= '</a></li>';
					}
					set_transient( md5( $feed ), $feed_html, 300 ); // expires in 300secs aka 5min
				}
				echo $feed_html;
				
				echo $append;
				echo '</ul>';
			} else {
				echo 'Temporarily unable to load feed...';
			}
		}
		
		
		function phpinfo_array() {
			ob_start();
			phpinfo(-1);

		
			$pi = preg_replace(
			array('#^.*<body>(.*)</body>.*$#ms', '#<h2>PHP License</h2>.*$#ms',
			'#<h1>Configuration</h1>#',  "#\r?\n#", "#</(h1|h2|h3|tr)>#", '# +<#',
			"#[ \t]+#", '#&nbsp;#', '#  +#', '# class=".*?"#', '%&#039;%',
			'#<tr>(?:.*?)" src="(?:.*?)=(.*?)" alt="PHP Logo" /></a>'
			.'<h1>PHP Version (.*?)</h1>(?:\n+?)</td></tr>#',
			'#<h1><a href="(?:.*?)\?=(.*?)">PHP Credits</a></h1>#',
			'#<tr>(?:.*?)" src="(?:.*?)=(.*?)"(?:.*?)Zend Engine (.*?),(?:.*?)</tr>#',
			"# +#", '#<tr>#', '#</tr>#'),
			array('$1', '', '', '', '</$1>' . "\n", '<', ' ', ' ', ' ', '', ' ',
			'<h2>PHP Configuration</h2>'."\n".'<tr><td>PHP Version</td><td>$2</td></tr>'.
			"\n".'<tr><td>PHP Egg</td><td>$1</td></tr>',
			'<tr><td>PHP Credits Egg</td><td>$1</td></tr>',
			'<tr><td>Zend Engine</td><td>$2</td></tr>' . "\n" .
			'<tr><td>Zend Egg</td><td>$1</td></tr>', ' ', '%S%', '%E%'),
			ob_get_clean());

			$sections = explode('<h2>', strip_tags($pi, '<h2><th><td>'));
			unset($sections[0]);

			$pi = array();
			foreach($sections as $section){
				$n = substr($section, 0, strpos($section, '</h2>'));
				preg_match_all( '#%S%(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?%E%#', $section, $askapache, PREG_SET_ORDER);
				foreach($askapache as $m) {
					if (isset($m[2])) { // Fix undefined offset warning.
						$pi[$n][$m[1]]=(!isset($m[3])||$m[2]==$m[3])?$m[2]:array_slice($m,2);
					}
				}
			}

			return $pi;
		}



		
		// OPTIONS STORAGE //////////////////////

		
		function save() {
			add_option($this->_var, $this->_options, '', 'no'); // 'No' prevents autoload if we wont always need the data loaded.
			update_option($this->_var, $this->_options);
			return true;
		}
		
		
		function load() {
			$this->_options=get_option($this->_var);
			if ( empty( $this->_options ) ) { // No options set so use defaults.
				$this->_options = $this->_defaults;
				$this->save();
			}
			return true;
		}
		
		
		// ADMIN MENU FUNCTIONS /////////////////

		
		/** admin_menu()
		 *
		 * Initialize menu for admin section.
		 *
		 */		
		function admin_menu() {
			// Add main menu (default when clicking top of menu)
			add_menu_page($this->_name.' Analysis', $this->_name, 'administrator', $this->_var, array(&$this, 'view_index'), $this->_pluginURL.'/images/pluginbuddy.png');
			// Add sub-menu items (first should match default page above)
			add_submenu_page( $this->_var, $this->_name.' Analysis', 'Server Analysis', 'administrator', $this->_var, array(&$this, 'view_index'));
			//add_submenu_page( $this->_var, $this->_name.' Reports', 'Reports', 'administrator', $this->_var.'-reports', array(&$this, 'view_reports'));
			//add_submenu_page( $this->_var, $this->_name.' Settings', 'Settings', 'administrator', $this->_var.'-settings', array(&$this, 'view_settings'));
			//add_submenu_page( $this->_var, $this->_name.' Information', 'Information', 'administrator', $this->_var.'-information', array(&$this, 'view_information'));
			add_submenu_page( $this->_var, $this->_name.' WordPress', 'WordPress Info.', 'administrator', $this->_var.'-wordpress', array(&$this, 'view_wordpress'));
			add_submenu_page( $this->_var, $this->_name.' Directory Size Map', 'Directory Size Map', 'administrator', $this->_var.'-files', array(&$this, 'view_files'));
			
		}


		
		
		
		
		
		
		
		
		
		
		
		
		
		/////////////////////////////////////////////
		// CHRIS' FORM CREATION FUNCTIONS: //////////
		/////////////////////////////////////////////
		
		function _newForm() {
			$this->_usedInputs = array();
		}
		
		function _addSubmit( $var, $options = array(), $override_value = true ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'submit';
			$options['name'] = $var;
			$options['class'] = ( empty( $options['class'] ) ) ? 'button-primary' : $options['class'];
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addButton( $var, $options = array(), $override_value = true ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'button';
			$options['name'] = $var;
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addTextBox( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'text';
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addTextArea( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'textarea';
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addFileUpload( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'file';
			$options['name'] = $var;
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addCheckBox( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'checkbox';
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addMultiCheckBox( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'checkbox';
			$var = $var . '[]';
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addRadio( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'radio';
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addDropDown( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array();
			else if ( ! isset( $options['value'] ) || ! is_array( $options['value'] ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'dropdown';
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addHidden( $var, $options = array(), $override_value = false ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['type'] = 'hidden';
			$this->_addSimpleInput( $var, $options, $override_value );
		}
		
		function _addHiddenNoSave( $var, $options = array(), $override_value = true ) {
			if ( ! is_array( $options ) )
				$options = array( 'value' => $options );
			
			$options['name'] = $var;
			$this->_addHidden( $var, $options, $override_value );
		}
		
		function _addDefaultHidden( $var ) {
			$options = array();
			$options['value'] = $this->defaults[$var];
			
			$var = "default_option_$var";
			$this->_addHiddenNoSave( $var, $options );
		}
		
		function _addUsedInputs() {
			$options['type'] = 'hidden';
			$options['value'] = implode( ',', $this->_usedInputs );
			$options['name'] = 'used-inputs';
			$this->_addSimpleInput( 'used-inputs', $options, true );
		}
		
		function _addSimpleInput( $var, $options = false, $override_value = false ) {
			if ( empty( $options['type'] ) ) {
				echo "<!-- _addSimpleInput called without a type option set. -->\n";
				return false;
			}

			$scrublist['textarea']['value'] = true;
			$scrublist['file']['value'] = true;
			$scrublist['dropdown']['value'] = true;
			$defaults = array();
			$defaults['name'] = $this->_var . '-' . $var;
			$var = str_replace( '[]', '', $var );
			
			if ( 'checkbox' === $options['type'] )
				$defaults['class'] = $var;
			else
				$defaults['id'] = $var;
			
			$options = $this->_merge_defaults( $options, $defaults );
			
			if ( ( false === $override_value ) && isset( $this->_options[$var] ) ) {
				if ( 'checkbox' === $options['type'] ) {
					if ( $this->_options[$var] == $options['value'] )
						$options['checked'] = 'checked';
				}
				elseif ( 'dropdown' !== $options['type'] )
					$options['value'] = $this->_options[$var];
			}
			
			if ( ( preg_match( '/^' . $this->_var . '/', $options['name'] ) ) && ( ! in_array( $options['name'], $this->_usedInputs ) ) )
				$this->_usedInputs[] = $options['name'];
			
			$attributes = '';
			
			if ( false !== $options )
				foreach ( (array) $options as $name => $val )
					if ( ! is_array( $val ) && ( ! isset( $scrublist[$options['type']][$name] ) || ( true !== $scrublist[$options['type']][$name] ) ) )
						if ( ( 'submit' === $options['type'] ) || ( 'button' === $options['type'] ) )
							$attributes .= "$name=\"$val\" ";
						else
							$attributes .= "$name=\"" . htmlspecialchars( $val ) . '" ';
			
			if ( 'textarea' === $options['type'] )
				echo '<textarea ' . $attributes . '>' . $options['value'] . '</textarea>';
			elseif ( 'dropdown' === $options['type'] ) {
				echo "<select ".$class." $attributes>\n";
				foreach ( (array) $options['value'] as $val => $name ) {
				
					$selected = ( $this->_options[$var] == $val ) ? ' selected="selected"' : '';
					echo "<option value=\"$val\"$selected>$name</option>\n";
				}
				
				echo "</select>\n";
			}
			else
				echo '<input ' . $attributes . '/>';
		}
		
		function _merge_defaults( $values, $defaults, $force = false ) {
			if ( ! $this->_is_associative_array( $defaults ) ) {
				if ( ! isset( $values ) ) {
					return $defaults;
				}
				if ( false === $force ) {
					return $values;
				}
				if ( isset( $values ) || is_array( $values ) )
					return $values;
				return $defaults;
			}
			
			foreach ( (array) $defaults as $key => $val ) {
				if ( ! isset( $values[$key] ) ) {
					$values[$key] = null;
				}
				$values[$key] = $this->_merge_defaults($values[$key], $val, $force );
			}
			return $values;
		}
		
		function _is_associative_array( &$array ) {
			if ( ! is_array( $array ) || empty( $array ) ) {
				return false;
			}
			$next = 0;
			foreach ( $array as $k => $v ) {
				if ( $k !== $next++ ) {
					return true;
				}
			}
			return false;
		}
		
		// PUBLIC DISPLAY OF MESSAGES ////////////////////////
		
		function _showStatusMessage( $message ) {
			echo '<div id="message" class="updated fade"><p><strong>'.$message.'</strong></p></div>';			
		}
		function _showErrorMessage( $message ) {
			echo '<div id="message" class="error"><p><strong>'.$message.'</strong></p></div>';
		}
		
		// SORTING FUNCTION(S) //////////////////////////////////
		
		function _sortGroupsByName( $a, $b ) {
			if ( $this->_options['groups'][$a]['name'] < $this->_options['groups'][$b]['name'] )
				return -1;
			
			return 1;
		}

		
		/////////////////////////////////////////////
		// END CHRIS' FUNCTIONS /////////////////////
		/////////////////////////////////////////////
		
		
    } // End class

	$iThemesServerBuddy = new iThemesServerBuddy(); // Create instance
}