<?php
// @since 7.0.3.12
// @author Dustin Bolton

/*
$recent_send_fails = array(
	'file' => '',
	'log_tail' => '',
	'error' => '',
);
*/




// backupbuddy_live_troubleshooting::run();
// $results = backupbuddy_live_troubleshooting::get_raw_results();


class backupbuddy_live_troubleshooting {
	
	const WARN_IF_LAST_SNAPSHOT_AGO_EXCEEDS_SECONDS_PAST_INTERVAL = 604800; // Warns if time since last snapshot exceeds twice the expected interval or _7_ days past the expected interval.
	private static $_finished = false;
	
	private static $_settings = array(
		'max_notifications' => 10,								// Max number of most recent sync notifications to return.
		'status_log_recent_lines' => 75,						// Max number of most recent lines to get from status log.
		'extraneous_log_recent_lines' => 30,					// Max number of most recent lines to get from extraneous overall status log.
		'send_fail_status_log_recent_lines' => 20,				// Max number of most recent lines to get from a REMOTE TRANSFER status log for Stash Live sends that FAILED.
	);
	
	
	private static $_results = array(
		'bb_version' => '',
		'wp_version' => '',
		'site_url' => '',
		'home_url' => '',
		'start_troubleshooting' => 0,
		'finish_troubleshooting' => 0,
		'gmt_offset' => 0,
		'current_time' => 0,
		'localized_time' => 0,
		'current_timestamp' => 0,
		
		'alerts' => array(),
		'highlights' => array(),
		'memory' => array(
			'estimated_base_usage' => 0,
			'estimated_catalog_usage' => 0,							// Estimate of max free memory that will be needed. In MB.
			'estimated_total_needed' => 0,
			'memory_tested' => 0,
			'memory_tested_hours_ago' => -1,
			'memory_reported_local' => 0,
			'memory_reported_master' => 0,
			'memory_max_usage_logged' => 0,
			'memory_status' => 'OK',
		),
		'php_notices' => array(),								// Any PHP errors, warnings, notices found in any of the log searched.
		'file_info' => array(),									// File sizes, mtime, etc of various logs.
		'bb_notices' => array(),								// Any BackupBuddy errors or warnings logged.
		'recent_waiting_on_files' => array(),					// Recent list of files waiting on as per $files_pending_send_file file contents.
		'recent_waiting_on_files_time' => 0,					// File modified time.
		'recent_waiting_on_files_time_ago' => 0,				// File modified time.
		'recent_waiting_on_tables' => array(),					
		'recent_waiting_on_tables_time' => 0,					// File modified time.
		'recent_waiting_on_tables_time_ago' => 0,				// File modified time.
		'recent_live_send_fails' => array(),					// Remote destination send failures to Live.
		'recent_sync_notifications' => array(),					// Sync Notification errors (live_error).
		'live_status_log_tail' => '',							// Recent Stash Live Status Log.
		'live_stats' => array(),
		'server_stats' => array(),
		'crons' => array(),										// Listing of crons for troubleshooting.
		'extraneous_log_tail' => '',							// Tail end of extraneous log file.
	);
	
	
	
	public static function run() {
		self::$_results['start_troubleshooting'] = microtime( true );
		self::$_results['gmt_offset'] = get_option( 'gmt_offset' );
		self::$_results['current_time'] = pb_backupbuddy::$format->date( time() );
		self::$_results['localized_time'] = pb_backupbuddy::$format->date( pb_backupbuddy::$format->localize_time( time() ) );
		self::$_results['current_timestamp'] = time();
		
		// Recent send fails (remote destination failures).
		// HIGHLIGHTS: PHP errors, send errors, NUMBER of sends failed in X hours
		
		// Populates tail of status log and looks for PHP and BB notices.
		self::_test_site_home_url();
		self::_test_versions();
		self::_test_file_info();
		self::_test_status_log();
		self::_test_recent_sync_notifications();
		self::_test_live_state();
		self::_test_server_stats();
		self::_test_memory();
		self::_test_cron_scheduled();
		self::_test_recent_live_send_fails();
		self::_test_extraneous_log();
		self::_recent_waiting_on_files_tables();
		self::_record_alerts();
		self::_test_php_runtime();
		self::_test_godaddy_managed_wp();
		self::_test_last_snapshot();
		
		self::$_results['finish_troubleshooting'] = microtime( true );
		self::$_finished = true;
		
	} // End run().
	
	
	
	public static function _test_site_home_url() {
		self::$_results['site_url'] = site_url();
		self::$_results['home_url'] = home_url();
	}
	
	
	public static function _test_last_snapshot() {
		// Get WP schedules.
		$schedule_intervals = wp_get_schedules();
		$destination = backupbuddy_live_periodic::get_destination_settings();
		if ( ! isset( $schedule_intervals[ $destination['remote_snapshot_period'] ] ) ) {
			$error = 'Error #38939833. Invalid snapshot period. Check snapshot interval settings and re-save for contact support.';
			self::$_results['highlights'][] = $error;
			self::$_results['alerts'][] = $error;
			return false;
		}
		$interval = $schedule_intervals[ $destination['remote_snapshot_period'] ]['interval'];
		$interval_display = $schedule_intervals[ $destination['remote_snapshot_period'] ]['display'];
		$time_passed = ( time() - self::$_results['live_stats']['last_remote_snapshot'] );
		
		if ( ( $time_passed > 2*$interval ) || ( $time_passed > $interval+self::WARN_IF_LAST_SNAPSHOT_AGO_EXCEEDS_SECONDS_PAST_INTERVAL ) ) { // If twice the interval is passed or 7 days past the expected interval.
			
			$last_id = self::$_results['live_stats']['last_remote_snapshot_id'];
			$additionalParams = array(
				'snapshot' => $last_id,
			);
			$response = pb_backupbuddy_destination_live::stashAPI( $destination, 'live-snapshot-status', $additionalParams, true, false, 5 ); // 5 sec timeout to not halt troubleshooting
			if ( ! is_array( $response ) ) {
				$response = 'Error #3489349844: Unable to get last snapshot details for ID `' . $last_id . '`.';
			} else {
				if ( isset( $response['snapshot'] ) ) {
					$response['snapshot'] = '**truncated due to size; if needed, see "Last Snapshot Details" button under Advanced Troubleshooting Options section**';
				}
				$response = print_r( $response, true );
			}
			
			$days_since = round( ( time() - self::$_results['live_stats']['last_remote_snapshot'] ) / 60 / 60 / 24, 2 );
			$error = 'It has been `' . $days_since . '` days since the last snapshot. Current interval name: `' . $interval_display . '`. Current interval value: `' . $interval . '`. Last snapshot details (just now checked): `' . $response . '`. Last snapshot response (from last snapshot requested): `' . print_r( self::$_results['live_stats']['last_remote_snapshot_response'], true ) . '`.';
			self::$_results['highlights'][] = $error;
			self::$_results['alerts'][] = $error;
		}
	}
	
	
	public static function _test_versions() {
		global $wp_version;
		self::$_results['bb_version'] = pb_backupbuddy::settings( 'version' );
		self::$_results['wp_version'] = $wp_version;
	}
	
	
	
	public static function _test_php_runtime() {
		if ( backupbuddy_core::detectMaxExecutionTime() < 28 ) {
			$error = 'Detected maximum PHP execution time below 30 seconds. Contact host to increase to at least 30 seconds. Detected: `' . backupbuddy_core::detectMaxExecutionTime() . '` seconds.';
			self::$_results['highlights'][] = $error;
			self::$_results['alerts'][] = $error;
		}
	}
	
	
	public static function _test_godaddy_managed_wp() {
		if ( defined( 'GD_SYSTEM_PLUGIN_DIR' ) || class_exists( '\\WPaaS\\Plugin' ) ) {
			self::$_results['alerts'][] = 'GoDaddy Managed WordPress Hosting detected. This hosting has had known problems with the WordPress cron in the past. This may be resolved at this time.';
		}
	}
	
	
	
	// NOTE: run BEFORE _test_memory().
	public static function _test_file_info() {
		$catalog_file = backupbuddy_core::getLogDirectory() . 'live/catalog-' . pb_backupbuddy::$options['log_serial'] . '.txt';
		$state_file = backupbuddy_core::getLogDirectory() . 'live/state-' . pb_backupbuddy::$options['log_serial'] . '.txt';
		
		if ( false !== ( $catalog_size = @filesize( $catalog_file ) ) ) {
			self::$_results['memory']['estimated_catalog_usage'] = round( ( $catalog_size / 1024 / 1024 ) * 10, 2 );
		}
		
		$log_files = array(
			'files_pending_log' => backupbuddy_core::getLogDirectory() . 'live/files_pending_send-' . pb_backupbuddy::$options['log_serial'] . '.txt',
			'tables_pending_log' => backupbuddy_core::getLogDirectory() . 'live/tables_pending_send-' . pb_backupbuddy::$options['log_serial'] . '.txt',
			'extraneous_log' => backupbuddy_core::getLogDirectory() . 'log-' . pb_backupbuddy::$options['log_serial'] . '.txt',
			'live_log' => backupbuddy_core::getLogDirectory() . 'status-live_periodic_' . pb_backupbuddy::$options['log_serial'] . '.txt',
			'catalog_file' => $catalog_file,
			'state_file' => $state_file,
		);
		
		foreach( $log_files as $title => $log_file ) {
			if ( ! file_exists( $log_file ) ) {
				self::$_results['file_info'][ $title ] = '[does not exist]';
				continue;
			}
			
			$mtime = @filemtime( $log_file );
			
			self::$_results['file_info'][ $title ] = array(
				'size' => pb_backupbuddy::$format->file_size( @filesize( $log_file ) ),
				'modified' => $mtime,
				'modified_pretty' => pb_backupbuddy::$format->date( $mtime ),
				'modified_ago' => pb_backupbuddy::$format->time_ago( $mtime ),
			);
		}
	} // End _test_log_file_sizes().
	
	
	
	// NOTE: run AFTER _test_file_info().
	public static function _test_memory() {
		
		self::$_results['memory']['estimated_base_usage'] = round( memory_get_usage() / 1048576, 2 );
		if ( self::$_results['memory']['estimated_catalog_usage'] > 0 ) {
			self::$_results['memory']['estimated_total_needed'] = self::$_results['memory']['estimated_base_usage'] + self::$_results['memory']['estimated_catalog_usage'];
			self::$_results['memory']['estimated_total_needed'] += ( self::$_results['memory']['estimated_total_needed'] * .15 ); // 15% wiggle room.
			self::$_results['memory']['estimated_total_needed'] = round( self::$_results['memory']['estimated_total_needed'], 2 );
		}
		
		// These globals populated by _server_tests.php.
		global $bb_local_mem, $bb_master_mem, $bb_tested_mem, $bb_tested_mem_ago;
		self::$_results['memory']['memory_reported_local'] = $bb_local_mem;
		self::$_results['memory']['memory_reported_master'] = $bb_master_mem;
		self::$_results['memory']['memory_tested'] = $bb_tested_mem;
		self::$_results['memory']['memory_tested_hours_ago'] = round( $bb_tested_mem_ago / 60 / 60, 2 );
		
		// Use tested value above others.
		if ( self::$_results['memory']['memory_tested'] > 0 ) {
			if ( self::$_results['memory']['estimated_total_needed'] > self::$_results['memory']['memory_tested'] ) {
				self::$_results['memory']['memory_status'] = 'ERROR! Not enough memory. Increase PHP memory limits! `' . self::$_results['memory']['memory_tested'] . 'MB` tested available but `' . self::$_results['memory']['estimated_total_needed'] . 'MB` estimated required.';
				self::$_results['highlights'][] = self::$_results['memory']['memory_status'];
				self::$_results['alerts'][] = self::$_results['memory']['memory_status'] . ' Please contact your host to assist in correcting this issue.';
			} else { // Probably okay but just warn if reported values are below tested.
				
				// TODO: This may be over-sensitive and not needed. In the future possibly remove. Likely too many false hits/warns.
				if ( ( self::$_results['memory']['memory_reported_local'] < self::$_results['memory']['memory_tested'] ) || ( self::$_results['memory']['memory_reported_master'] < self::$_results['memory']['memory_tested'] ) ) {
					self::$_results['memory']['memory_status'] = 'OK';
					// Highlight only.
					self::$_results['highlights'][] = 'OK. Note: Reported PHP memory value(s) below tested value. Re-test PHP memory to verify it is up to date. If up to date then IGNORE this note. Tested: `' . self::$_results['memory']['memory_tested'] . 'MB`, Reported Local: `' . self::$_results['memory']['memory_reported_local'] . 'MB`, Reported Master: `' . self::$_results['memory']['memory_reported_master'] . 'MB`. Estimated needed: `' . self::$_results['memory']['estimated_total_needed'] . 'MB`. Memory tested: `' . pb_backupbuddy::$format->time_ago( time() + $bb_tested_mem_ago ) . '` ago.';
				}
			}
			
			$most_likely_memory = self::$_results['memory']['memory_tested'];
		} else {
			$lowest_memory = self::$_results['memory']['memory_reported_local'];
			$lowest = 'local';
			
			if ( self::$_results['memory']['memory_reported_master'] < self::$_results['memory']['memory_reported_local'] ) {
				$lowest_memory = self::$_results['memory']['memory_reported_master'];
				$lowest = 'master';
			}
			
			if ( self::$_results['memory']['memory_reported_master'] == self::$_results['memory']['memory_reported_local'] ) {
				$lowest = 'equal';
			}
			
			if ( $lowest_memory < self::$_results['memory']['estimated_total_needed'] ) {
				if ( 'equal' == $lowest ) { // Definitely not enough.
					self::$_results['memory']['memory_status'] = 'ERROR! Not enough memory. Increase PHP memory limits for local & master values! `' . $lowest_memory . 'MB` reported available but `' . self::$_results['memory']['estimated_total_needed'] . 'MB` estimated required.';
					self::$_results['highlights'][] = self::$_results['memory']['memory_status'];
					self::$_results['alerts'][] = self::$_results['memory']['memory_status'] . ' Please contact your host to assist in correcting this issue.';
				} else { // One or the other may be overriding. Warn.
					self::$_results['memory']['memory_status'] = 'WARNING! Possibly not enough memory. Increase PHP memory limits for `' . $lowest . '` value! Master or local values can override one another. `' . $lowest_memory . 'MB` reported available for `' . $lowest . '` value but `' . self::$_results['memory']['estimated_total_needed'] . 'MB` estimated required.';
					self::$_results['highlights'][] = self::$_results['memory']['memory_status'];
				}
			}
			
			$most_likely_memory = $lowest_memory;
		}
		
		if ( ( self::$_results['memory']['memory_max_usage_logged'] + ( self::$_results['memory']['memory_max_usage_logged'] * .20 ) ) > $most_likely_memory ) {
			self::$_results['highlights'][] = 'WARNING: Max memory usage detected in log file(s) is getting close to tested limit. Max seen: `' . self::$_results['memory']['memory_max_usage_logged'] . 'MB`, max tested available: `' . self::$_results['memory']['memory_tested'] . 'MB`.';
		}
		
	} // End _test_memory().
	
	
	
	public static function get_raw_results() {
		if ( false === self::$_finished ) {
			return false;
		}
		return self::$_results;
	}
	
	
	
	public static function get_html_results() {
		if ( false === self::$_finished ) {
			return false;
		}
		echo 'TODO #483948434';
	}
	
	
	
	private static function _recent_waiting_on_files_tables() {
		$files_pending_send_file = backupbuddy_core::getLogDirectory() . 'live/files_pending_send-' . pb_backupbuddy::$options['log_serial'] . '.txt';
		$tables_pending_send_file = backupbuddy_core::getLogDirectory() . 'live/tables_pending_send-' . pb_backupbuddy::$options['log_serial'] . '.txt';
		
		if ( file_exists( $files_pending_send_file ) ) {
			if ( false !== ( $files_pending_send = @file_get_contents( $files_pending_send_file ) ) ) {
				self::$_results['recent_waiting_on_files'] = explode( "\n", $files_pending_send );
				self::$_results['recent_waiting_on_files_time'] = @filemtime( $files_pending_send_file );
				self::$_results['recent_waiting_on_files_time_ago'] = pb_backupbuddy::$format->time_ago( self::$_results['recent_waiting_on_files_time'] ) . ' ' . __( 'ago', 'it-l10n-backupbuddy' );
				if ( count( self::$_results['recent_waiting_on_files'] ) > 0 ) {
					self::$_results['highlights'][] = '`' . count( self::$_results['recent_waiting_on_files'] ) . '` total files recently needed waiting on.';
				}
			}
		}
		if ( file_exists( $tables_pending_send_file ) ) {
			if ( false !== ( $tables_pending_send = @file_get_contents( $tables_pending_send_file ) ) ) {
				self::$_results['recent_waiting_on_tables'] = explode( "\n", $tables_pending_send );
				self::$_results['recent_waiting_on_tables_time'] = @filemtime( $tables_pending_send_file );
				self::$_results['recent_waiting_on_tables_time_ago'] = pb_backupbuddy::$format->time_ago( self::$_results['recent_waiting_on_tables_time'] ) . ' ' . __( 'ago', 'it-l10n-backupbuddy' );
				if ( count( self::$_results['recent_waiting_on_tables'] ) > 0 ) {
					self::$_results['highlights'][] = '`' . count( self::$_results['recent_waiting_on_tables'] ) . '` total tables recently needed waiting on.';
				}
			}
		}
	}
	
	private static function _test_extraneous_log() {
		$status_log_file = backupbuddy_core::getLogDirectory() . 'log-' . pb_backupbuddy::$options['log_serial'] . '.txt';
		$status_log_file_contents = file_get_contents( $status_log_file );
		self::_find_notices( $status_log_file_contents, $status_log_file );
		
		// Get tail of status log.
		if ( file_exists( $status_log_file ) ) {
			self::$_results['extraneous_log_tail'] = backupbuddy_core::read_backward_line( $status_log_file, self::$_settings['extraneous_log_recent_lines'] );
		} else {
			self::$_results['extraneous_log_tail'] = '**Log file `' . $status_log_file . '` not found.**';
		}
	}
	
	private static function _test_status_log() {
		$status_log_file = backupbuddy_core::getLogDirectory() . 'status-live_periodic_' . pb_backupbuddy::$options['log_serial'] . '.txt';
		$status_log_file_contents = file_get_contents( $status_log_file );
		self::_find_notices( $status_log_file_contents, $status_log_file );
		
		// Get tail of status log.
		if ( file_exists( $status_log_file ) ) {
			self::$_results['live_status_log_tail'] = backupbuddy_core::read_backward_line( $status_log_file, self::$_settings['status_log_recent_lines'] );
		} else {
			self::$_results['extraneous_log_tail'] = '**Log file `' . $status_log_file . '` not found.**';
		}
	}
	
	
	
	private static function _test_recent_sync_notifications() {
		$notifications = backupbuddy_core::getNotifications();
		
		// Remove non-Stash Live notifications.
		foreach( $notifications as $key => $notification ) {
			if ( 'live_error' != $notification['slug'] ) {
				unset( $notifications[ $key ] );
				continue;
			}
		}
		
		if ( count( $notifications ) > 0 ) {
			self::$_results['highlights'][] = '`' . count( $notifications ) . '` recent Stash Live Sync error notifications.';
		}
		
		// Limit to X number of most recent notifications.
		self::$_results['recent_sync_notifications'] = array_slice( $notifications, -1 * ( self::$_settings['max_notifications'] ), self::$_settings['max_notifications'], $preserve_key = false );
		
	}
	
	
	
	private static function _test_live_state() {
		self::$_results['live_stats'] = backupbuddy_api::getLiveStats();
	}
	
	
	
	private static function _test_server_stats() {
		require( pb_backupbuddy::plugin_path() . '/controllers/pages/server_info/_server_tests.php' ); // Populates $tests.
		self::$_results['server_stats'] = $tests;
		foreach( self::$_results['server_stats'] as &$stat ) {
			$stat = self::_strip_tags_content( $stat );
			if ( ( 'FAIL' == $stat['status'] ) || ( 'WARNING' == $stat['status'] ) ) {
				self::$_results['highlights'][] = $stat;
			}
		}
	}
	
	
	
	private static function _test_cron_scheduled() {
		$cron_warnings = array();
		require( pb_backupbuddy::plugin_path() . '/controllers/pages/server_info/_cron.php' );
		self::$_results['crons'] = self::_strip_tags_content( $crons );
		if ( count( $cron_warnings ) > 0 ) {
			self::$_results['highlights'][] = count( $cron_warnings ) . ' cron(s) warnings were found (such as past due; see cron section for details): ' . implode( '; ', array_unique( $cron_warnings ) );
		}
	}
	
	
	
	private static function _test_recent_live_send_fails() {
		$troubleshooting = true; // Tell _remote_sends.php to run in troubleshooting/text mode.
		require( pb_backupbuddy::plugin_path() . '/controllers/pages/server_info/_remote_sends.php' ); // Populates $sends.
		self::$_results['recent_live_send_fails'] = $sends;
		foreach( self::$_results['recent_live_send_fails'] as $key => &$send ) {
			
			// Only include Live sends.
			if ( 'live' != $send['type'] ) {
				unset( self::$_results['recent_live_send_fails'][ $key ] );
				continue;
			}
			
			// Only include FAILED sends.
			if ( true !== $send['failed'] ) {
				unset( self::$_results['recent_live_send_fails'][ $key ] );
				continue;
			}
			
			// If error message, set as highlight.
			if ( '' != $send['error'] ) {
				self::$_results['highlights'][] = array(
					'error' => 'File send Error #4389844959:' . $send['error'],
					'send_details' => $send
				);
			}
			
			if ( file_exists( $send['log_file'] ) ) {
				$send['log_tail'] = backupbuddy_core::read_backward_line( $send['log_file'], self::$_settings['send_fail_status_log_recent_lines'] );
			} else {
				self::$_results['extraneous_log_tail'] = '**Log file `' . $send['log_file'] . '` not found.**';
			}
		}
		
		if ( count( self::$_results['recent_live_send_fails'] ) > 0 ) {
			self::$_results['highlights'][] = count( self::$_results['recent_live_send_fails'] ) . ' total files pending send before Snapshot can be made.';
		}
	}
	
	
	
	/* _find_notices()
	 *
	 * Finds any PHP errors, warnings, notices + BackupBuddy errors and warnings in a log file.
	 *
	 * @param	string	$log	Newline-deliminated log file.
	 *
	 */
	private static function _find_notices( $log, $log_file ) {
		$php_notices = array();
		$bb_notices = array();
		
		$newProcessStarting = false;
		$prevLine = '';
		$lastMem = 0;
		$recordNextLines = 0;
		$maxMem = 0;
		
		$separator = "\r\n";
		$line = strtok( $log, $separator ); // Attribution: http://stackoverflow.com/questions/1462720/iterate-over-each-line-in-a-string-in-php
		while ($line !== false) {
			# do something with $line
			$line = strtok( $separator );
			
			if ( $recordNextLines > 0 ) {
				$php_notices[] = $line;
				$recordNextLines--;
			}
			
			if ( true === $newProcessStarting ) {
				if ( false !== stripos( $line, 'possible_timeout' ) ) {
					self::$_results['highlights'][] = 'Possible timeout or memory ceiling (peak before new process: `' . $lastMem . '`) detected in `' . $log_file . '`. Pre-timeout line: `' . $preTimeoutLine . '`. Post-timeout line: `' . $prevLine . '`.';
					$newProcessStarting = false;
				}
			}
			
			if ( false !== strpos( $line, '"-----"' ) ) {
				$newProcessStarting = true;
				// Get memory value from previous line.
				if ( null != ( $line_array = json_decode( trim( $prevLine ), $assoc = true ) ) ) {
					if ( isset( $line_array[ 'mem' ] ) ) {
						$lastMem = $line_array[ 'mem' ];
						if ( $lastMem > $maxMem ) {
							$maxMem = $lastMem;
						}
						$preTimeoutLine = $prevLine;
					}
				}
			
			// BackupBuddy Error #
			} elseif ( false !== stripos( $line, 'Error #' ) ) {
				$bb_notices[] = $line;
			
			// BackupBuddy Warning #
			} elseif ( false !== stripos( $line, 'Warning #' ) ) {
				$bb_notices[] = $line;
			
			} elseif ( false !== stripos( $line, 'Fatal PHP error encountered:' ) ) { // BB-prefix.
				$php_notices[] = $line;
				$recordNextLines = 5; // Record the next 5 lines after this so we get the actual error.
			
			// fatal PHP error
			} elseif ( false !== stripos( $line, 'Fatal error:' ) ) {
				$php_notices[] = $line;
			
			// PHP parse error
			} elseif ( false !== stripos( $line, 'Parse error:' ) ) {
				$php_notices[] = $line;
			
			// out of memory error
			} elseif ( false !== stripos( $line, 'allowed memory size of' ) ) {
				$php_notices[] = $line;
			}
			
			
			$prevLine = $line;
		}
		
		
		if ( ( count( $php_notices ) > 0 ) || ( count( $bb_notices ) > 0 ) ) {
			self::$_results['highlights'][] = 'Detected `' . count( $php_notices ) . '` possible PHP notices and `' . count( $bb_notices ) . '` possible BackupBuddy notices in log `' . $log_file . '`. See php_notices or bb_notices section for details.';
		}
		
		self::$_results['php_notices'] = array_merge( self::$_results['php_notices'], $php_notices );
		self::$_results['bb_notices'] = array_merge( self::$_results['bb_notices'], $bb_notices );
		
		// Log max memory usage seen in this log.
		if ( $maxMem > self::$_results['memory']['memory_max_usage_logged'] ) {
			self::$_results['memory']['memory_max_usage_logged'] = $maxMem;
		}
		
		return array( $php_notices, $bb_notices );
	}
	
	
	
	// Save alerts into file for displaying on Stash Live page.
	public static function _record_alerts() {
		$troubleshooting_alerts_file = backupbuddy_core::getLogDirectory() . 'live/troubleshooting_alerts-' . pb_backupbuddy::$options['log_serial'] . '.txt';
		
		if ( count( self::$_results['alerts'] ) > 0 ) {
			if ( false === @file_put_contents( $troubleshooting_alerts_file, implode( "<br>", self::$_results['alerts'] ) ) ) {
				// Unable to write.
			}
		} else { // Clear away file.
			if ( @file_exists( $troubleshooting_alerts_file ) ) {
				@unlink( $troubleshooting_alerts_file );
			}
		}
		
	} // End _record_alerts().
	
	
	
	public static function _strip_tags_content( $array ) {
		foreach( $array as &$array_contents ) {
			if ( is_array( $array_contents ) ) {
				$array_contents = self::_strip_tags_content( $array_contents );
			} else {
				$array_contents = strip_tags( $array_contents );
			}
		}
		return $array;
	} 
	
	
} // End class.

