CVE-2022-0157 (PHP, published 2022-01-10T16:15Z)
Description: value: phoronix-test-suite is vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Severity: LOW (CVSS v3 base score: 5.4)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/phoronix-test-suite/phoronix-test-suite
Files changed:
ChangeLog
pts-core/objects/pts_env.php
pts-core/objects/pts_phoroql.php
pts-core/objects/pts_result_viewer_embed.php
pts-core/phoromatic/pages/phoromatic_account_activity.php
pts-core/phoromatic/pages/phoromatic_admin.php
pts-core/phoromatic/pages/phoromatic_admin_config.php
pts-core/phoromatic/pages/phoromatic_admin_data.php
pts-core/phoromatic/pages/phoromatic_benchmark.php
pts-core/phoromatic/pages/phoromatic_build_suite.php
pts-core/phoromatic/pages/phoromatic_caches.php
pts-core/phoromatic/pages/phoromatic_component_table.php
pts-core/phoromatic/pages/phoromatic_create_test.php
pts-core/phoromatic/pages/phoromatic_dashboard.php
pts-core/phoromatic/pages/phoromatic_local_suites.php
pts-core/phoromatic/pages/phoromatic_logs.php
pts-core/phoromatic/pages/phoromatic_main.php
pts-core/phoromatic/pages/phoromatic_maintenance_table.php
pts-core/phoromatic/pages/phoromatic_password.php
pts-core/phoromatic/pages/phoromatic_r_add_test_build_suite_details.php
pts-core/phoromatic/pages/phoromatic_r_basic_suite_details.php
pts-core/phoromatic/pages/phoromatic_result.php
pts-core/phoromatic/pages/phoromatic_results.php
pts-core/phoromatic/pages/phoromatic_sched.php
pts-core/phoromatic/pages/phoromatic_schedules.php
pts-core/phoromatic/pages/phoromatic_search.php
pts-core/phoromatic/pages/phoromatic_settings.php
pts-core/phoromatic/pages/phoromatic_system_claim.php
pts-core/phoromatic/pages/phoromatic_systems.php
pts-core/phoromatic/pages/phoromatic_testing.php
pts-core/phoromatic/pages/phoromatic_tests.php
pts-core/phoromatic/pages/phoromatic_tracker.php
pts-core/phoromatic/pages/phoromatic_users.php
pts-core/phoromatic/pages/phoromatic_welcome.php
pts-core/phoromatic/phoromatic_functions.php
pts-core/phoromatic/public_html/phoromatic.php
pts-core/phoromatic/public_html/public.php
Commit message: phodevi: Input sanitization updates for Phoromatic Server

Also other code formatting / cleanups while reviewing the code...


Vulnerable code:
					$posted[$var] = $v;
	public static function evaluate_search_tree($tree, $join = 'AND', $callback)
	Copyright (C) 2018 - 2020, Phoronix Media
	Copyright (C) 2018 - 2020, Michael Larabel
		$PAGE .= '<h1 id="result_file_title" placeholder="Title">' . $result_file->get_title() . '</h1>';
		$PAGE .= '<p id="result_file_desc" placeholder="Description">' . str_replace(PHP_EOL, '<br />', $result_file->get_description()) . '</p>';
			// $PAGE .= $res . '<br />';


					$PAGE .= '<div id="update_annotation_' . $i . '" contentEditable="true">' . $result_object->get_annotation() . '</div> <input type="submit" value="Update Annotation" onclick="javascript:update_annotation_for_result_object(\'' . $this->result_public_id . '\', \'' . $i . '\'); return false;">';
				$PAGE .= '<p class="mini">' . $result_object->get_annotation() . '</p>';





	Copyright (C) 2014 - 2018, Phoronix Media
	Copyright (C) 2014 - 2018, Michael Larabel




			$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'public.php?ut=' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_system_id_to_name($test_result_row['SystemID'], $test_result_row['AccountID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';

							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_account_id_to_group_name($row['AccountID']) . '</td><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($row['AccountID'], $row['ScheduleID'])), 'System') . '</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td><td><a onclick="return confirm(\'Permanently remove this schedule?\');" href="/?admin_data/delete/schedule/' . $row['AccountID'] . '/' . $row['ScheduleID'] . '">Permanently Remove</a></td></tr></table></li></a>';

							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_account_id_to_group_name($row['AccountID']) . '</td><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($row['AccountID'], $row['ScheduleID'])), 'System') . '</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td><td><a onclick="return confirm(\'Permanently remove this schedule?\');" href="/?admin_data/delete/schedule/' . $row['AccountID'] . '/' . $row['ScheduleID'] . '">Permanently Remove</a></td></tr></table></li></a>';
							$main .= '<a onclick=""><li>' . $row['Trigger'] . '<br /><table><tr><td>' . $row['TriggeredOn'] . '</td><td>' . phoromatic_account_id_to_group_name($row['AccountID']) . '</td><td><a onclick="return confirm(\'Permanently remove this trigger?\');" href="/?admin_data/delete/trigger/' . $row['AccountID'] . '/' . $row['ScheduleID'] . '/' . $row['Trigger'] . '">Permanently Remove</a></td></tr></table></li></a>';
							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_account_id_to_group_name($row['AccountID']) . '</td><td>' . $row['LocalIP'] . '</td><td><strong>' . $row['CurrentTask'] . '</strong></td><td><strong>Last Communication:</strong> ' . date('j F Y H:i', strtotime($row['LastCommunication'])) . '</td><td><a onclick="return confirm(\'Permanently remove this system?\');" href="/?admin_data/delete/system/' . $row['AccountID'] . '/' . $row['SystemID'] . '">Permanently Remove</a></td></tr></table></li></a>';

							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_account_id_to_group_name($row['AccountID']) . '</td><td>' . $row['LocalIP'] . '</td><td><strong>' . $row['CurrentTask'] . '</strong></td><td><strong>Last Communication:</strong> ' . date('j F Y H:i', strtotime($row['LastCommunication'])) . '</td><td><a onclick="return confirm(\'Permanently remove this system?\');" href="/?admin_data/delete/system/' . $row['AccountID'] . '/' . $row['SystemID'] . '">Permanently Remove</a></td></tr></table></li></a>';
	Copyright (C) 2015 - 2021, Phoronix Media
	Copyright (C) 2015 - 2021, Michael Larabel



						$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'?result/' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';
			$main = '
			<h2>' . ($is_new ? 'Create' : 'Edit') . ' A Benchmark</h2>


	Copyright (C) 2015 - 2018, Phoronix Media
	Copyright (C) 2015 - 2018, Michael Larabel













			$main .= '<a name="' . $id . '"></a><h1>' . $test_suite->get_title() . ' [' . $id . ']</h1>';
			$main .= '<p><strong>' . $test_suite->get_maintainer() . '</strong></p>';
			$main .= '<p><em>' . $test_suite->get_description() . '</em></p>';










	Copyright (C) 2014 - 2021, Phoronix Media
	Copyright (C) 2014 - 2021, Michael Larabel


	Copyright (C) 2008 - 2021, Phoronix Media
	Copyright (C) 2008 - 2021, Michael Larabel
				$result_file_title = phoromatic_system_id_to_name($system_types[0]) . ' Tests';
							$system_name = phoromatic_system_id_to_name($row['SystemID']);
							$system_name = phoromatic_system_id_to_name($row['SystemID']) . ': ' . $row['Trigger'];
							$system_name = phoromatic_system_id_to_name($row['SystemID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
					if(($replacement = phoromatic_system_id_to_name($row['SystemID'])) != null)
					if(($replacement = phoromatic_account_id_to_group_name($row['AccountID'])) != null)
					$right .= '<p><input type="checkbox" value="' . $row['PPRID'] . '" name="compare_results" /> ' . $row['Title'] . '<br /><em>' . phoromatic_system_id_to_name($row['SystemID'], $row['AccountID']) . '</em></p>';
	Copyright (C) 2008 - 2018, Phoronix Media
	Copyright (C) 2008 - 2018, Michael Larabel

			echo phoromatic_webui_header_logged_in();
			$main = null;
			if(!PHOROMATIC_USER_IS_VIEWER && isset($PATH[0]) && $PATH[0] == 'delete')
			{
				$pprids = explode(',', $PATH[1]);
				foreach($pprids as $pprid)
					$stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_results WHERE AccountID = :account_id AND PPRID = :pprid LIMIT 1');
					$stmt->bindValue(':account_id', $_SESSION['AccountID']);
					$stmt->bindValue(':pprid', $pprid);
					$result = $stmt->execute();
					if($result && ($row = $result->fetchArray()))
						$composite_xml = phoromatic_server::phoromatic_account_result_path($_SESSION['AccountID'], $row['UploadID']) . 'composite.xml';
						if(is_file($composite_xml))
						{
							unlink($composite_xml);
						}

						pts_file_io::delete(phoromatic_server::phoromatic_account_result_path($_SESSION['AccountID'], $row['UploadID']), null, true);

						$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_results_results WHERE AccountID = :account_id AND UploadID = :upload_id');
						$stmt->bindValue(':account_id', $_SESSION['AccountID']);
						$stmt->bindValue(':upload_id', $row['UploadID']);
						$result = $stmt->execute();

						$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_results_systems WHERE AccountID = :account_id AND UploadID = :upload_id');
						$stmt->bindValue(':account_id', $_SESSION['AccountID']);
						$stmt->bindValue(':upload_id', $row['UploadID']);
						$result = $stmt->execute();


					$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_results WHERE AccountID = :account_id AND PPRID = :pprid');
					$stmt->bindValue(':pprid', $pprid);
					// TODO XXX fix below
					//$upload_dir = phoromatic_server::phoromatic_account_result_path($_SESSION['AccountID'], $upload_id);
					//pts_file_io::delete($upload_dir);
			if($main == null)
				if(isset($_POST['result_limit']))
					if(is_numeric($_POST['result_limit']) && $_POST['result_limit'] > 9)
					{
						$result_limit = $_POST['result_limit'];
					}
					else
					{
						$result_limit = 0;
					}
					$result_limit = 100;
				$min_date = strtotime(phoromatic_server::account_created_on($_SESSION['AccountID']));
				$default_start_date = max($min_date, strtotime('-1 year'));
				$min_date = date('Y-m-d', $min_date);
				$time_start = strtotime(isset($_POST['time_start']) && !empty($_POST['time_start']) ? $_POST['time_start'] : $min_date);
				if(empty($time_start))
					$time_start = strtotime($min_date);
				$time_end = strtotime((isset($_POST['time_end']) && !empty($_POST['time_end']) ? $_POST['time_end'] : date('Y-m-d')) . ' 23:59:59');
				if(empty($time_end))
					$time_end = strtotime(date('Y-m-d') . ' 23:59:59');
				$main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" method="post"><div style="text-align: left; font-weight: bold;">Results From <input id="time_start" name="time_start" type="date" required pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" min="' . $min_date . '" value="' . (isset($_POST['time_start']) ? $_POST['time_start'] : date('Y-m-d', $default_start_date)) . '" max="' . date('Y-m-d') . '" /> To  <input id="time_end" name="time_end" type="date" required pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" min="' . $min_date . '" value="' . (isset($_POST['time_end']) ? $_POST['time_end'] : date('Y-m-d')) . '" max="' . date('Y-m-d') . '" /> &nbsp; With Tests: <input type="text" name="containing_tests" id="containing_tests" value="' . (isset($_POST['containing_tests']) ? $_POST['containing_tests'] : null) . '" /> With Hardware: <input type="text" name="containing_hardware" id="containing_hardware" value="' . (isset($_POST['containing_hardware']) ? $_POST['containing_hardware'] : null) . '" /> With System Software: <input type="text" name="containing_software" id="containing_software" value="' . (isset($_POST['containing_software']) ? $_POST['containing_software'] : null) . '" /> Search For <input type="text" name="search" id="search_for" value="' . (isset($_POST['search']) ? $_POST['search'] : null) . '" /> Limit Results To <select id="result_limit" name="result_limit">';
				for($i = 100; $i <= 500; $i += 100)
					$main .= '<option value="' . $i . '"' . ($result_limit == $i ? ' selected="selected"' : null) . '>' . $i . '</option>';
				$main .= '<option value=""' . (isset($_POST['result_limit']) && empty($result_limit) ? ' selected="selected"' : null) . '>No Limit</option>';
				$main .= '</select> &nbsp; <input type="button" value="Reset" onclick="phoromatic_clear_results_search_fields();" />';
				$main .= ' &nbsp; <input type="submit" value="Update" /></div></form>';
				$main .= '<p style="font-size: 90%;">** <em>AND</em>, <em>OR</em>, and <em>NOT</em> search operators supported for tests/hardware/software search fields. **</p>';
				$main .= '<h1>Account Test Results</h1>';
				$main .= '<div class="pts_phoromatic_info_box_area">';
				$search_for = (!isset($_POST['search']) || empty($_POST['search']) ? null : 'AND (Title LIKE :search OR Description LIKE :search OR UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND (Software LIKE :search OR Hardware LIKE :search)))');
				if(isset($_POST['containing_hardware']) && !empty($_POST['containing_hardware']))
					$hw_advanced_query = stripos($_POST['containing_hardware'], ' AND ') !== false || stripos($_POST['containing_hardware'], ' OR ') !== false || stripos($_POST['containing_hardware'], ' NOT ') !== false;
					if($hw_advanced_query || true)
					{
						$hw_advanced_query = pts_phoroql::search_query_to_tree($_POST['containing_hardware']);
					}
					else
					{
						$search_for .= ' AND UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND Hardware LIKE :containing_hardware)';
					}
				if(isset($_POST['containing_software']) && !empty($_POST['containing_software']))
					$sw_advanced_query = strpos($_POST['containing_software'], ' AND ') !== false || strpos($_POST['containing_software'], ' OR ') !== false || strpos($_POST['containing_software'], ' NOT ') !== false;
					if($sw_advanced_query || true)
					{
						$sw_advanced_query = pts_phoroql::search_query_to_tree($_POST['containing_software']);
					}
					else
					{
						$search_for .= ' AND UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND Software LIKE :containing_software)';
					}
				$main .= '<div style="margin: 0 5%;"><ul style="max-height: 100%;"><li><h1>Recent Test Results</h1></li>';

				if(isset($PATH[1]) && $PATH[0] == 'hash')
					// Find matching comparison hashes
					$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE AccountID = :account_id ' . $search_for. ' AND ComparisonHash = :comparison_hash ORDER BY UploadTime DESC');
					$stmt->bindValue(':comparison_hash', $PATH[1]);
				else if(isset($PATH[1]) && $PATH[0] == 'ticket')
					// Find matching ticket results
					$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE AccountID = :account_id ' . $search_for. ' AND BenchmarkTicketID = :ticket_id ORDER BY UploadTime DESC');
					$stmt->bindValue(':ticket_id', $PATH[1]);
				else
					$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE AccountID = :account_id ' . $search_for. ' ORDER BY UploadTime DESC');

				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt->bindValue(':search', (isset($_POST['search']) ? '%' . $_POST['search'] . '%' : null));
				$stmt->bindValue(':containing_hardware', (isset($_POST['containing_hardware']) ? '%' . $_POST['containing_hardware'] . '%' : null));
				$stmt->bindValue(':containing_software', (isset($_POST['containing_software']) ? '%' . $_POST['containing_software'] . '%' : null));
				$test_result_result = $stmt->execute();
				$results = 0;
				$containing_tests = isset($_POST['containing_tests']) ? $_POST['containing_tests'] : null;
					$containing_tests = pts_phoroql::search_query_to_tree($containing_tests);
				while($test_result_row = $test_result_result->fetchArray())

					$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'?result/' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';
				if($results == 0)
				{
					$main .= '<li class="light" style="text-align: center;">No Results Found</li>';
				}
				else if($results > 3)
				{
					$main .= '<a onclick=""><li id="global_bottom_totals"><input type="checkbox" id="global_checkbox" onclick="javascript:phoromatic_toggle_checkboxes_on_page(this);" onchange="return false;"></input> <strong>' . $results . ' Results</strong></li></a>';
				}
				$main .= '</div>';

				$result_share_opt = phoromatic_server::read_setting('force_result_sharing') ? '1 = 1' : 'AccountID IN (SELECT AccountID FROM phoromatic_account_settings WHERE LetOtherGroupsViewResults = "1")';
				$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE ' . $result_share_opt . ' AND AccountID != :account_id ' . $search_for. ' ORDER BY UploadTime DESC');
				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt->bindValue(':search', (isset($_POST['search']) ? '%' . $_POST['search'] . '%' : null));
				$stmt->bindValue(':containing_hardware', (isset($_POST['containing_hardware']) ? '%' . $_POST['containing_hardware'] . '%' : null));
				$stmt->bindValue(':containing_software', (isset($_POST['containing_software']) ? '%' . $_POST['containing_software'] . '%' : null));
				$test_result_result = $stmt->execute();
				if(!empty($test_result_result) && ($test_result_row = $test_result_result->fetchArray()))
				{
					$main .= '<div class="pts_phoromatic_info_box_area">';
					$main .= '<ul style="max-height: 100%;"><li><h1>Results Shared By Other Groups</h1></li>';
					$results = 0;
					do
					{
						if(strtotime($test_result_row['UploadTime']) > $time_end)
						{
							continue;
						}
						if(strtotime($test_result_row['UploadTime']) < $time_start)
						{
							//break;
						}
						if(!empty($result_limit) && $result_limit > 1 && $result_limit == $results)
						{
							break;
						}

						$composite_xml = phoromatic_server::phoromatic_account_result_path($test_result_row['AccountID'], $test_result_row['UploadID']) . 'composite.xml';
						$result_file = new pts_result_file($composite_xml);

						if(isset($_POST['containing_hardware']) && !empty($_POST['containing_hardware']) && $hw_advanced_query)
						{
							//if(!$result_file->contains_system_hardware($_POST['containing_hardware']))
							if(!pts_phoroql::evaluate_search_tree($hw_advanced_query, 'AND', array($result_file, 'contains_system_hardware')))
							{
								continue;
							}
						}
						if(isset($_POST['containing_software']) && !empty($_POST['containing_software']) && $sw_advanced_query)
						{
							if(!pts_phoroql::evaluate_search_tree($sw_advanced_query, 'AND', array($result_file, 'contains_system_software')))
							{
								continue;
							}
						}

						if(!empty($containing_tests))
						{
							if(!pts_phoroql::evaluate_search_tree($containing_tests, 'AND', array($result_file, 'contains_test')))
							{
								continue;
							}
						}

						$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'?result/' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td><strong>' . phoromatic_account_id_to_group_name($test_result_row['AccountID']) . '</strong></td><td>' . phoromatic_system_id_to_name($test_result_row['SystemID'], $test_result_row['AccountID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';
						$results++;
					}
					while($test_result_row = $test_result_result->fetchArray());
					$main .= '</ul></div>';
				}
			echo phoromatic_webui_main($main);
			echo phoromatic_webui_footer();
	Copyright (C) 2014 - 2017, Phoronix Media
	Copyright (C) 2014 - 2017, Michael Larabel

			<p><select name="schedule_hour" id="schedule_hour">';

			if(!$is_new)
			{
				$run_at = explode('.', $e_schedule['RunAt']);
				$days_active = !empty($e_schedule['ActiveOn']) ? explode(',', $e_schedule['ActiveOn']) : array();
			}
			for($i = 0; $i <= 23; $i++)
			{
				$i_f = (strlen($i) == 1 ? '0' . $i : $i);
				$main .= '<option value="' . $i_f . '"' . (!$is_new && $run_at[0] == $i ? 'selected="selected" ' : null) . '>' . $i_f . '</option>';
			}

			$main .= '</select> <select name="schedule_minute" id="schedule_minute">';
			for($i = 0; $i < 60; $i += 10)
			{
				$i_f = (strlen($i) == 1 ? '0' . $i : $i);
				$main .= '<option value="' . $i_f . '"' . (!$is_new && $run_at[1] == $i ? 'selected="selected" ' : null) . '>' . $i_f . '</option>';
			}
			$main .= '</select><h3>Active On:</h3><p>';
			$week = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
			foreach($week as $index => $day)
			{
				$main .= '<input type="checkbox" name="days_active[]" value="' . $index . '"' . (!$is_new && in_array($index, $days_active) ? 'checked="checked" ' : null) . '/> ' . $day;
			}
			$main .= '</p></td>
</tr>
<tr>
  <td><h3>Trigger-Based Testing</h3><em>To carry out trigger-based testing, you can simply have an external process/script trigger (&quot;ping&quot;) a specialized URL whenever an event occurs to commence a new round of testing. This is the most customizable approach to having Phoromatic run tests on a system if you wish to have it occur whenever a Git/SVN commit takes place or other operations.</em></td>
  <td><h3>Once creating the test schedule there will be a specialized URL you can use for &quot;pinging&quot; where you can pass it a Git commit hash, SVN revision number, date, or other unique identifiers to externally trigger the test schedules and systems to begin testing. This custom trigger is passed to any of the used context scripts for setting up the system in an appropriate state.</h3></td>
</tr>
<tr>
  <td><h3>One-Time / Manual Testing</h3><em>Carrying out Phoromatic-controlled benchmark on no routine schedule, similar to the trigger-based testing.</em></td>
  <td><h3>If you wish to only run a set of tests once on a given system or to do so seldom with the same set of tests, simply proceed with creating the test schedule without setting any run time / active days. When going to the web page for this test schedule there will be a button to trigger the tests to run on all affected systems. One-time benchmarking can also be setup via the <a href="?benchmark">Run A Benchmark</a> page.</h3></td>
</tr>
</table>';
$main .= (empty($env_var_edit) ? '<p><a id="env_var_options_show" onclick="javascript:document.getElementById(\'env_var_options\').style.display = \'block\'; javascript:document.getElementById(\'env_var_options_show\').style.display = \'none\'; ">Advanced Options</a></p> <div id="env_var_options" style="display: none;">' : '<div id="env_var_options">') . '<p>The advanced options require the Phoromatic clients be on the latest Phoronix Test Suite (10.8 or newer / Git). See the Phoronix Test Suite documentation for more information on these environment variables / advanced options.</p>' . pts_env::get_html_options('phoromatic', $env_var_edit) . '</div>';
$main .= '<p align="right"><input name="submit" value="' . ($is_new ? 'Create' : 'Edit') . ' Schedule" type="submit" onclick="return pts_rmm_validate_schedule();" /></p>
			echo phoromatic_webui_main($main);
			echo phoromatic_webui_footer();
	Copyright (C) 2008 - 2018, Phoronix Media
	Copyright (C) 2008 - 2018, Michael Larabel



				$trigger_url = 'http://' . phoromatic_web_socket_server_ip() . '/event.php?type=trigger&user=' . $_SESSION['UserName'] . '&public_key=' . $row['PublicKey'] . '&trigger=XXX';
				$main .= '<p>This test schedule can be manually triggered to run at any time by calling <strong>' . $trigger_url . '</strong> where <em>XXX</em> is the trigger value to be used (if relevant, such as a time-stamp, Git/SVN commit number or hash, etc). There\'s also the option of sub-targeting system(s) part of this schedule. One option is appending <em>&sub_target_this_ip</em> if this URL is being called from one of the client test systems to only sub-target the triggered testing on that client, among other options.</p>';
				$main .= '<p>If you wish to run this test schedule now, click the following button and the schedule will be run on all intended systems at their next earliest possible convenience.</p>';
				$main .= '<p><form action="?schedules/' . $PATH[0] . '" name="manual_run" method="post">';
				$main .= '<input type="hidden" name="do_manual_test_run" value="1" /><input type="submit" value="Run Test Schedule Now" onclick="return confirm(\'Run this test schedule now?\');" />';
				$main .= '</form></p>';
				$main .= '<p><form action="?schedules/' . $PATH[0] . '" name="skip_run" method="post">';
				$main .= '<input type="hidden" name="skip_current_ticket" value="1" /><input type="submit" value="Skip Current Test Ticket" onclick="return confirm(\'Skip any currently active test ticket on all systems?\');" />';
				$main .= '</form></p>';


						$main .= '<a href="?result/' . $test_result_row['PPRID'] . '"><li>' . $test_result_row['Title'] . '<br /><table><tr><td>' . phoromatic_system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td></tr></table></li></a>';
			<p>Test schedules are used for tests that are intended to be run on a recurring basis -- either daily or other defined time period -- or whenever a trigger/event occurs, like a new Git commit to a software repository being tracked. Test schedules can be run on any given system(s)/group(s) and can be later edited.</p>';

			if(!PHOROMATIC_USER_IS_VIEWER)
			{
				$main .= '
				<hr />
				<h2>Create A Schedule</h2>
				<p><a href="?sched">Create a schedule</a> followed by adding tests/suites to run for that schedule on the selected systems.</p>';
			}

			$main .= '<hr /><h2>Current Schedules</h2>';
			$main .= '<div class="pts_phoromatic_info_box_area">
					<ul>
						<li><h1>Active Test Schedules</h1></li>';
					$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, Description, RunTargetSystems, RunTargetGroups, RunAt, ActiveOn FROM phoromatic_schedules WHERE AccountID = :account_id AND State >= 1 ORDER BY Title ASC');
					$stmt->bindValue(':account_id', $_SESSION['AccountID']);
					$result = $stmt->execute();
					$row = $result->fetchArray();

					if($row == false)
					{
						$main .= '<li class="light" style="text-align: center;">No Schedules Found</li>';
					}
					else
					{
						do
						{
							$stmt_tests = phoromatic_server::$db->prepare('SELECT COUNT(*) AS TestCount FROM phoromatic_schedules_tests WHERE AccountID = :account_id AND ScheduleID = :schedule_id ORDER BY TestProfile ASC');
							$stmt_tests->bindValue(':account_id', $_SESSION['AccountID']);
							$stmt_tests->bindValue(':schedule_id', $row['ScheduleID']);
							$result_tests = $stmt_tests->execute();
							$row_tests = $result_tests->fetchArray();
							$test_count = !empty($row_tests) ? $row_tests['TestCount'] : 0;

							$group_count = empty($row['RunTargetGroups']) ? 0 : count(explode(',', $row['RunTargetGroups']));
							$main .= '<a href="?schedules/' . $row['ScheduleID'] . '"><li>' . $row['Title'] . '<br /><table><tr><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($_SESSION['AccountID'], $row['ScheduleID'])), 'System') . '</td><td>' . pts_strings::plural_handler($group_count, 'Group') . '</td><td>' . pts_strings::plural_handler($test_count, 'Test') . '</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID']), 'Result') . ' Total</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID'], 'TODAY'), 'Result') . ' Today</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td></tr></table></li></a>';
						}
						while($row = $result->fetchArray());
					}
			$main .= '</ul>
			</div>';
			$main .= '<hr /><h2>Schedule Overview</h2>';
			$week = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
			foreach($week as $i => $day)
				$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, RunAt, RunTargetGroups, RunTargetSystems FROM phoromatic_schedules WHERE AccountID = :account_id AND State >= 1 AND ActiveOn LIKE :active_on ORDER BY RunAt,ActiveOn,Title ASC');
				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt->bindValue(':active_on', '%' . $i . '%');
				$result = $stmt->execute();
				$has_matched = false;
				while($row = $result->fetchArray())
					if(!$has_matched)
					{
						$main .= '<h3>' . $day . '</h3>' . PHP_EOL . '<p>';
						$has_matched = true;
					}
					$main .= '<em>' . $row['RunAt'] . '</em> <a href="?schedules/' . $row['ScheduleID'] . '">' . $row['Title'] . '</a>';
					//$main .= $row['RunTargetSystems'] . ' ' . $row['RunTargetGroups'];
					$main .= '<br />';

				if($has_matched)
					$main .= '</p>' . PHP_EOL;

			$main .= '<div class="pts_phoromatic_info_box_area">
					<ul>
						<li><h1>Deactivated Test Schedules</h1></li>';
					$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, Description, RunTargetSystems, RunTargetGroups, RunAt, ActiveOn FROM phoromatic_schedules WHERE AccountID = :account_id AND State < 1 ORDER BY Title ASC');
					$stmt->bindValue(':account_id', $_SESSION['AccountID']);
					$result = $stmt->execute();
					$row = $result->fetchArray();
					if($row == false)
					{
						$main .= '<li class="light" style="text-align: center;">No Schedules Found</li>';
					}
					else
					{
						do
						{
							$stmt_tests = phoromatic_server::$db->prepare('SELECT COUNT(*) AS TestCount FROM phoromatic_schedules_tests WHERE AccountID = :account_id AND ScheduleID = :schedule_id ORDER BY TestProfile ASC');
							$stmt_tests->bindValue(':account_id', $_SESSION['AccountID']);
							$stmt_tests->bindValue(':schedule_id', $row['ScheduleID']);
							$result_tests = $stmt_tests->execute();
							$row_tests = $result_tests->fetchArray();
							$test_count = !empty($row_tests) ? $row_tests['TestCount'] : 0;

							$group_count = empty($row['RunTargetGroups']) ? 0 : count(explode(',', $row['RunTargetGroups']));
							$main .= '<a href="?schedules/' . $row['ScheduleID'] . '"><li>' . $row['Title'] . '<br /><table><tr><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($_SESSION['AccountID'], $row['ScheduleID'])), 'System') . '</td><td>' . pts_strings::plural_handler($group_count, 'Group') . '</td><td>' . pts_strings::plural_handler($test_count, 'Test') . '</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID']), 'Result') . ' Total</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID'], 'TODAY'), 'Result') . ' Today</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td></tr></table></li></a>';
						}
						while($row = $result->fetchArray());
					}
			$main .= '</ul>
			</div>';
			echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
			echo phoromatic_webui_footer();
	Copyright (C) 2014 - 2018, Phoronix Media
	Copyright (C) 2014 - 2018, Michael Larabel

		$search_query = $_REQUEST['search'];


	Copyright (C) 2008 - 2015, Phoronix Media
	Copyright (C) 2008 - 2015, Michael Larabel

if(function_exists('ssh2_connect') && isset($_POST['ip']) && isset($_POST['port']) && isset($_POST['password']) && isset($_POST['username']))
{
	$connection = ssh2_connect($_POST['ip'], $_POST['port']);
	if(ssh2_auth_password($connection, $_POST['username'], $_POST['password']))
	{
		$tmp_local_file = tempnam('/tmp', 'pts-ssh');
		$tmp_remote_file = 'pts-ssh-' . rand(9999, 99999);

		file_put_contents($tmp_local_file, '#!/bin/sh
if [ -w /var/lib/phoronix-test-suite/ ]
then
	PHORO_FILE_PATH=/var/lib/phoronix-test-suite/
elif [ -w $HOME/.phoronix-test-suite/ ]
then
	PHORO_FILE_PATH=$HOME/.phoronix-test-suite/
fi

echo "' . phoromatic_web_socket_server_ip() . '" >> $PHORO_FILE_PATH/phoromatic-servers
mkdir -p $PHORO_FILE_PATH/modules-data/phoromatic
echo "' . phoromatic_web_socket_server_addr() . '" > $PHORO_FILE_PATH/modules-data/phoromatic/last-phoromatic-server
');

		ssh2_scp_send($connection, $tmp_local_file, $tmp_remote_file);
		unlink($tmp_local_file);
		ssh2_exec($connection, 'chmod +x ' . $tmp_remote_file);
		ssh2_exec($connection, './' . $tmp_remote_file);
		ssh2_exec($connection, 'rm' . $tmp_remote_file);
	}
}
				$stmt->bindValue(':ip_address', $_POST['ip_claim']);
				$stmt->bindValue(':mac_address', $_POST['mac_claim']);
				$stmt->bindValue(':ip_address', $ipc);
				$stmt->bindValue(':mac_address', $macc);
	Copyright (C) 2008 - 2021, Phoronix Media
	Copyright (C) 2008 - 2021, Michael Larabel
			$stmt->bindValue(':title', $_POST['system_title']);
			$stmt->bindValue(':description', $_POST['system_description']);
						$main .= '<a href="?result/' . $test_result_row['PPRID'] . '"><li>' . $test_result_row['Title'] . '<br /><table><tr><td>' . phoromatic_system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td></tr></table></li></a>';
				$stmt->bindValue(':group_name', $_POST['remove_group']);
				$stmt = phoromatic_server::$db->prepare('SELECT SystemID, Groups FROM phoromatic_systems WHERE AccountID = :account_id AND Groups LIKE \'%#' . $_POST['remove_group'] . '#%\'');
					$revised_groups = str_replace('#' . $_POST['remove_group'] . '#', '', $row['Groups']);
				$stmt->bindValue(':inactive_days_before_removal', $_POST['remove_inactive_systems']);
			$main .= '<hr />





	Copyright (C) 2016, Phoronix Media
	Copyright (C) 2016, Michael Larabel

			if(!PHOROMATIC_USER_IS_VIEWER)
				$main .= '
				<hr />
				<h2>Create A Schedule</h2>
				<p><a href="?sched">Create a schedule</a> followed by adding tests/suites to run for that schedule on the selected systems.</p>';
			$main .= '<hr /><h2>Current Schedules</h2>';
					<ul>
						<li><h1>Active Test Schedules</h1></li>';

					$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, Description, RunTargetSystems, RunTargetGroups, RunAt, ActiveOn FROM phoromatic_schedules WHERE AccountID = :account_id AND State >= 1 ORDER BY Title ASC');
					$stmt->bindValue(':account_id', $_SESSION['AccountID']);
					$result = $stmt->execute();
					$row = $result->fetchArray();

					if($row == false)
					{
						$main .= '<li class="light" style="text-align: center;">No Schedules Found</li>';
					}
					else
					{
						do
						{
							$stmt_tests = phoromatic_server::$db->prepare('SELECT COUNT(*) AS TestCount FROM phoromatic_schedules_tests WHERE AccountID = :account_id AND ScheduleID = :schedule_id ORDER BY TestProfile ASC');
							$stmt_tests->bindValue(':account_id', $_SESSION['AccountID']);
							$stmt_tests->bindValue(':schedule_id', $row['ScheduleID']);
							$result_tests = $stmt_tests->execute();
							$row_tests = $result_tests->fetchArray();
							$test_count = !empty($row_tests) ? $row_tests['TestCount'] : 0;

							$group_count = empty($row['RunTargetGroups']) ? 0 : count(explode(',', $row['RunTargetGroups']));
							$main .= '<a href="?schedules/' . $row['ScheduleID'] . '"><li>' . $row['Title'] . '<br /><table><tr><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($_SESSION['AccountID'], $row['ScheduleID'])), 'System') . '</td><td>' . pts_strings::plural_handler($group_count, 'Group') . '</td><td>' . pts_strings::plural_handler($test_count, 'Test') . '</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID']), 'Result') . ' Total</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID'], 'TODAY'), 'Result') . ' Today</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td></tr></table></li></a>';
						}
						while($row = $result->fetchArray());
					}


			$main .= '</ul>
			</div>';

			$stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_benchmark_tickets WHERE AccountID = :account_id AND State >= 0 AND TicketIssueTime > :time_cutoff ORDER BY TicketIssueTime DESC LIMIT 30');
			$stmt->bindValue(':account_id', $_SESSION['AccountID']);
			$stmt->bindValue(':time_cutoff', (time() - (60 * 60 * 24 * 14)));
			$result = $stmt->execute();
			$right = '<ul><li>Benchmark Tickets</li>';

			if($result)
			{
				$main .= '<div class="pts_phoromatic_info_box_area">
						<ul>
							<li><h1>Active Benchmark Tickets</h1></li>';
				$row = $result->fetchArray();
				if(!empty($row))
				{
					do
					{
						$main .= '<a href="?benchmark/' . $row['TicketID'] . '"><li>' . $row['Title'] . '</li></a>';
					}
					while($row = $result->fetchArray());
				}
				else
					$main .= '<li class="light" style="text-align: center;">No Tickets Found</li>';	
			$main .= '</ul>
			</div>';

			if(!PHOROMATIC_USER_IS_VIEWER)
				$main .= '
				<hr />
				<h2>Run A Benchmark</h2>
				<p><a href="?benchmark">Run a benchmark</a> is the area where you can run a one-time benchmark on selected system(s) and is also where to go for setting up a stress-run benchmark.</p>
				<hr />
				<h2>Create A Suite</h2>
				<p><a href="?build_suite">Build a suite</a>, which is a collection of predefined test profiles.</p>
				<hr />
				<h2>View Local Suites</h2>
				<p><a href="?local_suites">See local suites</a> available for your benchmarking needs.</p>';


			echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
			echo phoromatic_webui_footer();


	Copyright (C) 2014 - 2015, Phoronix Media
	Copyright (C) 2014 - 2015, Michael Larabel

			$stmt->bindValue(':group_name', $_POST['group_name']);
		$group_name = phoromatic_account_id_to_group_name($_SESSION['AccountID']);
	Copyright (C) 2008 - 2015, Phoronix Media
	Copyright (C) 2008 - 2015, Michael Larabel

				$box .= '
							<p id="register_link"><a onclick="javascript:document.getElementById(\'register\').style.display = \'block\'; document.getElementById(\'register_link\').style.display = \'none\';">Create A New Account</a></p>


	Copyright (C) 2013 - 2020, Phoronix Media
	Copyright (C) 2013 - 2020, Michael Larabel

		$group_name = phoromatic_account_id_to_group_name($_SESSION['AccountID']);
		$group_name = phoromatic_account_id_to_group_name($_SESSION['AccountID']);

		<h2>' . $description . '</h2>
		<p>To fix this error, try <a onclick="javascript:window.history.back();">returning to the previous page</a>. Still having problems? Consider <a href="https://github.com/phoronix-test-suite/phoronix-test-suite/issues?state=open">opening a GitHub issue report</a>; commercial support customers should contact Phoronix Media.</p><hr /><hr />';
function phoromatic_system_id_to_name($system_id, $aid = false)
{
	return phoromatic_server::system_id_to_name($system_id, $aid);
}
function phoromatic_account_id_to_group_name($account_id)
{
	// XXX deprecated
	return phoromatic_server::account_id_to_group_name($account_id);
}
	$stmt->bindValue(':title', $HOSTNAME);
	$stmt->bindValue(':client_hardware', $CLIENT_HARDWARE);
	Copyright (C) 2008 - 2021, Phoronix Media
	Copyright (C) 2008 - 2021, Michael Larabel
				$system_name = phoromatic_system_id_to_name($row['SystemID'], $row['AccountID']);
				$system_name = phoromatic_system_id_to_name($row['SystemID'], $row['AccountID']) . ': ' . $row['Trigger'];
				$system_name = phoromatic_system_id_to_name($row['SystemID'], $row['AccountID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
	$attribute_options = array(
		'normalize_results' => 'normalize_result_buffer',
		'sort_by_performance' => 'sort_result_buffer_values',
		'sort_by_reverse' => 'reverse_result_buffer',
		'sort_by_name' => 'sort_result_buffer',
		'condense_comparison' => 'condense_multi_way',
		);
	foreach($attribute_options as $web_var => $attr_var)
	{
		if(isset($_REQUEST[$web_var]))
		{
			$extra_attributes[$attr_var] = true;
		}
	}

	if(isset($_POST['transpose_comparison']))
	{
		$result_file->invert_multi_way_invert();
	}
	$intent = null;
	$main .= '<h1>' . $result_file->get_title() . '</h1>';
	$main .= '<p>' . $result_file->get_description() . '</p>';
	$main .= phoromatic_annotate_entry('RESULT', implode(',', $result_ids), 'TOP');

	if($result_file->get_system_count() == 1 || ($intent = pts_result_file_analyzer::analyze_result_file_intent($result_file, $intent, true)))
	{
		$table = new pts_ResultFileCompactSystemsTable($result_file, $intent);
	}
	else
	{
		$table = new pts_ResultFileSystemsTable($result_file);
	}

	$main .= '<p style="text-align: center; overflow: auto;" class="result_object">' . pts_render::render_graph_inline_embed($table, $result_file, $extra_attributes) . '</p>';

	$table = new pts_ResultFileTable($result_file, $intent);
	$main .= '<p style="text-align: center; overflow: auto;" class="result_object">' . pts_render::render_graph_inline_embed($table, $result_file, $extra_attributes) . '</p>';
	$main .= '<div id="pts_results_area">';
	foreach($result_file->get_result_objects((isset($_POST['show_only_changed_results']) ? 'ONLY_CHANGED_RESULTS' : -1)) as $i => $result_object)
	{
		$main .= '<h2><a name="r-' . $i . '"></a><a name="' . $result_object->get_comparison_hash(true, false) . '"></a>' . $result_object->test_profile->get_title() . '</h2>';
		$main .= phoromatic_annotate_entry('RESULT', implode(',', $result_ids), $result_object->get_comparison_hash(true, false));
		$main .= '<p style="text-align: center; overflow: auto;">';
		$main .= pts_render::render_graph_inline_embed($result_object, $result_file, $extra_attributes);
		$main .= '</p>';
	}
	$main .= '</div>';
		$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'public.php?ut=' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_system_id_to_name($test_result_row['SystemID'], $test_result_row['AccountID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';

Fixed code:
Phoronix Test Suite (Git)

phodevi: Input sanitization updates for Phoromatic Server

					$posted[$var] = pts_strings::sanitize($v);
	public static function evaluate_search_tree($tree, $join = 'AND', $callback = '')
	Copyright (C) 2018 - 2022, Phoronix Media
	Copyright (C) 2018 - 2022, Michael Larabel
		$PAGE .= '<h1 id="result_file_title" placeholder="Title">' . pts_strings::sanitize($result_file->get_title()) . '</h1>';
		$PAGE .= '<p id="result_file_desc" placeholder="Description">' . str_replace(PHP_EOL, '<br />', pts_strings::sanitize($result_file->get_description())) . '</p>';
					$PAGE .= '<div id="update_annotation_' . $i . '" contentEditable="true">' . pts_strings::sanitize($result_object->get_annotation()) . '</div> <input type="submit" value="Update Annotation" onclick="javascript:update_annotation_for_result_object(\'' . $this->result_public_id . '\', \'' . $i . '\'); return false;">';
				$PAGE .= '<p class="mini">' . pts_strings::sanitize($result_object->get_annotation()) . '</p>';
	Copyright (C) 2014 - 2022, Phoronix Media
	Copyright (C) 2014 - 2022, Michael Larabel
			phoromatic_quit_if_invalid_input_found(array('register_username', 'register_password', 'register_password_confirm', 'register_email', 'seed_accountid'));
			phoromatic_quit_if_invalid_input_found(array('email_all_subject', 'email_all_message'));
			$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'public.php?ut=' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_server::system_id_to_name($test_result_row['SystemID'], $test_result_row['AccountID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';
							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_server::account_id_to_group_name($row['AccountID']) . '</td><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($row['AccountID'], $row['ScheduleID'])), 'System') . '</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td><td><a onclick="return confirm(\'Permanently remove this schedule?\');" href="/?admin_data/delete/schedule/' . $row['AccountID'] . '/' . $row['ScheduleID'] . '">Permanently Remove</a></td></tr></table></li></a>';
							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_server::account_id_to_group_name($row['AccountID']) . '</td><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($row['AccountID'], $row['ScheduleID'])), 'System') . '</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td><td><a onclick="return confirm(\'Permanently remove this schedule?\');" href="/?admin_data/delete/schedule/' . $row['AccountID'] . '/' . $row['ScheduleID'] . '">Permanently Remove</a></td></tr></table></li></a>';
							$main .= '<a onclick=""><li>' . $row['Trigger'] . '<br /><table><tr><td>' . $row['TriggeredOn'] . '</td><td>' . phoromatic_server::account_id_to_group_name($row['AccountID']) . '</td><td><a onclick="return confirm(\'Permanently remove this trigger?\');" href="/?admin_data/delete/trigger/' . $row['AccountID'] . '/' . $row['ScheduleID'] . '/' . $row['Trigger'] . '">Permanently Remove</a></td></tr></table></li></a>';
							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_server::account_id_to_group_name($row['AccountID']) . '</td><td>' . $row['LocalIP'] . '</td><td><strong>' . $row['CurrentTask'] . '</strong></td><td><strong>Last Communication:</strong> ' . date('j F Y H:i', strtotime($row['LastCommunication'])) . '</td><td><a onclick="return confirm(\'Permanently remove this system?\');" href="/?admin_data/delete/system/' . $row['AccountID'] . '/' . $row['SystemID'] . '">Permanently Remove</a></td></tr></table></li></a>';
							$main .= '<a onclick=""><li>' . $row['Title'] . '<br /><table><tr><td>' . phoromatic_server::account_id_to_group_name($row['AccountID']) . '</td><td>' . $row['LocalIP'] . '</td><td><strong>' . $row['CurrentTask'] . '</strong></td><td><strong>Last Communication:</strong> ' . date('j F Y H:i', strtotime($row['LastCommunication'])) . '</td><td><a onclick="return confirm(\'Permanently remove this system?\');" href="/?admin_data/delete/system/' . $row['AccountID'] . '/' . $row['SystemID'] . '">Permanently Remove</a></td></tr></table></li></a>';
	Copyright (C) 2015 - 2022, Phoronix Media
	Copyright (C) 2015 - 2022, Michael Larabel
						$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'?result/' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_server::system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';
			$main = '<h2>' . ($is_new ? 'Create' : 'Edit') . ' A Benchmark</h2>
	Copyright (C) 2015 - 2022, Phoronix Media
	Copyright (C) 2015 - 2022, Michael Larabel
			phoromatic_quit_if_invalid_input_found(array('suite_title', 'test_add', 'suite_version', 'suite_description'));
						phoromatic_quit_if_invalid_input_found(array($i, $i . '_selected'));
			$main .= '<a name="' . $id . '"></a><h1>' . pts_strings::sanitize($test_suite->get_title()) . ' [' . $id . ']</h1>';
			$main .= '<p><strong>' . pts_strings::sanitize($test_suite->get_maintainer()) . '</strong></p>';
			$main .= '<p><em>' . pts_strings::sanitize($test_suite->get_description()) . '</em></p>';
	Copyright (C) 2014 - 2022, Phoronix Media
	Copyright (C) 2014 - 2022, Michael Larabel
		phoromatic_quit_if_invalid_input_found(array('tp'));
	Copyright (C) 2008 - 2022, Phoronix Media
	Copyright (C) 2008 - 2022, Michael Larabel
				$result_file_title = phoromatic_server::system_id_to_name($system_types[0]) . ' Tests';
							$system_name = phoromatic_server::system_id_to_name($row['SystemID']);
							$system_name = phoromatic_server::system_id_to_name($row['SystemID']) . ': ' . $row['Trigger'];
							$system_name = phoromatic_server::system_id_to_name($row['SystemID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
					if(($replacement = phoromatic_server::system_id_to_name($row['SystemID'])) != null)
					if(($replacement = phoromatic_server::account_id_to_group_name($row['AccountID'])) != null)
					$right .= '<p><input type="checkbox" value="' . $row['PPRID'] . '" name="compare_results" /> ' . $row['Title'] . '<br /><em>' . phoromatic_server::system_id_to_name($row['SystemID'], $row['AccountID']) . '</em></p>';
	Copyright (C) 2008 - 2022, Phoronix Media
	Copyright (C) 2008 - 2022, Michael Larabel
		echo phoromatic_webui_header_logged_in();
		$main = null;
		if(!PHOROMATIC_USER_IS_VIEWER && isset($PATH[0]) && $PATH[0] == 'delete')
		{
			$pprids = explode(',', $PATH[1]);
			foreach($pprids as $pprid)
			{
				$stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_results WHERE AccountID = :account_id AND PPRID = :pprid LIMIT 1');
				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt->bindValue(':pprid', $pprid);
				$result = $stmt->execute();
				if($result && ($row = $result->fetchArray()))
					$composite_xml = phoromatic_server::phoromatic_account_result_path($_SESSION['AccountID'], $row['UploadID']) . 'composite.xml';
					if(is_file($composite_xml))
						unlink($composite_xml);
					pts_file_io::delete(phoromatic_server::phoromatic_account_result_path($_SESSION['AccountID'], $row['UploadID']), null, true);
					$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_results_results WHERE AccountID = :account_id AND UploadID = :upload_id');
					$stmt->bindValue(':upload_id', $row['UploadID']);
					$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_results_systems WHERE AccountID = :account_id AND UploadID = :upload_id');
					$stmt->bindValue(':account_id', $_SESSION['AccountID']);
					$stmt->bindValue(':upload_id', $row['UploadID']);
					$result = $stmt->execute();

				$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_results WHERE AccountID = :account_id AND PPRID = :pprid');
				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt->bindValue(':pprid', $pprid);
				$result = $stmt->execute();

				// TODO XXX fix below
				//$upload_dir = phoromatic_server::phoromatic_account_result_path($_SESSION['AccountID'], $upload_id);
				//pts_file_io::delete($upload_dir);
		}
		if($main == null)
		{
			phoromatic_quit_if_invalid_input_found(array('result_limit', 'containing_tests', 'time_end', 'time_start', 'search', 'containing_hardware', 'containing_software'));
			if(isset($_POST['result_limit']))
				if(is_numeric($_POST['result_limit']) && $_POST['result_limit'] > 9)
					$result_limit = $_POST['result_limit'];
					$result_limit = 0;
				}
			}
			else
			{
				$result_limit = 100;
			}
			$min_date = strtotime(phoromatic_server::account_created_on($_SESSION['AccountID']));
			$default_start_date = max($min_date, strtotime('-1 year'));
			$min_date = date('Y-m-d', $min_date);
			$time_start = strtotime(isset($_POST['time_start']) && !empty($_POST['time_start']) ? $_POST['time_start'] : $min_date);
			if(empty($time_start))
			{
				$time_start = strtotime($min_date);
			}
			$time_end = strtotime((isset($_POST['time_end']) && !empty($_POST['time_end']) ? $_POST['time_end'] : date('Y-m-d')) . ' 23:59:59');
			if(empty($time_end))
			{
				$time_end = strtotime(date('Y-m-d') . ' 23:59:59');
			}
			$main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" method="post"><div style="text-align: left; font-weight: bold;">Results From <input id="time_start" name="time_start" type="date" required pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" min="' . $min_date . '" value="' . (isset($_POST['time_start']) ? $_POST['time_start'] : date('Y-m-d', $default_start_date)) . '" max="' . date('Y-m-d') . '" /> To  <input id="time_end" name="time_end" type="date" required pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" min="' . $min_date . '" value="' . (isset($_POST['time_end']) ? $_POST['time_end'] : date('Y-m-d')) . '" max="' . date('Y-m-d') . '" /> &nbsp; With Tests: <input type="text" name="containing_tests" id="containing_tests" value="' . (isset($_POST['containing_tests']) ? $_POST['containing_tests'] : null) . '" /> With Hardware: <input type="text" name="containing_hardware" id="containing_hardware" value="' . (isset($_POST['containing_hardware']) ? $_POST['containing_hardware'] : null) . '" /> With System Software: <input type="text" name="containing_software" id="containing_software" value="' . (isset($_POST['containing_software']) ? $_POST['containing_software'] : null) . '" /> Search For <input type="text" name="search" id="search_for" value="' . (isset($_POST['search']) ? $_POST['search'] : null) . '" /> Limit Results To <select id="result_limit" name="result_limit">';
			for($i = 100; $i <= 500; $i += 100)
			{
				$main .= '<option value="' . $i . '"' . ($result_limit == $i ? ' selected="selected"' : null) . '>' . $i . '</option>';
			}
			$main .= '<option value=""' . (isset($_POST['result_limit']) && empty($result_limit) ? ' selected="selected"' : null) . '>No Limit</option>';
			$main .= '</select> &nbsp; <input type="button" value="Reset" onclick="phoromatic_clear_results_search_fields();" />';
			$main .= ' &nbsp; <input type="submit" value="Update" /></div></form>';
			$main .= '<p style="font-size: 90%;">** <em>AND</em>, <em>OR</em>, and <em>NOT</em> search operators supported for tests/hardware/software search fields. **</p>';
			$main .= '<h1>Account Test Results</h1>';
			$main .= '<div class="pts_phoromatic_info_box_area">';
			$search_for = (!isset($_POST['search']) || empty($_POST['search']) ? null : 'AND (Title LIKE :search OR Description LIKE :search OR UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND (Software LIKE :search OR Hardware LIKE :search)))');
			if(isset($_POST['containing_hardware']) && !empty($_POST['containing_hardware']))
			{
				$hw_advanced_query = stripos($_POST['containing_hardware'], ' AND ') !== false || stripos($_POST['containing_hardware'], ' OR ') !== false || stripos($_POST['containing_hardware'], ' NOT ') !== false;
				if($hw_advanced_query || true)
				{
					$hw_advanced_query = pts_phoroql::search_query_to_tree($_POST['containing_hardware']);
				else
					$search_for .= ' AND UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND Hardware LIKE :containing_hardware)';
			}
			if(isset($_POST['containing_software']) && !empty($_POST['containing_software']))
			{
				$sw_advanced_query = strpos($_POST['containing_software'], ' AND ') !== false || strpos($_POST['containing_software'], ' OR ') !== false || strpos($_POST['containing_software'], ' NOT ') !== false;
				if($sw_advanced_query || true)
					$sw_advanced_query = pts_phoroql::search_query_to_tree($_POST['containing_software']);
				else
					$search_for .= ' AND UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND Software LIKE :containing_software)';
			}
			$main .= '<div style="margin: 0 5%;"><ul style="max-height: 100%;"><li><h1>Recent Test Results</h1></li>';
			if(isset($PATH[1]) && $PATH[0] == 'hash')
			{
				// Find matching comparison hashes
				$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE AccountID = :account_id ' . $search_for. ' AND ComparisonHash = :comparison_hash ORDER BY UploadTime DESC');
				$stmt->bindValue(':comparison_hash', $PATH[1]);
			}
			else if(isset($PATH[1]) && $PATH[0] == 'ticket')
			{
				// Find matching ticket results
				$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE AccountID = :account_id ' . $search_for. ' AND BenchmarkTicketID = :ticket_id ORDER BY UploadTime DESC');
				$stmt->bindValue(':ticket_id', $PATH[1]);
			}
			else
			{
				$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE AccountID = :account_id ' . $search_for. ' ORDER BY UploadTime DESC');
			}

			$stmt->bindValue(':account_id', $_SESSION['AccountID']);
			$stmt->bindValue(':search', (isset($_POST['search']) ? '%' . $_POST['search'] . '%' : null));
			$stmt->bindValue(':containing_hardware', (isset($_POST['containing_hardware']) ? '%' . $_POST['containing_hardware'] . '%' : null));
			$stmt->bindValue(':containing_software', (isset($_POST['containing_software']) ? '%' . $_POST['containing_software'] . '%' : null));
			$test_result_result = $stmt->execute();
			$results = 0;
			$containing_tests = isset($_POST['containing_tests']) ? $_POST['containing_tests'] : null;
			if(!empty($containing_tests))
			{
				$containing_tests = pts_phoroql::search_query_to_tree($containing_tests);
			}

			while($test_result_row = $test_result_result->fetchArray())
			{
				if(strtotime($test_result_row['UploadTime']) > $time_end)
					continue;
				if(strtotime($test_result_row['UploadTime']) < $time_start)
					//break;
				if(!empty($result_limit) && $result_limit > 1 && $result_limit == $results)
					break;

				$composite_xml = phoromatic_server::phoromatic_account_result_path($test_result_row['AccountID'], $test_result_row['UploadID']) . 'composite.xml';
				$result_file = new pts_result_file($composite_xml);

				if(isset($_POST['containing_hardware']) && !empty($_POST['containing_hardware']) && $hw_advanced_query)
					//if(!$result_file->contains_system_hardware($_POST['containing_hardware']))
					if(!pts_phoroql::evaluate_search_tree($hw_advanced_query, 'AND', array($result_file, 'contains_system_hardware')))
					{
						continue;
					}
				if(isset($_POST['containing_software']) && !empty($_POST['containing_software']) && $sw_advanced_query)
					if(!pts_phoroql::evaluate_search_tree($sw_advanced_query, 'AND', array($result_file, 'contains_system_software')))
					{
						continue;
					}
					if(!pts_phoroql::evaluate_search_tree($containing_tests, 'AND', array($result_file, 'contains_test')))
					{
						continue;
					}
				$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'?result/' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_server::system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';
				$results++;
			}
			if($results == 0)
			{
				$main .= '<li class="light" style="text-align: center;">No Results Found</li>';
			}
			else if($results > 3)
			{
				$main .= '<a onclick=""><li id="global_bottom_totals"><input type="checkbox" id="global_checkbox" onclick="javascript:phoromatic_toggle_checkboxes_on_page(this);" onchange="return false;"></input> <strong>' . $results . ' Results</strong></li></a>';
			}
			$main .= '</ul></div>';
			$main .= '</div>';

			$result_share_opt = phoromatic_server::read_setting('force_result_sharing') ? '1 = 1' : 'AccountID IN (SELECT AccountID FROM phoromatic_account_settings WHERE LetOtherGroupsViewResults = "1")';
			$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results WHERE ' . $result_share_opt . ' AND AccountID != :account_id ' . $search_for. ' ORDER BY UploadTime DESC');
			$stmt->bindValue(':account_id', $_SESSION['AccountID']);
			$stmt->bindValue(':search', (isset($_POST['search']) ? '%' . $_POST['search'] . '%' : null));
			$stmt->bindValue(':containing_hardware', (isset($_POST['containing_hardware']) ? '%' . $_POST['containing_hardware'] . '%' : null));
			$stmt->bindValue(':containing_software', (isset($_POST['containing_software']) ? '%' . $_POST['containing_software'] . '%' : null));
			$test_result_result = $stmt->execute();
			if(!empty($test_result_result) && ($test_result_row = $test_result_result->fetchArray()))
			{
				$main .= '<div class="pts_phoromatic_info_box_area">';
				$main .= '<ul style="max-height: 100%;"><li><h1>Results Shared By Other Groups</h1></li>';
				$results = 0;
				do
					$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'?result/' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td><strong>' . phoromatic_server::account_id_to_group_name($test_result_row['AccountID']) . '</strong></td><td>' . phoromatic_server::system_id_to_name($test_result_row['SystemID'], $test_result_row['AccountID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';
				while($test_result_row = $test_result_result->fetchArray());
		}
		echo phoromatic_webui_main($main);
		echo phoromatic_webui_footer();
	Copyright (C) 2014 - 2022, Phoronix Media
	Copyright (C) 2014 - 2022, Michael Larabel
		<p><select name="schedule_hour" id="schedule_hour">';
		if(!$is_new)
		{
			$run_at = explode('.', $e_schedule['RunAt']);
			$days_active = !empty($e_schedule['ActiveOn']) ? explode(',', $e_schedule['ActiveOn']) : array();
		}
		for($i = 0; $i <= 23; $i++)
		{
			$i_f = (strlen($i) == 1 ? '0' . $i : $i);
			$main .= '<option value="' . $i_f . '"' . (!$is_new && $run_at[0] == $i ? 'selected="selected" ' : null) . '>' . $i_f . '</option>';
		}
		$main .= '</select> <select name="schedule_minute" id="schedule_minute">';
		for($i = 0; $i < 60; $i += 10)
		{
			$i_f = (strlen($i) == 1 ? '0' . $i : $i);
			$main .= '<option value="' . $i_f . '"' . (!$is_new && $run_at[1] == $i ? 'selected="selected" ' : null) . '>' . $i_f . '</option>';
		}
		$main .= '</select><h3>Active On:</h3><p>';
		$week = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
		foreach($week as $index => $day)
		{
			$main .= '<input type="checkbox" name="days_active[]" value="' . $index . '"' . (!$is_new && in_array($index, $days_active) ? 'checked="checked" ' : null) . '/> ' . $day;
		}
		$main .= '</p></td>
			</tr>
			<tr>
			  <td><h3>Trigger-Based Testing</h3><em>To carry out trigger-based testing, you can simply have an external process/script trigger (&quot;ping&quot;) a specialized URL whenever an event occurs to commence a new round of testing. This is the most customizable approach to having Phoromatic run tests on a system if you wish to have it occur whenever a Git/SVN commit takes place or other operations.</em></td>
			  <td><h3>Once creating the test schedule there will be a specialized URL you can use for &quot;pinging&quot; where you can pass it a Git commit hash, SVN revision number, date, or other unique identifiers to externally trigger the test schedules and systems to begin testing. This custom trigger is passed to any of the used context scripts for setting up the system in an appropriate state.</h3></td>
			</tr>
			<tr>
			  <td><h3>One-Time / Manual Testing</h3><em>Carrying out Phoromatic-controlled benchmark on no routine schedule, similar to the trigger-based testing.</em></td>
			  <td><h3>If you wish to only run a set of tests once on a given system or to do so seldom with the same set of tests, simply proceed with creating the test schedule without setting any run time / active days. When going to the web page for this test schedule there will be a button to trigger the tests to run on all affected systems. One-time benchmarking can also be setup via the <a href="?benchmark">Run A Benchmark</a> page.</h3></td>
			</tr>
			</table>';

		$main .= (empty($env_var_edit) ? '<p><a id="env_var_options_show" onclick="javascript:document.getElementById(\'env_var_options\').style.display = \'block\'; javascript:document.getElementById(\'env_var_options_show\').style.display = \'none\'; ">Advanced Options</a></p> <div id="env_var_options" style="display: none;">' : '<div id="env_var_options">') . '<p>The advanced options require the Phoromatic clients be on the latest Phoronix Test Suite (10.8 or newer / Git). See the Phoronix Test Suite documentation for more information on these environment variables / advanced options.</p>' . pts_env::get_html_options('phoromatic', $env_var_edit) . '</div>';

		$main .= '<p align="right"><input name="submit" value="' . ($is_new ? 'Create' : 'Edit') . ' Schedule" type="submit" onclick="return pts_rmm_validate_schedule();" /></p>
		echo phoromatic_webui_main($main);
		echo phoromatic_webui_footer();
	Copyright (C) 2008 - 2022, Phoronix Media
	Copyright (C) 2008 - 2022, Michael Larabel
						phoromatic_quit_if_invalid_input_found(array('add_to_schedule_select_test'));
								phoromatic_quit_if_invalid_input_found(array($i, $i . '_selected'));
					$trigger_url = 'http://' . phoromatic_web_socket_server_ip() . '/event.php?type=trigger&user=' . $_SESSION['UserName'] . '&public_key=' . $row['PublicKey'] . '&trigger=XXX';
					$main .= '<p>This test schedule can be manually triggered to run at any time by calling <strong>' . $trigger_url . '</strong> where <em>XXX</em> is the trigger value to be used (if relevant, such as a time-stamp, Git/SVN commit number or hash, etc). There\'s also the option of sub-targeting system(s) part of this schedule. One option is appending <em>&sub_target_this_ip</em> if this URL is being called from one of the client test systems to only sub-target the triggered testing on that client, among other options.</p>';
					$main .= '<p>If you wish to run this test schedule now, click the following button and the schedule will be run on all intended systems at their next earliest possible convenience.</p>';
					$main .= '<p><form action="?schedules/' . $PATH[0] . '" name="manual_run" method="post">';
					$main .= '<input type="hidden" name="do_manual_test_run" value="1" /><input type="submit" value="Run Test Schedule Now" onclick="return confirm(\'Run this test schedule now?\');" />';
					$main .= '</form></p>';
					$main .= '<p><form action="?schedules/' . $PATH[0] . '" name="skip_run" method="post">';
					$main .= '<input type="hidden" name="skip_current_ticket" value="1" /><input type="submit" value="Skip Current Test Ticket" onclick="return confirm(\'Skip any currently active test ticket on all systems?\');" />';
					$main .= '</form></p>';
						$main .= '<a href="?result/' . $test_result_row['PPRID'] . '"><li>' . $test_result_row['Title'] . '<br /><table><tr><td>' . phoromatic_server::system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td></tr></table></li></a>';
		<p>Test schedules are used for tests that are intended to be run on a recurring basis -- either daily or other defined time period -- or whenever a trigger/event occurs, like a new Git commit to a software repository being tracked. Test schedules can be run on any given system(s)/group(s) and can be later edited.</p>';
		if(!PHOROMATIC_USER_IS_VIEWER)
		{
			$main .= '
			<hr />
			<h2>Create A Schedule</h2>
			<p><a href="?sched">Create a schedule</a> followed by adding tests/suites to run for that schedule on the selected systems.</p>';
		}
		$main .= '<hr /><h2>Current Schedules</h2>';
		$main .= '<div class="pts_phoromatic_info_box_area">
			<ul>
			<li><h1>Active Test Schedules</h1></li>';
		$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, Description, RunTargetSystems, RunTargetGroups, RunAt, ActiveOn FROM phoromatic_schedules WHERE AccountID = :account_id AND State >= 1 ORDER BY Title ASC');
		$stmt->bindValue(':account_id', $_SESSION['AccountID']);
		$result = $stmt->execute();
		$row = $result->fetchArray();
		if($row == false)
		{
			$main .= '<li class="light" style="text-align: center;">No Schedules Found</li>';
		}
		else
		{
			do
			{
				$stmt_tests = phoromatic_server::$db->prepare('SELECT COUNT(*) AS TestCount FROM phoromatic_schedules_tests WHERE AccountID = :account_id AND ScheduleID = :schedule_id ORDER BY TestProfile ASC');
				$stmt_tests->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt_tests->bindValue(':schedule_id', $row['ScheduleID']);
				$result_tests = $stmt_tests->execute();
				$row_tests = $result_tests->fetchArray();
				$test_count = !empty($row_tests) ? $row_tests['TestCount'] : 0;

				$group_count = empty($row['RunTargetGroups']) ? 0 : count(explode(',', $row['RunTargetGroups']));
				$main .= '<a href="?schedules/' . $row['ScheduleID'] . '"><li>' . $row['Title'] . '<br /><table><tr><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($_SESSION['AccountID'], $row['ScheduleID'])), 'System') . '</td><td>' . pts_strings::plural_handler($group_count, 'Group') . '</td><td>' . pts_strings::plural_handler($test_count, 'Test') . '</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID']), 'Result') . ' Total</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID'], 'TODAY'), 'Result') . ' Today</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td></tr></table></li></a>';
			}
			while($row = $result->fetchArray());
		}
		$main .= '</ul>
		</div>';
		$main .= '<hr /><h2>Schedule Overview</h2>';
		$week = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
		foreach($week as $i => $day)
		{
			$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, RunAt, RunTargetGroups, RunTargetSystems FROM phoromatic_schedules WHERE AccountID = :account_id AND State >= 1 AND ActiveOn LIKE :active_on ORDER BY RunAt,ActiveOn,Title ASC');
			$stmt->bindValue(':account_id', $_SESSION['AccountID']);
			$stmt->bindValue(':active_on', '%' . $i . '%');
			$result = $stmt->execute();
			$has_matched = false;
			while($row = $result->fetchArray())
				if(!$has_matched)
					$main .= '<h3>' . $day . '</h3>' . PHP_EOL . '<p>';
					$has_matched = true;
				$main .= '<em>' . $row['RunAt'] . '</em> <a href="?schedules/' . $row['ScheduleID'] . '">' . $row['Title'] . '</a>';
				//$main .= $row['RunTargetSystems'] . ' ' . $row['RunTargetGroups'];
				$main .= '<br />';
			if($has_matched)
				$main .= '</p>' . PHP_EOL;
		}
		$main .= '<div class="pts_phoromatic_info_box_area">
				<ul>
				<li><h1>Deactivated Test Schedules</h1></li>';
		$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, Description, RunTargetSystems, RunTargetGroups, RunAt, ActiveOn FROM phoromatic_schedules WHERE AccountID = :account_id AND State < 1 ORDER BY Title ASC');
		$stmt->bindValue(':account_id', $_SESSION['AccountID']);
		$result = $stmt->execute();
		$row = $result->fetchArray();
		if($row == false)
		{
			$main .= '<li class="light" style="text-align: center;">No Schedules Found</li>';
		}
		else
		{
			do
			{
				$stmt_tests = phoromatic_server::$db->prepare('SELECT COUNT(*) AS TestCount FROM phoromatic_schedules_tests WHERE AccountID = :account_id AND ScheduleID = :schedule_id ORDER BY TestProfile ASC');
				$stmt_tests->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt_tests->bindValue(':schedule_id', $row['ScheduleID']);
				$result_tests = $stmt_tests->execute();
				$row_tests = $result_tests->fetchArray();
				$test_count = !empty($row_tests) ? $row_tests['TestCount'] : 0;
				$group_count = empty($row['RunTargetGroups']) ? 0 : count(explode(',', $row['RunTargetGroups']));
				$main .= '<a href="?schedules/' . $row['ScheduleID'] . '"><li>' . $row['Title'] . '<br /><table><tr><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($_SESSION['AccountID'], $row['ScheduleID'])), 'System') . '</td><td>' . pts_strings::plural_handler($group_count, 'Group') . '</td><td>' . pts_strings::plural_handler($test_count, 'Test') . '</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID']), 'Result') . ' Total</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID'], 'TODAY'), 'Result') . ' Today</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td></tr></table></li></a>';
			}
			while($row = $result->fetchArray());
		}
		$main .= '</ul>
		</div>';
		echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
		echo phoromatic_webui_footer();
	Copyright (C) 2014 - 2022, Phoronix Media
	Copyright (C) 2014 - 2022, Michael Larabel
		$search_query = pts_strings::sanitize($_REQUEST['search']);
	Copyright (C) 2008 - 2022, Phoronix Media
	Copyright (C) 2008 - 2022, Michael Larabel
			if(function_exists('ssh2_connect') && isset($_POST['ip']) && isset($_POST['port']) && isset($_POST['password']) && isset($_POST['username']))
			{
				$connection = ssh2_connect($_POST['ip'], $_POST['port']);
				if(ssh2_auth_password($connection, $_POST['username'], $_POST['password']))
				{
					$tmp_local_file = tempnam('/tmp', 'pts-ssh');
					$tmp_remote_file = 'pts-ssh-' . rand(9999, 99999);

					file_put_contents($tmp_local_file, '#!/bin/sh
			if [ -w /var/lib/phoronix-test-suite/ ]
			then
				PHORO_FILE_PATH=/var/lib/phoronix-test-suite/
			elif [ -w $HOME/.phoronix-test-suite/ ]
			then
				PHORO_FILE_PATH=$HOME/.phoronix-test-suite/
			fi

			echo "' . phoromatic_web_socket_server_ip() . '" >> $PHORO_FILE_PATH/phoromatic-servers
			mkdir -p $PHORO_FILE_PATH/modules-data/phoromatic
			echo "' . phoromatic_web_socket_server_addr() . '" > $PHORO_FILE_PATH/modules-data/phoromatic/last-phoromatic-server
			');

					ssh2_scp_send($connection, $tmp_local_file, $tmp_remote_file);
					unlink($tmp_local_file);
					ssh2_exec($connection, 'chmod +x ' . $tmp_remote_file);
					ssh2_exec($connection, './' . $tmp_remote_file);
					ssh2_exec($connection, 'rm' . $tmp_remote_file);
				}
			}
				$stmt->bindValue(':ip_address', pts_strings::simple($_POST['ip_claim']));
				$stmt->bindValue(':mac_address', pts_strings::simple($_POST['mac_claim']));
				$stmt->bindValue(':ip_address', pts_strings::simple($ipc));
				$stmt->bindValue(':mac_address', pts_strings::simple($macc));
	Copyright (C) 2008 - 2022, Phoronix Media
	Copyright (C) 2008 - 2022, Michael Larabel
			phoromatic_quit_if_invalid_input_found(array('system_title', 'system_description', 'system_state'));
			$stmt->bindValue(':title', pts_strings::simple($_POST['system_title']));
			$stmt->bindValue(':description', pts_strings::sanitize($_POST['system_description']));
						$main .= '<a href="?result/' . $test_result_row['PPRID'] . '"><li>' . $test_result_row['Title'] . '<br /><table><tr><td>' . phoromatic_server::system_id_to_name($test_result_row['SystemID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td></tr></table></li></a>';
					phoromatic_quit_if_invalid_input_found(array('new_group'));
					$group = pts_strings::simple($group);
				$remove_group = pts_strings::sanitize($_POST['remove_group']);
				$stmt->bindValue(':group_name', $remove_group);
				$stmt = phoromatic_server::$db->prepare('SELECT SystemID, Groups FROM phoromatic_systems WHERE AccountID = :account_id AND Groups LIKE \'%#' . $remove_group . '#%\'');
					$revised_groups = str_replace('#' . $remove_group . '#', '', $row['Groups']);
				$stmt->bindValue(':inactive_days_before_removal', pts_strings::sanitize($_POST['remove_inactive_systems']));
			$main .= '<hr />
	Copyright (C) 2016 - 2022, Phoronix Media
	Copyright (C) 2016 - 2022, Michael Larabel
		if(!PHOROMATIC_USER_IS_VIEWER)
		{
			$main .= '
			<hr />
			<h2>Create A Schedule</h2>
			<p><a href="?sched">Create a schedule</a> followed by adding tests/suites to run for that schedule on the selected systems.</p>';
		}

		$main .= '<hr /><h2>Current Schedules</h2>';
		$main .= '<div class="pts_phoromatic_info_box_area">
			<ul>
			<li><h1>Active Test Schedules</h1></li>';

		$stmt = phoromatic_server::$db->prepare('SELECT Title, ScheduleID, Description, RunTargetSystems, RunTargetGroups, RunAt, ActiveOn FROM phoromatic_schedules WHERE AccountID = :account_id AND State >= 1 ORDER BY Title ASC');
		$stmt->bindValue(':account_id', $_SESSION['AccountID']);
		$result = $stmt->execute();
		$row = $result->fetchArray();

		if($row == false)
		{
			$main .= '<li class="light" style="text-align: center;">No Schedules Found</li>';
		}
		else
		{
			do
				$stmt_tests = phoromatic_server::$db->prepare('SELECT COUNT(*) AS TestCount FROM phoromatic_schedules_tests WHERE AccountID = :account_id AND ScheduleID = :schedule_id ORDER BY TestProfile ASC');
				$stmt_tests->bindValue(':account_id', $_SESSION['AccountID']);
				$stmt_tests->bindValue(':schedule_id', $row['ScheduleID']);
				$result_tests = $stmt_tests->execute();
				$row_tests = $result_tests->fetchArray();
				$test_count = !empty($row_tests) ? $row_tests['TestCount'] : 0;

				$group_count = empty($row['RunTargetGroups']) ? 0 : count(explode(',', $row['RunTargetGroups']));
				$main .= '<a href="?schedules/' . $row['ScheduleID'] . '"><li>' . $row['Title'] . '<br /><table><tr><td>' . pts_strings::plural_handler(count(phoromatic_server::systems_associated_with_schedule($_SESSION['AccountID'], $row['ScheduleID'])), 'System') . '</td><td>' . pts_strings::plural_handler($group_count, 'Group') . '</td><td>' . pts_strings::plural_handler($test_count, 'Test') . '</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID']), 'Result') . ' Total</td><td>' . pts_strings::plural_handler(phoromatic_results_for_schedule($row['ScheduleID'], 'TODAY'), 'Result') . ' Today</td><td><strong>' . phoromatic_schedule_activeon_string($row['ActiveOn'], $row['RunAt']) . '</strong></td></tr></table></li></a>';
			while($row = $result->fetchArray());
		}

		$main .= '</ul>
		</div>';
		$stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_benchmark_tickets WHERE AccountID = :account_id AND State >= 0 AND TicketIssueTime > :time_cutoff ORDER BY TicketIssueTime DESC LIMIT 30');
		$stmt->bindValue(':account_id', $_SESSION['AccountID']);
		$stmt->bindValue(':time_cutoff', (time() - (60 * 60 * 24 * 14)));
		$result = $stmt->execute();
		$right = '<ul><li>Benchmark Tickets</li>';
		if($result)
		{
				<ul>
				<li><h1>Active Benchmark Tickets</h1></li>';
			$row = $result->fetchArray();
			if(!empty($row))
			{
				do
					$main .= '<a href="?benchmark/' . $row['TicketID'] . '"><li>' . $row['Title'] . '</li></a>';
				while($row = $result->fetchArray());
			else
				$main .= '<li class="light" style="text-align: center;">No Tickets Found</li>';	
		}
		$main .= '</ul>
		</div>';

		if(!PHOROMATIC_USER_IS_VIEWER)
		{
			$main .= '
			<hr />
			<h2>Run A Benchmark</h2>
			<p><a href="?benchmark">Run a benchmark</a> is the area where you can run a one-time benchmark on selected system(s) and is also where to go for setting up a stress-run benchmark.</p>
			<hr />
			<h2>Create A Suite</h2>
			<p><a href="?build_suite">Build a suite</a>, which is a collection of predefined test profiles.</p>
			<hr />
			<h2>View Local Suites</h2>
			<p><a href="?local_suites">See local suites</a> available for your benchmarking needs.</p>';
		}

		echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
		echo phoromatic_webui_footer();
	Copyright (C) 2014 - 2022, Phoronix Media
	Copyright (C) 2014 - 2022, Michael Larabel
			phoromatic_quit_if_invalid_input_found(array('group_name'));
			$stmt->bindValue(':group_name', pts_strings::simple($_POST['group_name']));
			phoromatic_quit_if_invalid_input_found(array('username', 'email'));
		$group_name = phoromatic_server::account_id_to_group_name($_SESSION['AccountID']);
	Copyright (C) 2008 - 2022, Phoronix Media
	Copyright (C) 2008 - 2022, Michael Larabel
			phoromatic_quit_if_invalid_input_found(array('register_username', 'register_email'));
			phoromatic_quit_if_invalid_input_found(array('username'));
			phoromatic_quit_if_invalid_input_found(array('username'));
				$box .= '<p id="register_link"><a onclick="javascript:document.getElementById(\'register\').style.display = \'block\'; document.getElementById(\'register_link\').style.display = \'none\';">Create A New Account</a></p>
	Copyright (C) 2013 - 2022, Phoronix Media
	Copyright (C) 2013 - 2022, Michael Larabel
function phoromatic_quit_if_invalid_input_found($input_keys = null)
{
	if(empty($input_keys))
	{
		// Check them all if not being selective about what keys to check
		$input_keys = array_keys($_REQUEST);
	}
	// backup as to sanitization and stripping elsewhere, safeguard namely check for things like < for fields that shouldn't have it
	// plus a few simple backups as safeguards for words that really have no legit relevance within Phoromatic...

	foreach(array('<', 'document.write', '../', 'onerror', 'onload', 'alert(') as $invalid_string)
	{
		foreach($input_keys as $key)
		{
			if(isset($_REQUEST[$key]) && !empty($_REQUEST[$key]))
			{
				foreach(pts_arrays::to_array($_REQUEST[$key]) as $val_to_check)
				{
					if(stripos($val_to_check, $invalid_string) !== false)
					{
						echo '<strong>Exited due to invalid input ( ' . $invalid_string . ') attempted:</strong> ' . htmlspecialchars($val_to_check);
						exit;
					}
				}
			}
		}
	}
}
		$group_name = phoromatic_server::account_id_to_group_name($_SESSION['AccountID']);
	if(isset($_POST[$name]))
	{
		phoromatic_quit_if_invalid_input_found(array($name));
	}

		$group_name = phoromatic_server::account_id_to_group_name($_SESSION['AccountID']);
		<h2>' . $description . '</h2>';
	$stmt->bindValue(':title', pts_strings::simple($HOSTNAME));
	$stmt->bindValue(':client_hardware', pts_strings::simple($CLIENT_HARDWARE));
	Copyright (C) 2008 - 2022, Phoronix Media
	Copyright (C) 2008 - 2022, Michael Larabel
				$system_name = phoromatic_server::system_id_to_name($row['SystemID'], $row['AccountID']);
				$system_name = phoromatic_server::system_id_to_name($row['SystemID'], $row['AccountID']) . ': ' . $row['Trigger'];
				$system_name = phoromatic_server::system_id_to_name($row['SystemID'], $row['AccountID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
	$embed = new pts_result_viewer_embed($result_file);
	$embed->show_html_result_table(false);
	$embed->show_test_metadata_helper(false);
	$embed->include_page_print_only_helpers(false);
	$main .= $embed->get_html();
		$main .= '<a onclick=""><li id="result_select_' . $test_result_row['PPRID'] . '"><input type="checkbox" id="result_compare_checkbox_' . $test_result_row['PPRID'] . '" onclick="javascript:phoromatic_checkbox_toggle_result_comparison(\'' . $test_result_row['PPRID'] . '\');" onchange="return false;"></input> <span onclick="javascript:phoromatic_window_redirect(\'public.php?ut=' . $test_result_row['PPRID'] . '\');">' . $test_result_row['Title'] . '</span><br /><table><tr><td>' . phoromatic_server::system_id_to_name($test_result_row['SystemID'], $test_result_row['AccountID']) . '</td><td>' . phoromatic_user_friendly_timedate($test_result_row['UploadTime']) .  '</td><td>' . $test_result_row['TimesViewed'] . ' Times Viewed</td></table></li></a>';