CVE-2022-0157: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: phoronix-test-suite is vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
CWE description: 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.
CVSS v3 base score: 5.4
Published: 2022-01-10T16:15Z
Repository: https://github.com/phoronix-test-suite/phoronix-test-suite
Language: PHP
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 date: 2022-01-08 04:47:20 -0600
Commit message: phodevi: Input sanitization updates for Phoromatic Server

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

Diff: diff --git a/ChangeLog b/ChangeLog
index a617b231c..db6805001 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,11 @@
 PHORONIX TEST SUITE CHANGE-LOG
 
+Phoronix Test Suite (Git)
+
+phodevi: Input sanitization updates for Phoromatic Server
+
 Phoronix Test Suite 10.8.0
 25 December 2021
 
 pts-core: Remaining PHP 8.1 warnings/fixes addressed
 pts-core: Various macOS 12 warning fixes
diff --git a/pts-core/objects/pts_env.php b/pts-core/objects/pts_env.php
index 5d53ddaa0..ba88efab7 100644
--- a/pts-core/objects/pts_env.php
+++ b/pts-core/objects/pts_env.php
@@ -648,11 +648,11 @@ class pts_env
 					// TODO add more validation handling checks... then again, PTS client has its own validation of the env vars
 					$v = strip_tags($_REQUEST[$var]);
 				}
 				if(!empty($v) && $v !== 0)
 				{
-					$posted[$var] = $v;
+					$posted[$var] = pts_strings::sanitize($v);
 				}
 			}
 		}
 		return $posted;
 	}
diff --git a/pts-core/objects/pts_phoroql.php b/pts-core/objects/pts_phoroql.php
index 0ef49ed03..1d94eb3b6 100644
--- a/pts-core/objects/pts_phoroql.php
+++ b/pts-core/objects/pts_phoroql.php
@@ -20,11 +20,11 @@
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
 class pts_phoroql
 {
-	public static function evaluate_search_tree($tree, $join = 'AND', $callback)
+	public static function evaluate_search_tree($tree, $join = 'AND', $callback = '')
 	{
 		$matches = false;
 
 		foreach($tree as $i => $el)
 		{
diff --git a/pts-core/objects/pts_result_viewer_embed.php b/pts-core/objects/pts_result_viewer_embed.php
index 060000d65..a7f90a19d 100644
--- a/pts-core/objects/pts_result_viewer_embed.php
+++ b/pts-core/objects/pts_result_viewer_embed.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2018 - 2020, Phoronix Media
-	Copyright (C) 2018 - 2020, Michael Larabel
+	Copyright (C) 2018 - 2022, Phoronix Media
+	Copyright (C) 2018 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -117,12 +117,12 @@ class pts_result_viewer_embed
 		$result_file->avoid_duplicate_identifiers();
 		$extra_attributes = null;
 		$html_options = self::get_html_options_markup($result_file, $_REQUEST, $this->result_public_id, $this->can_delete_results);
 		self::process_request_to_attributes($_REQUEST, $result_file, $extra_attributes);
 		$PAGE .= self::get_html_sort_bar($result_file, $_REQUEST);
-		$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 .= '<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="result-settings">';
 		if($this->can_modify_results)
 		{
 			$PAGE .= ' <input type="submit" id="save_result_file_meta_button" value="Save" onclick="javascript:save_result_file_meta(\'' . $this->result_public_id . '\'); return false;" style="display: none;">';
 			$PAGE .= ' <input type="submit" id="edit_result_file_meta_button" value="Edit" onclick="javascript:edit_result_file_meta(); return false;">';
@@ -410,12 +410,10 @@ class pts_result_viewer_embed
 						}
 						$PAGE .= '</div>';
 				}
 			}
 
-			// $PAGE .= $res . '<br />';
-
 			//
 			// DISPLAY LOGS
 			//
 			$PAGE .= $this->result_object_to_error_report($result_file, $result_object, $i);
 			$button_area = null;
@@ -428,11 +426,10 @@ class pts_result_viewer_embed
 			if($result_file->get_install_log_for_test($result_object->test_profile, -2))
 			{
 				$button_area .= ' <button onclick="javascript:display_install_logs_for_result_object(\'' . $this->result_public_id . '\', \'' . $i . '\'); return false;">View Test Installation Logs</button> ';
 			}
 
-
 			//
 			// EDITING / DELETE OPTIONS
 			//
 
 			if($this->can_delete_results && !$result_object->dynamically_generated)
@@ -450,16 +447,16 @@ class pts_result_viewer_embed
 					$button_area .= ' <button onclick="javascript:display_add_annotation_for_result_object(\'' . $this->result_public_id . '\', \'' . $i . '\', this); return false;">Add Annotation</button> ';
 					$PAGE .= ' <div id="annotation_area_' . $i . '" style="display: none;"> <form action="#" onsubmit="javascript:add_annotation_for_result_object(\'' . $this->result_public_id . '\', \'' . $i . '\', this); return false;"><textarea rows="4" cols="50" placeholder="Add Annotation..." name="annotation"></textarea><br /><input type="submit" value="Add Annotation"></form></div>';
 				}
 				else
 				{
-					$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 .= '<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;">';
 				}
 			}
 			else
 			{
-				$PAGE .= '<p class="mini">' . $result_object->get_annotation() . '</p>';
+				$PAGE .= '<p class="mini">' . pts_strings::sanitize($result_object->get_annotation()) . '</p>';
 			}
 			if($button_area != null)
 			{
 				$PAGE .= '<p>' . $button_area . '</p>';
 			}
@@ -1021,11 +1018,10 @@ class pts_result_viewer_embed
 				exit;
 		}
 	}
 	public static function process_result_modify_pre_render(&$result_file, $can_modify_results = false, $can_delete_results = false)
 	{
-
 		if(!isset($_REQUEST['modify']) || ($can_modify_results == false && $can_delete_results == false))
 		{
 			return;
 		}
 
diff --git a/pts-core/phoromatic/pages/phoromatic_account_activity.php b/pts-core/phoromatic/pages/phoromatic_account_activity.php
index b35a8ab90..3520d0742 100644
--- a/pts-core/phoromatic/pages/phoromatic_account_activity.php
+++ b/pts-core/phoromatic/pages/phoromatic_account_activity.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_account_activity implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Account Activity';
@@ -35,13 +34,11 @@ class phoromatic_account_activity implements pts_webui_interface
 	{
 		return true;
 	}
 	public static function render_page_process($PATH)
 	{
-
 		$main = '<h1>Recent Account Activity</h1>';
-
 		$stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_activity_stream WHERE AccountID = :account_id ORDER BY ActivityTime DESC');
 		$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 		$result = $stmt->execute();
 		$row = $result->fetchArray();
 		$prev_date = null;
@@ -120,11 +117,10 @@ class phoromatic_account_activity implements pts_webui_interface
 
 					if($id_link_format != null)
 						$main .= ': ' . $id_link_format;
 
 					$main .= '<br />' . PHP_EOL;
-
 				}
 
 				//$main .= '<p>' .  $row['ActivityCreator'] . ' ' . $row['ActivityCreatorType'] . ' ' . $row['ActivityEvent'] . ' ' . $row['ActivityEventID'] . ' ' . $row['ActivityEventType'] . '</p>';
 			}
 			while($row = $result->fetchArray());
diff --git a/pts-core/phoromatic/pages/phoromatic_admin.php b/pts-core/phoromatic/pages/phoromatic_admin.php
index dec2a0e15..488307fdd 100644
--- a/pts-core/phoromatic/pages/phoromatic_admin.php
+++ b/pts-core/phoromatic/pages/phoromatic_admin.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2014 - 2018, Phoronix Media
-	Copyright (C) 2014 - 2018, Michael Larabel
+	Copyright (C) 2014 - 2022, Phoronix Media
+	Copyright (C) 2014 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_admin implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Phoromatic Root Administrator';
@@ -69,14 +68,16 @@ class phoromatic_admin implements pts_webui_interface
 				$main .= '<h2>Updated Password For Account: ' . $_POST['change_user_password'] . '</h2>';
 			}
 		}
 		else if(isset($_POST['register_username']) && isset($_POST['register_password']) && isset($_POST['register_password_confirm']) && isset($_POST['register_email']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('register_username', 'register_password', 'register_password_confirm', 'register_email', 'seed_accountid'));
 			$new_account = create_new_phoromatic_account($_POST['register_username'], $_POST['register_password'], $_POST['register_password_confirm'], $_POST['register_email'], (isset($_POST['seed_accountid']) ? $_POST['seed_accountid'] : null));
 		}
 		else if(isset($_POST['email_all_subject']) && isset($_POST['email_all_message']) && !empty($_POST['email_all_message']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('email_all_subject', 'email_all_message'));
 			$stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_users ORDER BY UserName ASC');
 			$result = $stmt->execute();
 
 			while($row = $result->fetchArray())
 			{
@@ -205,11 +206,10 @@ class phoromatic_admin implements pts_webui_interface
 		<sup>2</sup> Passwords shall be at least six characters long.<br />
 		<sup>3</sup> A valid email address is required for notifications, password reset, and other verification purposes.<br />
 		<sup>4</sup> The account ID field is optional and is used to pre-seed the account identifier for advanced purposes. The field must be six characters. Leave this field blank if you are unsure.<br />
 						</p>';
 
-
 		//
 		$server_log = explode(PHP_EOL, file_get_contents(getenv('PTS_PHOROMATIC_LOG_LOCATION')));
 		foreach($server_log as $i => $line_item)
 		{
 			if(strpos($line_item, '[200]') !== false || strpos($line_item, '[302]') !== false)
diff --git a/pts-core/phoromatic/pages/phoromatic_admin_config.php b/pts-core/phoromatic/pages/phoromatic_admin_config.php
index ebb3a4c1f..780ef5adc 100644
--- a/pts-core/phoromatic/pages/phoromatic_admin_config.php
+++ b/pts-core/phoromatic/pages/phoromatic_admin_config.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_admin_config implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Phoromatic Server Configuration';
diff --git a/pts-core/phoromatic/pages/phoromatic_admin_data.php b/pts-core/phoromatic/pages/phoromatic_admin_data.php
index be5f2d5c5..7ccc7179b 100644
--- a/pts-core/phoromatic/pages/phoromatic_admin_data.php
+++ b/pts-core/phoromatic/pages/phoromatic_admin_data.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_admin_data implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Phoromatic Server Data';
@@ -142,21 +141,20 @@ class phoromatic_admin_data implements pts_webui_interface
 		$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime, TimesViewed, AccountID, UploadID FROM phoromatic_results ORDER BY UploadTime DESC LIMIT 100');
 		$test_result_result = $stmt->execute();
 		$results = 0;
 		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(\'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 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>';
 			$results++;
 
 		}
 		if($results == 0)
 		{
 					$main .= '<li class="light" style="text-align: center;">No Results Found</li>';
 		}
 		$main .= '</ul></div>';
 		$main .= '</div>';
-
 		$main .= '<hr /><h1>Schedules</h1>';
 		$main .= '<h2>Active Test Schedules</h2>';
 		$main .= '<div class="pts_phoromatic_info_box_area">
 				<ul>
 					<li><h1>Active Test Schedules</h1></li>';
@@ -171,16 +169,15 @@ class phoromatic_admin_data implements pts_webui_interface
 					else
 					{
 						do
 						{
 
-							$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_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>';
 						}
 						while($row = $result->fetchArray());
 					}
 		$main .= '</ul></div>';
-
 		$main .= '<hr /><h2>Inactive Test 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, AccountID FROM phoromatic_schedules WHERE State < 1 ORDER BY Title ASC');
@@ -194,11 +191,11 @@ class phoromatic_admin_data implements pts_webui_interface
 					else
 					{
 						do
 						{
 
-							$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_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>';
 						}
 						while($row = $result->fetchArray());
 					}
 		$main .= '</ul></div>';
 
@@ -217,11 +214,11 @@ class phoromatic_admin_data implements pts_webui_interface
 					else
 					{
 						do
 						{
 
-							$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['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>';
 						}
 						while($row = $result->fetchArray());
 					}
 		$main .= '</ul></div>';
 
@@ -243,21 +240,20 @@ class phoromatic_admin_data implements pts_webui_interface
 					}
 					else
 					{
 						do
 						{
-							$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_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>';
 							$active_system_count++;
 						}
 						while($row = $result->fetchArray());
 					}
 
 
 			$main .= '</ul></div>';
 			$main .= '<h2>Inactive Systems</h2>
 			<div class="pts_phoromatic_info_box_area">
-
 					<ul>
 						<li><h1>Inactive Systems</h1></li>';
 
 					$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, LocalIP, CurrentTask, LastCommunication, EstimatedTimeForTask, TaskPercentComplete, AccountID FROM phoromatic_systems WHERE State < 0 ORDER BY LastCommunication DESC');
 					$result = $stmt->execute();
@@ -270,11 +266,11 @@ class phoromatic_admin_data implements pts_webui_interface
 					}
 					else
 					{
 						do
 						{
-							$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_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>';
 							$active_system_count++;
 						}
 						while($row = $result->fetchArray());
 					}
 
diff --git a/pts-core/phoromatic/pages/phoromatic_benchmark.php b/pts-core/phoromatic/pages/phoromatic_benchmark.php
index 5feeb2747..689ee13c7 100644
--- a/pts-core/phoromatic/pages/phoromatic_benchmark.php
+++ b/pts-core/phoromatic/pages/phoromatic_benchmark.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2015 - 2021, Phoronix Media
-	Copyright (C) 2015 - 2021, Michael Larabel
+	Copyright (C) 2015 - 2022, Phoronix Media
+	Copyright (C) 2015 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_benchmark implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'One-Time Benchmark Run';
@@ -139,22 +138,20 @@ class phoromatic_benchmark implements pts_webui_interface
 						}
 					}
 				}
 
 				$main .= '</ol>';
-
 				if(!empty($row['EnvironmentVariables']))
 				{
 					$main .= '<hr /><h1>Environment</h1><ol>';
 
 					foreach(explode(';', $row['EnvironmentVariables']) as $env)
 					{
 						$main .= '<li><strong>' . $env . '</strong></li>';
 					}
 					$main .= '</ol>';
 				}
-
 				$main .= '<hr /><h1>Ticket Payload</h1>';
 				$main .= '<p>This ticket runs the <strong>' . $row['SuiteToRun'] . '</strong> test suite:</p>';
 				$main .= '<div style="max-height: 400px; overflow-y: scroll;">';
 				$xml_path = phoromatic_server::find_suite_file($_SESSION['AccountID'], $row['SuiteToRun']);
 				if(is_file($xml_path))
@@ -234,11 +231,11 @@ class phoromatic_benchmark implements pts_webui_interface
 					$stmt->bindValue(':ticket_id', $PATH[0]);
 					$test_result_result = $stmt->execute();
 					$results = 0;
 					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>';
+						$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)
 					{
@@ -336,14 +333,12 @@ class phoromatic_benchmark implements pts_webui_interface
 				{
 					header('Location: ?benchmark/' . $ticket_id);
 				}
 			}
 
-			$main = '
-			<h2>' . ($is_new ? 'Create' : 'Edit') . ' A Benchmark</h2>
+			$main = '<h2>' . ($is_new ? 'Create' : 'Edit') . ' A Benchmark</h2>
 			<p>This page allows you to run a test suite -- consisting of a single or multiple test suites -- on a given set/group of systems right away at their next earliest possibility. This benchmark mode is an alternative to the <a href="?schedules">benchmark schedules</a> for reptitive/routine testing.</p>';
-
 			$local_suites = array();
 			foreach(pts_file_io::glob(phoromatic_server::phoromatic_account_suite_path($_SESSION['AccountID']) . '*/suite-definition.xml') as $xml_path)
 			{
 					$id = basename(dirname($xml_path));
 					$test_suite = new pts_test_suite($xml_path);
@@ -382,11 +377,10 @@ class phoromatic_benchmark implements pts_webui_interface
 
 				$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID FROM phoromatic_systems WHERE AccountID = :account_id AND State >= 0 ORDER BY Title ASC');
 				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 				$result = $stmt->execute();
 
-
 				if(!$is_new)
 				{
 					$e_schedule['RunTargetSystems'] = explode(',', $e_schedule['RunTargetSystems']);
 					$e_schedule['RunTargetGroups'] = explode(',', $e_schedule['RunTargetGroups']);
 				}
diff --git a/pts-core/phoromatic/pages/phoromatic_build_suite.php b/pts-core/phoromatic/pages/phoromatic_build_suite.php
index ec2d907bb..6c28e56fc 100644
--- a/pts-core/phoromatic/pages/phoromatic_build_suite.php
+++ b/pts-core/phoromatic/pages/phoromatic_build_suite.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2015 - 2018, Phoronix Media
-	Copyright (C) 2015 - 2018, Michael Larabel
+	Copyright (C) 2015 - 2022, Phoronix Media
+	Copyright (C) 2015 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_build_suite implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Build Custom Test Suite';
@@ -37,10 +36,11 @@ class phoromatic_build_suite implements pts_webui_interface
 	}
 	public static function render_page_process($PATH)
 	{
 		if(isset($_POST['suite_title']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('suite_title', 'test_add', 'suite_version', 'suite_description'));
 			if(strlen($_POST['suite_title']) < 3)
 			{
 				echo '<h2>Suite title must be at least three characters.</h2>';
 			}
 
@@ -56,10 +56,11 @@ class phoromatic_build_suite implements pts_webui_interface
 
 				foreach($_POST as $i => $v)
 				{
 					if(strpos($i, $test_prefix) !== false && substr($i, -9) != '_selected')
 					{
+						phoromatic_quit_if_invalid_input_found(array($i, $i . '_selected'));
 						if(strpos($v, '||') !== false)
 						{
 							$opts = explode('||', $v);
 							$a = array();
 							$d = array();
@@ -126,11 +127,10 @@ class phoromatic_build_suite implements pts_webui_interface
 			echo '<h2>Saved As ' . $suite_id . '</h2>';
 		}
 		echo phoromatic_webui_header_logged_in();
 		$main = '<h1>Local Suites</h1><p>Find already created local test suites by your account/group via the <a href="/?local_suites">local suites</a> page.</p>';
 
-
 		if(!PHOROMATIC_USER_IS_VIEWER)
 		{
 			$suite = null;
 			if(isset($PATH[0]))
 			{
@@ -193,11 +193,10 @@ class phoromatic_build_suite implements pts_webui_interface
 			}
 			$main .= '</select>';
 			$main .= pts_web_embed::cookie_checkbox_option_helper('list_show_all_test_versions', 'Show all available test profile versions.');
 			$main .= '<p align="right"><input name="submit" value="' . ($suite->get_title() != null ? 'Edit' : 'Create') .' Suite" type="submit" onclick="return pts_rmm_validate_suite();" /></p>';
 		}
-
 		echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
 		echo phoromatic_webui_footer();
 	}
 }
 
diff --git a/pts-core/phoromatic/pages/phoromatic_caches.php b/pts-core/phoromatic/pages/phoromatic_caches.php
index 5bddc1b0b..53cdb482a 100644
--- a/pts-core/phoromatic/pages/phoromatic_caches.php
+++ b/pts-core/phoromatic/pages/phoromatic_caches.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_caches implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Download Caches';
diff --git a/pts-core/phoromatic/pages/phoromatic_component_table.php b/pts-core/phoromatic/pages/phoromatic_component_table.php
index ca3018ba4..124be3811 100644
--- a/pts-core/phoromatic/pages/phoromatic_component_table.php
+++ b/pts-core/phoromatic/pages/phoromatic_component_table.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_component_table implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'System Component Table';
diff --git a/pts-core/phoromatic/pages/phoromatic_create_test.php b/pts-core/phoromatic/pages/phoromatic_create_test.php
index 6befd00c4..056f19aa8 100644
--- a/pts-core/phoromatic/pages/phoromatic_create_test.php
+++ b/pts-core/phoromatic/pages/phoromatic_create_test.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_create_test implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Create Test Profile';
@@ -87,11 +86,10 @@ class phoromatic_create_test implements pts_webui_interface
 			if($passed)
 			{
 				pts_validation::generate_test_profile_file_templates($tp_identifier, $tp_path);
 				header('Location: /?create_test/' . $tp_identifier . '-' . $tp->get_test_profile_version());
 			}
-
 		}
 		if(isset($_POST['dc_select_item']))
 		{
 			$to_add = false;
 
@@ -139,11 +137,10 @@ class phoromatic_create_test implements pts_webui_interface
 					header('Location: /?tests');
 				}
 			}
 		}
 
-
 		return true;
 	}
 	public static function render_page_process($PATH)
 	{
 		$main = null;
@@ -151,11 +148,10 @@ class phoromatic_create_test implements pts_webui_interface
 		{
 			goto RENDER_PAGE;
 		}
 
 		$identifier_item = isset($PATH[1]) ? $PATH[0] . '/' . $PATH[1] : false;
-
 		if($identifier_item && pts_test_profile::is_test_profile($identifier_item))
 		{
 			$tp = new pts_test_profile($identifier_item);
 			$main .= '<h1>Test Profile Editor: ' . $tp->get_identifier() . '</h1>';
 
@@ -173,11 +169,10 @@ class phoromatic_create_test implements pts_webui_interface
 					$main .= '</select> <input type="submit" value="Add File" /></form>';
 				}
 			}
 
 			$main .= '<form action="?create_test/' . $tp->get_identifier() . '" name="create_test" id="create_test" method="post" enctype="multipart/form-data"><input type="hidden" name="tp_update" value="' . $tp->get_identifier() . '" />';
-
 			foreach(pts_file_io::glob($tp->get_resource_dir() . '/*') as $file)
 			{
 				$file_name = basename($file);
 				$contents = file_get_contents($file);
 				$extension = substr($file_name, strrpos($file_name, '.') + 1);
diff --git a/pts-core/phoromatic/pages/phoromatic_dashboard.php b/pts-core/phoromatic/pages/phoromatic_dashboard.php
index dbc3fcd1a..ff395c3e2 100644
--- a/pts-core/phoromatic/pages/phoromatic_dashboard.php
+++ b/pts-core/phoromatic/pages/phoromatic_dashboard.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_dashboard implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'System Dashboard';
@@ -36,11 +35,10 @@ class phoromatic_dashboard implements pts_webui_interface
 		return true;
 	}
 	public static function render_page_process($PATH)
 	{
 		echo phoromatic_webui_header_logged_in();
-
 		$stmt = phoromatic_server::$db->prepare('SELECT * FROM phoromatic_systems WHERE AccountID = :account_id AND State >= 0 ORDER BY LastCommunication DESC');
 		$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 		$result = $stmt->execute();
 		echo '<script type="text/javascript"> setInterval(function() { window.location.reload(); }, 79000); </script>';
 		echo '<div style="margin: 10px 0 30px; clear: both; padding-bottom: 40px;">';
diff --git a/pts-core/phoromatic/pages/phoromatic_local_suites.php b/pts-core/phoromatic/pages/phoromatic_local_suites.php
index 39586a8aa..9ec19f6ef 100644
--- a/pts-core/phoromatic/pages/phoromatic_local_suites.php
+++ b/pts-core/phoromatic/pages/phoromatic_local_suites.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_local_suites implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Local Test Suite';
@@ -58,13 +57,13 @@ class phoromatic_local_suites implements pts_webui_interface
 		{
 			$suite_count++;
 			$id = basename(dirname($xml_path));
 			$test_suite = new pts_test_suite($xml_path);
 
-			$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>';
+			$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>';
 			if(!PHOROMATIC_USER_IS_VIEWER)
 			{
 				$main .= '<p><a href="?build_suite/' . $id . '">Edit Suite</a> - <a href="?local_suites/delete/' . $id . '">Delete Suite</a></p>';
 			}
 			$main .= '<div style="max-height: 400px; width: 80%; overflow-y: scroll;">';
diff --git a/pts-core/phoromatic/pages/phoromatic_logs.php b/pts-core/phoromatic/pages/phoromatic_logs.php
index d6d709fd5..c2bafc364 100644
--- a/pts-core/phoromatic/pages/phoromatic_logs.php
+++ b/pts-core/phoromatic/pages/phoromatic_logs.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_logs implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Logs';
diff --git a/pts-core/phoromatic/pages/phoromatic_main.php b/pts-core/phoromatic/pages/phoromatic_main.php
index 3e1999f68..adcc9f1e6 100644
--- a/pts-core/phoromatic/pages/phoromatic_main.php
+++ b/pts-core/phoromatic/pages/phoromatic_main.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_main implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Main';
@@ -154,17 +153,15 @@ class phoromatic_main implements pts_webui_interface
 		$main .= '<hr /><h2>Today\'s Scheduled Tests</h2>';
 
 		foreach($schedules_today as &$row)
 		{
 			$systems_for_schedule = phoromatic_server::systems_associated_with_schedule($_SESSION['AccountID'], $row['ScheduleID']);
-
 			$extra_css = null;
 			if(empty($systems_for_schedule))
 			{
 				$extra_css = ' opacity: 0.4;';
 			}
-
 			list($h, $m) = explode('.', $row['RunAt']);
 
 			$main .= '<div style="' . $extra_css . '" class="phoromatic_overview_box">';
 			$main .= '<h1><a href="?schedules/' . $row['ScheduleID'] . '">' . $row['Title'] . '</a></h1>';
 
@@ -213,11 +210,10 @@ class phoromatic_main implements pts_webui_interface
 			}
 
 			$main .= '</div>';
 		}
 		$main .= '</div>';
-
 		$main .= '</div>';
 
 		echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
 		//echo phoromatic_webui_main($main, phoromatic_webui_right_panel_logged_in());
 		echo phoromatic_webui_footer();
diff --git a/pts-core/phoromatic/pages/phoromatic_maintenance_table.php b/pts-core/phoromatic/pages/phoromatic_maintenance_table.php
index 14b7cf928..6cda31da2 100644
--- a/pts-core/phoromatic/pages/phoromatic_maintenance_table.php
+++ b/pts-core/phoromatic/pages/phoromatic_maintenance_table.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_maintenance_table implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'System Maintenance Table';
@@ -87,14 +86,11 @@ class phoromatic_maintenance_table implements pts_webui_interface
 					$c = substr($c, 0, $x);
 				}
 
 				$main .= '<td>' . $c . '</td>';
 			}
-
 			$main .= '</tr>';
-
-
 		}
 		$main .= '</table></div>';
 
 		$right = null;
 		echo phoromatic_webui_main($main, phoromatic_webui_right_panel_logged_in($right));
diff --git a/pts-core/phoromatic/pages/phoromatic_password.php b/pts-core/phoromatic/pages/phoromatic_password.php
index bdb052bc5..12525cce7 100644
--- a/pts-core/phoromatic/pages/phoromatic_password.php
+++ b/pts-core/phoromatic/pages/phoromatic_password.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_password implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Password Management';
diff --git a/pts-core/phoromatic/pages/phoromatic_r_add_test_build_suite_details.php b/pts-core/phoromatic/pages/phoromatic_r_add_test_build_suite_details.php
index e3753e17c..4aa82a1ad 100644
--- a/pts-core/phoromatic/pages/phoromatic_r_add_test_build_suite_details.php
+++ b/pts-core/phoromatic/pages/phoromatic_r_add_test_build_suite_details.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2014 - 2021, Phoronix Media
-	Copyright (C) 2014 - 2021, Michael Larabel
+	Copyright (C) 2014 - 2022, Phoronix Media
+	Copyright (C) 2014 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_r_add_test_build_suite_details implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return '';
@@ -35,10 +34,11 @@ class phoromatic_r_add_test_build_suite_details implements pts_webui_interface
 	{
 		return true;
 	}
 	public static function render_page_process($PATH)
 	{
+		phoromatic_quit_if_invalid_input_found(array('tp'));
 		$test_profile = new pts_test_profile($_GET['tp']);
 		$name = $test_profile->get_title();
 		$description = $test_profile->get_description();
 
 		$tid = 't_' . rand(1, 20000);
diff --git a/pts-core/phoromatic/pages/phoromatic_r_basic_suite_details.php b/pts-core/phoromatic/pages/phoromatic_r_basic_suite_details.php
index 78311d36c..6a8323ca9 100644
--- a/pts-core/phoromatic/pages/phoromatic_r_basic_suite_details.php
+++ b/pts-core/phoromatic/pages/phoromatic_r_basic_suite_details.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_r_basic_suite_details implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return '';
diff --git a/pts-core/phoromatic/pages/phoromatic_result.php b/pts-core/phoromatic/pages/phoromatic_result.php
index b0dfa9c12..957fc981e 100644
--- a/pts-core/phoromatic/pages/phoromatic_result.php
+++ b/pts-core/phoromatic/pages/phoromatic_result.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2008 - 2021, Phoronix Media
-	Copyright (C) 2008 - 2021, Michael Larabel
+	Copyright (C) 2008 - 2022, Phoronix Media
+	Copyright (C) 2008 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -119,11 +119,11 @@ class phoromatic_result implements pts_webui_interface
 			}
 
 			$result_file_title = null;
 			if(count($system_types) == 1)
 			{
-				$result_file_title = phoromatic_system_id_to_name($system_types[0]) . ' Tests';
+				$result_file_title = phoromatic_server::system_id_to_name($system_types[0]) . ' Tests';
 			}
 
 			if(!empty($tickets) && $tickets[0] != null)
 			{
 				$system_name_format = 'ORIGINAL_DATA';
@@ -178,23 +178,23 @@ class phoromatic_result implements pts_webui_interface
 					{
 						case 'ORIGINAL_DATA':
 							$system_name = null;
 							break;
 						case 'SYSTEM_NAME':
-							$system_name = phoromatic_system_id_to_name($row['SystemID']);
+							$system_name = phoromatic_server::system_id_to_name($row['SystemID']);
 							break;
 						case 'TRIGGER':
 							$system_name = $row['Trigger'];
 							break;
 						case 'TRIGGER_AND_SYSTEM':
-							$system_name = phoromatic_system_id_to_name($row['SystemID']) . ': ' . $row['Trigger'];
+							$system_name = phoromatic_server::system_id_to_name($row['SystemID']) . ': ' . $row['Trigger'];
 							break;
 						case 'SYSTEM_AND_SCHEDULE':
 							$system_name = phoromatic_schedule_id_to_name($row['ScheduleID']) . ': ' . $row['Trigger'];
 							break;
 						default:
-							$system_name = phoromatic_system_id_to_name($row['SystemID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
+							$system_name = phoromatic_server::system_id_to_name($row['SystemID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
 					}
 
 					if($system_name == null)
 					{
 						$rf = new pts_result_file($composite_xml);
@@ -203,15 +203,15 @@ class phoromatic_result implements pts_webui_interface
 						{
 							$system_name = $identifiers[0];
 						}
 					}
 
-					if(($replacement = phoromatic_system_id_to_name($row['SystemID'])) != null)
+					if(($replacement = phoromatic_server::system_id_to_name($row['SystemID'])) != null)
 					{
 						$system_name = str_replace('.SYSTEM', $replacement, $system_name);
 					}
-					if(($replacement = phoromatic_account_id_to_group_name($row['AccountID'])) != null)
+					if(($replacement = phoromatic_server::account_id_to_group_name($row['AccountID'])) != null)
 					{
 						$system_name = str_replace('.GROUP', $replacement, $system_name);
 					}
 					$system_variables = explode(';', phoromatic_server::system_id_variables($row['SystemID'], $row['AccountID']));
 					foreach($system_variables as $var)
@@ -326,11 +326,11 @@ class phoromatic_result implements pts_webui_interface
 				$right .= '<hr /><h3>Compare Results</h3><form name="compare_similar_results" onsubmit="return false;">
 						<input type="hidden" value="' . implode(',', $upload_ids) . '" id="compare_similar_results_this" />';
 
 				foreach($compare_results as &$row)
 				{
-					$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>';
+					$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>';
 				}
 
 				$right .= '<p><input type="submit" value="Compare Results" id="compare_results_submit" onclick="javascript:phoromatic_do_custom_compare_results(this); return false;" /></p></form>';
 
 				if($ticket_matches > 3)
diff --git a/pts-core/phoromatic/pages/phoromatic_results.php b/pts-core/phoromatic/pages/phoromatic_results.php
index 4173a11ec..1a5be530f 100644
--- a/pts-core/phoromatic/pages/phoromatic_results.php
+++ b/pts-core/phoromatic/pages/phoromatic_results.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2008 - 2018, Phoronix Media
-	Copyright (C) 2008 - 2018, Michael Larabel
+	Copyright (C) 2008 - 2022, Phoronix Media
+	Copyright (C) 2008 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_results implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Test Schedules';
@@ -35,156 +34,220 @@ class phoromatic_results implements pts_webui_interface
 	{
 		return true;
 	}
 	public static function render_page_process($PATH)
 	{
-			echo phoromatic_webui_header_logged_in();
-			$main = null;
+		echo phoromatic_webui_header_logged_in();
+		$main = null;
 
-			if(!PHOROMATIC_USER_IS_VIEWER && isset($PATH[0]) && $PATH[0] == 'delete')
-			{
-				$pprids = explode(',', $PATH[1]);
+		if(!PHOROMATIC_USER_IS_VIEWER && isset($PATH[0]) && $PATH[0] == 'delete')
+		{
+			$pprids = explode(',', $PATH[1]);
 
-				foreach($pprids as $pprid)
+			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()))
 				{
-					$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))
 					{
-						$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();
-
-
+						unlink($composite_xml);
 					}
 
-					$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_results WHERE AccountID = :account_id AND PPRID = :pprid');
+					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(':pprid', $pprid);
+					$stmt->bindValue(':upload_id', $row['UploadID']);
 					$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);
+					$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)
+		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(isset($_POST['result_limit']))
+				if(is_numeric($_POST['result_limit']) && $_POST['result_limit'] > 9)
 				{
-					if(is_numeric($_POST['result_limit']) && $_POST['result_limit'] > 9)
-					{
-						$result_limit = $_POST['result_limit'];
-					}
-					else
-					{
-						$result_limit = 0;
-					}
+					$result_limit = $_POST['result_limit'];
 				}
 				else
 				{
-					$result_limit = 100;
+					$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']);
 				}
-				$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))
+				else
 				{
-					$time_start = strtotime($min_date);
+					$search_for .= ' AND UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND Hardware LIKE :containing_hardware)';
 				}
-				$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))
+			}
+			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)
 				{
-					$time_end = strtotime(date('Y-m-d') . ' 23:59:59');
+					$sw_advanced_query = pts_phoroql::search_query_to_tree($_POST['containing_software']);
 				}
-				$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)
+				else
 				{
-					$main .= '<option value="' . $i . '"' . ($result_limit == $i ? ' selected="selected"' : null) . '>' . $i . '</option>';
+					$search_for .= ' AND UploadID IN (SELECT UploadID FROM phoromatic_results_systems WHERE AccountID = :account_id AND Software LIKE :containing_software)';
 				}
-				$main .= '<option value=""' . (isset($_POST['result_limit']) && empty($result_limit) ? ' selected="selected"' : null) . '>No Limit</option>';
+			}
+			$main .= '<div style="margin: 0 5%;"><ul style="max-height: 100%;"><li><h1>Recent Test Results</h1></li>';
 
-				$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']))
+			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)
 				{
-					$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)';
-					}
+					continue;
 				}
-				if(isset($_POST['containing_software']) && !empty($_POST['containing_software']))
+				if(strtotime($test_result_row['UploadTime']) < $time_start)
 				{
-					$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)';
-					}
+					//break;
 				}
-				$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')
+				if(!empty($result_limit) && $result_limit > 1 && $result_limit == $results)
 				{
-					// 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]);
+					break;
 				}
-				else if(isset($PATH[1]) && $PATH[0] == 'ticket')
+
+				$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)
 				{
-					// 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]);
+					//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;
+					}
 				}
-				else
+				if(isset($_POST['containing_software']) && !empty($_POST['containing_software']) && $sw_advanced_query)
 				{
-					$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');
+					if(!pts_phoroql::evaluate_search_tree($sw_advanced_query, 'AND', array($result_file, 'contains_system_software')))
+					{
+						continue;
+					}
 				}
-
-				$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);
+					if(!pts_phoroql::evaluate_search_tree($containing_tests, 'AND', array($result_file, 'contains_test')))
+					{
+						continue;
+					}
 				}
 
-				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_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
 				{
 					if(strtotime($test_result_row['UploadTime']) > $time_end)
 					{
 						continue;
 					}
@@ -213,96 +276,27 @@ class phoromatic_results implements pts_webui_interface
 						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>' . 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 .= '<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>';
 					$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>';
-				}
+				while($test_result_row = $test_result_result->fetchArray());
 				$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
-					{
-						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();
+		echo phoromatic_webui_main($main);
+		echo phoromatic_webui_footer();
 	}
 }
 
 ?>
diff --git a/pts-core/phoromatic/pages/phoromatic_sched.php b/pts-core/phoromatic/pages/phoromatic_sched.php
index 5567deccc..c376fe09a 100644
--- a/pts-core/phoromatic/pages/phoromatic_sched.php
+++ b/pts-core/phoromatic/pages/phoromatic_sched.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2014 - 2017, Phoronix Media
-	Copyright (C) 2014 - 2017, Michael Larabel
+	Copyright (C) 2014 - 2022, Phoronix Media
+	Copyright (C) 2014 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_sched implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Test Scheduling';
@@ -234,56 +233,56 @@ class phoromatic_sched implements pts_webui_interface
 		}
 		$main .='</select></p><table class="pts_phoromatic_schedule_type">
 <tr>
   <td><h3>Time-Based Testing</h3><em>Time-based testing allows tests to automatically commence at a given time on a defined cycle each day/week. This option is primarly aimed for those wishing to run a set of benchmarks every morning or night or at another defined period.</em></td>
   <td><h3>Run Time:</h3>
-			<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();
-			}
+		<p><select name="schedule_hour" id="schedule_hour">';
 
-			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">';
+		if(!$is_new)
+		{
+			$run_at = explode('.', $e_schedule['RunAt']);
+			$days_active = !empty($e_schedule['ActiveOn']) ? explode(',', $e_schedule['ActiveOn']) : array();
+		}
 
-			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>';
-			}
+		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><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 .= '</select> <select name="schedule_minute" id="schedule_minute">';
 
-			$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>';
+		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 .= (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 .= '</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 align="right"><input name="submit" value="' . ($is_new ? 'Create' : 'Edit') . ' Schedule" type="submit" onclick="return pts_rmm_validate_schedule();" /></p>
+		$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>
 			</form>';
-			echo phoromatic_webui_main($main);
-			echo phoromatic_webui_footer();
+		echo phoromatic_webui_main($main);
+		echo phoromatic_webui_footer();
 	}
 }
 
 ?>
diff --git a/pts-core/phoromatic/pages/phoromatic_schedules.php b/pts-core/phoromatic/pages/phoromatic_schedules.php
index 602572600..93e1863cb 100644
--- a/pts-core/phoromatic/pages/phoromatic_schedules.php
+++ b/pts-core/phoromatic/pages/phoromatic_schedules.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2008 - 2018, Phoronix Media
-	Copyright (C) 2008 - 2018, Michael Larabel
+	Copyright (C) 2008 - 2022, Phoronix Media
+	Copyright (C) 2008 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_schedules implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Test Schedules';
@@ -53,24 +52,25 @@ class phoromatic_schedules implements pts_webui_interface
 				$main = '<h1>Test Schedules</h1>';
 				$main .= '<h3>No Resource Found</h3>';
 			}
 			else
 			{
-
 				if(!PHOROMATIC_USER_IS_VIEWER)
 				{
 
 					if(isset($_POST['add_to_schedule_select_test']))
 					{
+						phoromatic_quit_if_invalid_input_found(array('add_to_schedule_select_test'));
 						$name = $_POST['add_to_schedule_select_test'];
 						$args = array();
 						$args_name = array();
 
 						foreach($_POST as $i => $v)
 						{
 							if(substr($i, 0, 12) == 'test_option_' && substr($i, -9) != '_selected')
 							{
+								phoromatic_quit_if_invalid_input_found(array($i, $i . '_selected'));
 								array_push($args, $v);
 								array_push($args_name, $_POST[$i . '_selected']);
 							}
 						}
 
@@ -173,11 +173,10 @@ class phoromatic_schedules implements pts_webui_interface
 						$stmt->execute();
 						$main .= '<h2 style="color: red;">Current Trigger To Be Ignored</h2>';
 					}
 				}
 
-
 				$main .= '<h1>' . $row['Title'] . '</h1>';
 				$main .= '<h3>' . $row['Description'] . '</h3>';
 				switch($row['RunPriority'])
 				{
 					case 1:
@@ -246,19 +245,19 @@ class phoromatic_schedules implements pts_webui_interface
 				{
 					$main .= '<p>This test schedule is not currently set to run a pre-defined time-based schedule.</p>';
 				}
 				if(!PHOROMATIC_USER_IS_VIEWER)
 				{
-				$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>';
+					$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 .= '<hr />';
 
 				$contexts = array('SetContextPreInstall' => 'Pre-Install', 'SetContextPostInstall' => 'Post-Install', 'SetContextPreRun' => 'Pre-Test-Run', 'SetContextPostRun' => 'Post-Test-Run');
@@ -424,12 +423,10 @@ class phoromatic_schedules implements pts_webui_interface
 					while($test_result_row = $test_result_result->fetchArray());
 					$main .= '</ul>';
 					$main .= '</div>';
 				}
 
-
-
 				$stmt = phoromatic_server::$db->prepare('SELECT Title, SystemID, ScheduleID, PPRID, UploadTime FROM phoromatic_results WHERE AccountID = :account_id AND ScheduleID = :schedule_id ORDER BY UploadTime DESC');
 				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 				$stmt->bindValue(':schedule_id', $PATH[0]);
 				$test_result_result = $stmt->execute();
 				$test_result_row = $test_result_result->fetchArray();
@@ -444,11 +441,11 @@ class phoromatic_schedules implements pts_webui_interface
 						$oldest_upload_time = $test_result_row['UploadTime'];
 						if($results > 100)
 						{
 							continue;
 						}
-						$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>';
+						$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>';
 						$results++;
 
 					}
 					while($test_result_row = $test_result_result->fetchArray());
 					$main .= '</ul>';
@@ -487,119 +484,113 @@ class phoromatic_schedules implements pts_webui_interface
 			return;
 		}
 
 
 		$main = '<h1>Test Schedules</h1>
-			<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>';
+		<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 .= '<div class="pts_phoromatic_info_box_area">
-					<ul>
-						<li><h1>Active Test Schedules</h1></li>';
+		$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());
-					}
+		$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 .= '</ul>
+		</div>';
 
-			$main .= '<hr /><h2>Schedule Overview</h2>';
-			$week = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
+		$main .= '<hr /><h2>Schedule Overview</h2>';
+		$week = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
 
-			foreach($week as $i => $day)
+		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())
 			{
-				$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)
 				{
-					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 />';
+					$main .= '<h3>' . $day . '</h3>' . PHP_EOL . '<p>';
+					$has_matched = true;
 				}
-
-				if($has_matched)
-					$main .= '</p>' . PHP_EOL;
-
+				$main .= '<em>' . $row['RunAt'] . '</em> <a href="?schedules/' . $row['ScheduleID'] . '">' . $row['Title'] . '</a>';
+				//$main .= $row['RunTargetSystems'] . ' ' . $row['RunTargetGroups'];
+				$main .= '<br />';
 			}
 
-			$main .= '<div class="pts_phoromatic_info_box_area">
-					<ul>
-						<li><h1>Deactivated Test Schedules</h1></li>';
+			if($has_matched)
+				$main .= '</p>' . PHP_EOL;
+		}
 
-					$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();
+		$main .= '<div class="pts_phoromatic_info_box_area">
+				<ul>
+				<li><h1>Deactivated Test Schedules</h1></li>';
 
-					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());
-					}
+		$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 .= '</ul>
+		</div>';
 
-			echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
-			echo phoromatic_webui_footer();
+		echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
+		echo phoromatic_webui_footer();
 	}
 }
 
 ?>
diff --git a/pts-core/phoromatic/pages/phoromatic_search.php b/pts-core/phoromatic/pages/phoromatic_search.php
index affd18609..82e5fe5a3 100644
--- a/pts-core/phoromatic/pages/phoromatic_search.php
+++ b/pts-core/phoromatic/pages/phoromatic_search.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2014 - 2018, Phoronix Media
-	Copyright (C) 2014 - 2018, Michael Larabel
+	Copyright (C) 2014 - 2022, Phoronix Media
+	Copyright (C) 2014 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_search implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Search';
@@ -176,12 +175,11 @@ class phoromatic_search implements pts_webui_interface
 
 		return $ret;
 	}
 	public static function render_page_process($PATH)
 	{
-		$search_query = $_REQUEST['search'];
-
+		$search_query = pts_strings::sanitize($_REQUEST['search']);
 		$main = null;
 
 		if(strlen($search_query) < 4)
 		{
 			$main = '<h1>Search Failed</h1>';
diff --git a/pts-core/phoromatic/pages/phoromatic_settings.php b/pts-core/phoromatic/pages/phoromatic_settings.php
index 3bde029a3..c2394c567 100644
--- a/pts-core/phoromatic/pages/phoromatic_settings.php
+++ b/pts-core/phoromatic/pages/phoromatic_settings.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_settings implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Settings';
diff --git a/pts-core/phoromatic/pages/phoromatic_system_claim.php b/pts-core/phoromatic/pages/phoromatic_system_claim.php
index 5f18e8260..cdf2c8a86 100644
--- a/pts-core/phoromatic/pages/phoromatic_system_claim.php
+++ b/pts-core/phoromatic/pages/phoromatic_system_claim.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2008 - 2015, Phoronix Media
-	Copyright (C) 2008 - 2015, Michael Larabel
+	Copyright (C) 2008 - 2022, Phoronix Media
+	Copyright (C) 2008 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_system_claim implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Phoromatic Client System Claim';
@@ -41,40 +40,40 @@ class phoromatic_system_claim implements pts_webui_interface
 		$main = null;
 
 		if(!PHOROMATIC_USER_IS_VIEWER)
 		{
 
-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(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);
-	}
-}
+				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);
+				}
+			}
 			if((isset($_POST['ip_claim']) && !empty($_POST['ip_claim'])) && isset($_POST['ping']))
 			{
 				$ip_ping = ip2long($_POST['ip_claim']) !== false ? $_POST['ip_claim'] : null;
 				if($ip_ping)
 				{
@@ -86,22 +85,22 @@ echo "' . phoromatic_web_socket_server_addr() . '" > $PHORO_FILE_PATH/modules-da
 			}
 			else if((isset($_POST['ip_claim']) && !empty($_POST['ip_claim'])) || (isset($_POST['mac_claim']) && !empty($_POST['mac_claim'])))
 			{
 				$stmt = phoromatic_server::$db->prepare('INSERT INTO phoromatic_system_association_claims (AccountID, IPAddress, NetworkMAC, CreationTime) VALUES (:account_id, :ip_address, :mac_address, :creation_time)');
 				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
-				$stmt->bindValue(':ip_address', $_POST['ip_claim']);
-				$stmt->bindValue(':mac_address', $_POST['mac_claim']);
+				$stmt->bindValue(':ip_address', pts_strings::simple($_POST['ip_claim']));
+				$stmt->bindValue(':mac_address', pts_strings::simple($_POST['mac_claim']));
 				$stmt->bindValue(':creation_time', phoromatic_server::current_time());
 				$result = $stmt->execute();
 			}
 			if(isset($_POST['remove_claim']) && !empty($_POST['remove_claim']))
 			{
 				list($ipc, $macc) = explode(',', $_POST['remove_claim']);
 				$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_system_association_claims WHERE AccountID = :account_id AND NetworkMAC = :mac_address AND IPAddress = :ip_address');
 				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
-				$stmt->bindValue(':ip_address', $ipc);
-				$stmt->bindValue(':mac_address', $macc);
+				$stmt->bindValue(':ip_address', pts_strings::simple($ipc));
+				$stmt->bindValue(':mac_address', pts_strings::simple($macc));
 				$stmt->bindValue(':creation_time', phoromatic_server::current_time());
 				$result = $stmt->execute();
 			}
 
 			$main .= '<h2>Add Phoromatic Server Info Via SSH</h2>
diff --git a/pts-core/phoromatic/pages/phoromatic_systems.php b/pts-core/phoromatic/pages/phoromatic_systems.php
index b5a0ff63e..ff8bb5467 100644
--- a/pts-core/phoromatic/pages/phoromatic_systems.php
+++ b/pts-core/phoromatic/pages/phoromatic_systems.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2008 - 2021, Phoronix Media
-	Copyright (C) 2008 - 2021, Michael Larabel
+	Copyright (C) 2008 - 2022, Phoronix Media
+	Copyright (C) 2008 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -40,15 +40,16 @@ class phoromatic_systems implements pts_webui_interface
 		echo phoromatic_webui_header_logged_in();
 		$main = null;
 
 		if(!PHOROMATIC_USER_IS_VIEWER && !empty($PATH[0]) && isset($_POST['system_title']) && !empty($_POST['system_title']) && isset($_POST['system_description']) && isset($_POST['system_state']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('system_title', 'system_description', 'system_state'));
 			$stmt = phoromatic_server::$db->prepare('UPDATE phoromatic_systems SET Title = :title, Description = :description, State = :state, CurrentTask = \'Awaiting Task\', BlockPowerOffs = :block_power_offs WHERE AccountID = :account_id AND SystemID = :system_id');
 			$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 			$stmt->bindValue(':system_id', $PATH[0]);
-			$stmt->bindValue(':title', $_POST['system_title']);
-			$stmt->bindValue(':description', $_POST['system_description']);
+			$stmt->bindValue(':title', pts_strings::simple($_POST['system_title']));
+			$stmt->bindValue(':description', pts_strings::sanitize($_POST['system_description']));
 			$stmt->bindValue(':state', $_POST['system_state']);
 			$stmt->bindValue(':block_power_offs', $_POST['block_power_offs']);
 			$stmt->execute();
 		}
 		if(!PHOROMATIC_USER_IS_VIEWER && !empty($PATH[0]) && isset($_POST['maintenance_mode']))
@@ -381,11 +382,11 @@ class phoromatic_systems implements pts_webui_interface
 						if($results > 20)
 						{
 							break;
 						}
 
-						$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>';
+						$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>';
 						$results++;
 
 					}
 					while($test_result_row = $test_result_result->fetchArray());
 				}
@@ -469,10 +470,12 @@ class phoromatic_systems implements pts_webui_interface
 			{
 				$group = trim($_POST['new_group']);
 
 				if($group)
 				{
+					phoromatic_quit_if_invalid_input_found(array('new_group'));
+					$group = pts_strings::simple($group);
 					$stmt = phoromatic_server::$db->prepare('INSERT INTO phoromatic_groups (AccountID, GroupName) VALUES (:account_id, :group_name)');
 					$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 					$stmt->bindValue(':group_name', $group);
 					$result = $stmt->execute();
 					phoromatic_add_activity_stream_event('groups', $group, 'added');
@@ -527,22 +530,23 @@ class phoromatic_systems implements pts_webui_interface
 					}
 				}
 			}
 			else if(!PHOROMATIC_USER_IS_VIEWER && isset($_POST['remove_group']))
 			{
+				$remove_group = pts_strings::sanitize($_POST['remove_group']);
 				$stmt = phoromatic_server::$db->prepare('DELETE FROM phoromatic_groups WHERE AccountID = :account_id AND GroupName = :group_name');
 				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
-				$stmt->bindValue(':group_name', $_POST['remove_group']);
+				$stmt->bindValue(':group_name', $remove_group);
 				$stmt->execute();
 				phoromatic_add_activity_stream_event('groups', $group, 'removed');
 
-				$stmt = phoromatic_server::$db->prepare('SELECT SystemID, Groups FROM phoromatic_systems WHERE AccountID = :account_id AND Groups LIKE \'%#' . $_POST['remove_group'] . '#%\'');
+				$stmt = phoromatic_server::$db->prepare('SELECT SystemID, Groups FROM phoromatic_systems WHERE AccountID = :account_id AND Groups LIKE \'%#' . $remove_group . '#%\'');
 				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 				$result = $stmt->execute();
 				while($row = $result->fetchArray())
 				{
-					$revised_groups = str_replace('#' . $_POST['remove_group'] . '#', '', $row['Groups']);
+					$revised_groups = str_replace('#' . $remove_group . '#', '', $row['Groups']);
 
 					$stmt1 = phoromatic_server::$db->prepare('UPDATE phoromatic_systems SET Groups = :new_groups WHERE AccountID = :account_id AND SystemID = :system_id');
 					$stmt1->bindValue(':account_id', $_SESSION['AccountID']);
 					$stmt1->bindValue(':system_id', $row['SystemID']);
 					$stmt1->bindValue(':new_groups', $revised_groups);
@@ -553,11 +557,11 @@ class phoromatic_systems implements pts_webui_interface
 			{
 				// $_POST['remove_inactive_systems'] is number of days system is without activity before removing
 				$stmt = phoromatic_server::$db->prepare('UPDATE phoromatic_systems SET State = :state WHERE AccountID = :account_id AND (julianday() - julianday(LastCommunication)) > :inactive_days_before_removal');
 				$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 				$stmt->bindValue(':state', -1);
-				$stmt->bindValue(':inactive_days_before_removal', $_POST['remove_inactive_systems']);
+				$stmt->bindValue(':inactive_days_before_removal', pts_strings::sanitize($_POST['remove_inactive_systems']));
 				$stmt->execute();
 			}
 
 			$main = '<h1>Test Systems</h1>';
 			if(!PHOROMATIC_USER_IS_VIEWER)
@@ -569,12 +573,12 @@ class phoromatic_systems implements pts_webui_interface
 				<p>Those having to connect many Phoronix Test Suite Phoromatic clients can also attempt <a href="?system_claim">adding the server configuration</a> via SSH or an IP/MAC address claim.</p>
 				<p>The Phoronix Test Suite ships with a <em>phoromatic-client</em> systemd example service file for automatically starting the Phoromatic client process after the initial configuration process is complete.</p>
 				<p><button onclick="javascript:window.location.replace(\'?system_claim\');">Add Via SSH Or IP/MAC Claim</button></p>';
 
 			}
-			$main .= '<hr />
 
+			$main .= '<hr />
 			<h2>Systems</h2>
 			<div class="pts_phoromatic_info_box_area">
 
 					<ul>
 						<li><h1>Active Systems</h1></li>';
@@ -637,11 +641,10 @@ class phoromatic_systems implements pts_webui_interface
 				}
 				while($row = $result->fetchArray());
 				$main .= '</ul>';
 			}
 
-
 			$main .= '</div>';
 
 			if(!PHOROMATIC_USER_IS_VIEWER)
 			{
 				$main .= '<hr />
@@ -728,23 +731,19 @@ class phoromatic_systems implements pts_webui_interface
 						}
 						$main .= '</tr>';
 					}
 
 					$main .= '</table><p><input name="submit" value="Update Groups" type="submit" /></p></form></div>';
-
 					$main .= '<hr /><h2>Remove A Group</h2><p>Removing a group is a permanent action that cannot be undone.</p>';
-
 					$main .= '<p><form action="' . $_SERVER['REQUEST_URI'] . '" name="remove_group" method="post"><select name="remove_group" id="remove_group">';
 
 					foreach($all_groups as $group)
 					{
 						$main .= '<option value="' . $group . '">' . $group . '</option>';
 					}
 					$main .= '</select> <input name="submit" value="Remove Group" type="submit" /></form></p>';
-
 					$main .= '<hr /><h2>Retire Inactive Systems</h2><p>This option will soft-delete systems that have not communicated with this Phoromatic Server in more than one week (7 days).</p>';
-
 					$main .= '<p><form action="' . $_SERVER['REQUEST_URI'] . '" name="remove_inactive" method="post"><input type="hidden" name="remove_inactive_systems" value="7" /><input name="submit" value="Remove Inactive Systems" type="submit" /></form></p>';
 				}
 			}
 		}
 
diff --git a/pts-core/phoromatic/pages/phoromatic_testing.php b/pts-core/phoromatic/pages/phoromatic_testing.php
index 590be4bd4..02fcb0f32 100644
--- a/pts-core/phoromatic/pages/phoromatic_testing.php
+++ b/pts-core/phoromatic/pages/phoromatic_testing.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2016, Phoronix Media
-	Copyright (C) 2016, Michael Larabel
+	Copyright (C) 2016 - 2022, Phoronix Media
+	Copyright (C) 2016 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_testing implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Testing';
@@ -41,100 +40,97 @@ class phoromatic_testing implements pts_webui_interface
 		echo phoromatic_webui_header_logged_in();
 
 		$main = '<h1>Phoromatic Testing Options</h1><h2>Test Schedules</h2>
 			<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)
+		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
 			{
-				$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>';
+				$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>Current Schedules</h2>';
+		$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 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>';
+				<ul>
+				<li><h1>Active Benchmark Tickets</h1></li>';
 
-				$row = $result->fetchArray();
+			$row = $result->fetchArray();
 
-				if(!empty($row))
-				{
-					do
-					{
-						$main .= '<a href="?benchmark/' . $row['TicketID'] . '"><li>' . $row['Title'] . '</li></a>';
-					}
-					while($row = $result->fetchArray());
-				}
-				else
+			if(!empty($row))
+			{
+				do
 				{
-					$main .= '<li class="light" style="text-align: center;">No Tickets Found</li>';	
+					$main .= '<a href="?benchmark/' . $row['TicketID'] . '"><li>' . $row['Title'] . '</li></a>';
 				}
+				while($row = $result->fetchArray());
 			}
-			$main .= '</ul>
-			</div>';
-
-			if(!PHOROMATIC_USER_IS_VIEWER)
+			else
 			{
-				$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>';
+				$main .= '<li class="light" style="text-align: center;">No Tickets Found</li>';	
 			}
-
-
-			echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
-			echo phoromatic_webui_footer();
+		}
+		$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();
 	}
 }
 
 ?>
diff --git a/pts-core/phoromatic/pages/phoromatic_tests.php b/pts-core/phoromatic/pages/phoromatic_tests.php
index f363bbd2b..3ea5c8114 100644
--- a/pts-core/phoromatic/pages/phoromatic_tests.php
+++ b/pts-core/phoromatic/pages/phoromatic_tests.php
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_tests implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Tests';
diff --git a/pts-core/phoromatic/pages/phoromatic_tracker.php b/pts-core/phoromatic/pages/phoromatic_tracker.php
index f1b0e5632..bb49f62c1 100644
--- a/pts-core/phoromatic/pages/phoromatic_tracker.php
+++ b/pts-core/phoromatic/pages/phoromatic_tracker.php
@@ -175,11 +175,10 @@ class phoromatic_tracker implements pts_webui_interface
 							}
 						}
 						while($row = $result->fetchArray());
 					}
 
-
 			$main .= '</ul>
 			</div>';
 			$right = null;
 		}
 
diff --git a/pts-core/phoromatic/pages/phoromatic_users.php b/pts-core/phoromatic/pages/phoromatic_users.php
index 816846510..578585122 100644
--- a/pts-core/phoromatic/pages/phoromatic_users.php
+++ b/pts-core/phoromatic/pages/phoromatic_users.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2014 - 2015, Phoronix Media
-	Copyright (C) 2014 - 2015, Michael Larabel
+	Copyright (C) 2014 - 2022, Phoronix Media
+	Copyright (C) 2014 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_users implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Account Administrator';
@@ -43,17 +42,19 @@ class phoromatic_users implements pts_webui_interface
 			return;
 		}
 
 		if(isset($_POST['group_name']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('group_name'));
 			$stmt = phoromatic_server::$db->prepare('UPDATE phoromatic_accounts SET GroupName = :group_name WHERE AccountID = :account_id');
-			$stmt->bindValue(':group_name', $_POST['group_name']);
+			$stmt->bindValue(':group_name', pts_strings::simple($_POST['group_name']));
 			$stmt->bindValue(':account_id', $_SESSION['AccountID']);
 			$result = $stmt->execute();
 		}
 		if(isset($_POST['username']) && isset($_POST['password']) && isset($_POST['confirm_password']) && isset($_POST['email']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('username', 'email'));
 			// REGISTER NEW USER
 			if(strlen($_POST['username']) < 4 || strpos($_POST['username'], ' ') !== false)
 			{
 				phoromatic_error_page('Oops!', 'Please go back and ensure the supplied username is at least four characters long and contains no spaces.');
 				return false;
@@ -238,11 +239,11 @@ class phoromatic_users implements pts_webui_interface
 		$main .= '
 			</select></p>
 			<p><input name="submit" value="Add User" type="submit" /></p>
 			</form>';
 
-		$group_name = phoromatic_account_id_to_group_name($_SESSION['AccountID']);
+		$group_name = phoromatic_server::account_id_to_group_name($_SESSION['AccountID']);
 		$main .= '<hr /><form action="' . $_SERVER['REQUEST_URI'] . '" name="group_name" id="group_name" method="post"><h2>Group Name</h2>
 			<p>A group name is an alternative, user-facing name for this set of accounts. The group name feature is primarily useful for being able to better distinguish results between groups when sharing of data within a large organization, etc. The group name is showed next to test results when viewing results from multiple groups/accounts.</p>
 			<h3>Group Name</h3>
 			<p><input type="text" name="group_name" value="' . $group_name . '" /></p>
 			<p><input name="submit" value="Update Group Name" type="submit" /></p>
diff --git a/pts-core/phoromatic/pages/phoromatic_welcome.php b/pts-core/phoromatic/pages/phoromatic_welcome.php
index fff7e7c3d..2fd251df9 100644
--- a/pts-core/phoromatic/pages/phoromatic_welcome.php
+++ b/pts-core/phoromatic/pages/phoromatic_welcome.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2008 - 2015, Phoronix Media
-	Copyright (C) 2008 - 2015, Michael Larabel
+	Copyright (C) 2008 - 2022, Phoronix Media
+	Copyright (C) 2008 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -18,11 +18,10 @@
 
 	You should have received a copy of the GNU General Public License
 	along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
-
 class phoromatic_welcome implements pts_webui_interface
 {
 	public static function page_title()
 	{
 		return 'Welcome';
@@ -40,10 +39,11 @@ class phoromatic_welcome implements pts_webui_interface
 		$account_creation_string = phoromatic_server::read_setting('account_creation_alt');
 		$account_creation_enabled = $account_creation_string == null;
 
 		if($account_creation_enabled && isset($_POST['register_username']) && isset($_POST['register_password']) && isset($_POST['register_password_confirm']) && isset($_POST['register_email']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('register_username', 'register_email'));
 			$new_account = create_new_phoromatic_account($_POST['register_username'], $_POST['register_password'], $_POST['register_password_confirm'], $_POST['register_email'], (isset($_POST['seed_accountid']) ? $_POST['seed_accountid'] : null));
 
 			if($new_account)
 			{
 				echo phoromatic_webui_header(array('Account Created'), '');
@@ -58,10 +58,11 @@ class phoromatic_welcome implements pts_webui_interface
 				echo phoromatic_webui_footer();
 			}
 		}
 		else if(isset($_POST['username']) && isset($_POST['password']) && strtolower($_POST['username']) == 'rootadmin')
 		{
+			phoromatic_quit_if_invalid_input_found(array('username'));
 			$admin_pw = phoromatic_server::read_setting('root_admin_pw');
 			if(empty($admin_pw))
 			{
 				echo phoromatic_webui_header(array('Action Required'), '');
 				$box = '<h1>Root Admin Password Not Set</h1>
@@ -92,10 +93,11 @@ class phoromatic_welcome implements pts_webui_interface
 				header('Location: /?admin');
 			}
 		}
 		else if(isset($_POST['username']) && isset($_POST['password']))
 		{
+			phoromatic_quit_if_invalid_input_found(array('username'));
 			$matching_user = phoromatic_server::$db->querySingle('SELECT UserName, Password, AccountID, UserID, AdminLevel, CreatedOn FROM phoromatic_users WHERE UserName = \'' . SQLite3::escapeString($_POST['username']) . '\'', true);
 			if(!empty($matching_user))
 			{
 				$user_id = $matching_user['UserID'];
 				$created_on = $matching_user['CreatedOn'];
@@ -221,12 +223,11 @@ class phoromatic_welcome implements pts_webui_interface
 				$box .= '<p>' . $account_creation_string . '</p>';
 			}
 			else
 			{
 
-				$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>
+				$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>
 			<div style="display: none;" id="register">
 
 
 					<p>To create a new account for this Phoromatic server, simply fill out the form below. Phoromatic also allows multi-user accounts. If wishing to be added to an existing Phoromatic account as a separate user, contact the appropriate party and request said access. Within a Phoromatic account with appropriate credentials, additional sub-accounts can be created/managed from the &quot;Users&quot; page.</p>';
 					$box .= '<form name="register_form" id="register_form" action="?register" method="post" onsubmit="return phoromatic_initial_registration(this);">
@@ -250,15 +251,13 @@ class phoromatic_welcome implements pts_webui_interface
 							<input type="email" name="register_email" id="r_email" required/>
 						</li>
 						<li class="label_input_wrapper">
 							<input type="submit" value="Create Account" />
 						</li>
-
 					</ul>
 
 					</form></div>';
-
 			}
 			$box .= '<hr />
 			<h1>View Public Results</h1>
 			<p>For accounts that opted to share their test results publicly, you can directly <a href="public.php">view the public test results</a>.</p><hr />';
 
diff --git a/pts-core/phoromatic/phoromatic_functions.php b/pts-core/phoromatic/phoromatic_functions.php
index 7319f978a..d4a8d9abf 100644
--- a/pts-core/phoromatic/phoromatic_functions.php
+++ b/pts-core/phoromatic/phoromatic_functions.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2013 - 2020, Phoronix Media
-	Copyright (C) 2013 - 2020, Michael Larabel
+	Copyright (C) 2013 - 2022, Phoronix Media
+	Copyright (C) 2013 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -21,10 +21,38 @@
 */
 
 define('PHOROMATIC_SERVER_WEB_INTERFACE', true);
 define('PAGE_LOAD_START_TIME', microtime(true));
 
+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;
+					}
+				}
+			}
+		}
+	}
+}
 function phoromatic_annotate_entry($type, $id, $secondary_id)
 {
 	$annotate_hash = sha1($id . $secondary_id);
 
 	if(isset($_GET['da_' . $annotate_hash]))
@@ -62,11 +90,10 @@ function phoromatic_annotate_entry($type, $id, $secondary_id)
 	$stmt->bindValue(':type', $type);
 	$stmt->bindValue(':id', $id);
 	$stmt->bindValue(':secondary_id', $secondary_id);
 	$result = $stmt->execute();
 	$row = $result->fetchArray();
-
 	$output = null;
 
 	if($row)
 	{
 		do
@@ -162,11 +189,11 @@ function phoromatic_webui_header($left_items, $right = null)
 
 	if(isset($_SESSION['AdminLevel']) &&$_SESSION['AdminLevel'] > 0 && isset($_SESSION['AccountID']) && !empty($_SESSION['AccountID']))
 	{
 		$ret .= '<ul id="pts_phoromatic_info">';
 		$ret .= '<li><a class="ph_date" href="#">' . date('H:i T - j F') . '</a></li>';
-		$group_name = phoromatic_account_id_to_group_name($_SESSION['AccountID']);
+		$group_name = phoromatic_server::account_id_to_group_name($_SESSION['AccountID']);
 		if($group_name != null)
 		{
 			$ret .= '<li><a href="#">' . $group_name . '</a></li>';
 		}
 		$ret .= '</ul>';
@@ -209,10 +236,15 @@ function phoromatic_webui_header($left_items, $right = null)
 
 	return $ret;
 }
 function phoromatic_get_posted_var($name, $default_value = null)
 {
+	if(isset($_POST[$name]))
+	{
+		phoromatic_quit_if_invalid_input_found(array($name));
+	}
+
 	return isset($_POST[$name]) ? $_POST[$name] : null;
 }
 function phoromatic_webui_main($main, $right = null)
 {
 	return '<div id="pts_phoromatic_main">' . ($right != null ? '<div id="pts_phoromatic_menu_right">' . $right . '</div>' : null) . '<div id="pts_phoromatic_main_area">' . $main . '</div><div style="clear: both;"></div></div>';
@@ -465,11 +497,11 @@ function phoromatic_webui_right_panel_logged_in($add = null)
 		$stmt->bindValue(':today_date', date('Y-m-d') . '%');
 		$result = $stmt->execute();
 		$row = $result->fetchArray();
 		$activity_count = $row['ActivityCount'];
 
-		$group_name = phoromatic_account_id_to_group_name($_SESSION['AccountID']);
+		$group_name = phoromatic_server::account_id_to_group_name($_SESSION['AccountID']);
 		if($group_name != null)
 		{
 			$group_name = '<strong>' . $group_name . '</strong><br />';
 		}
 
@@ -537,14 +569,12 @@ function phoromatic_web_socket_server_addr()
 	return phoromatic_web_socket_server_ip() . '/' . $_SESSION['AccountID'];
 }
 function phoromatic_error_page($title, $description)
 {
 	echo phoromatic_webui_header(array(''), '');
-
 	$box = '<h1>' . $title . '</h1>
-		<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 />';
+		<h2>' . $description . '</h2>';
 	echo phoromatic_webui_box($box);
 	echo phoromatic_webui_footer();
 }
 function phoromatic_systems_needing_attention()
 {
@@ -571,14 +601,10 @@ function phoromatic_systems_needing_attention()
 		$main .= '</ul></div></div>';
 	}
 
 	return $main;
 }
-function phoromatic_system_id_to_name($system_id, $aid = false)
-{
-	return phoromatic_server::system_id_to_name($system_id, $aid);
-}
 function phoromatic_oldest_result_for_schedule($schedule_id)
 {
 	static $old_time;
 
 	if(!isset($old_time[$schedule_id]))
@@ -607,15 +633,10 @@ function phoromatic_schedule_id_to_name($schedule_id)
 		$schedule_names[$schedule_id] = $row['Title'];
 	}
 
 	return $schedule_names[$schedule_id];
 }
-function phoromatic_account_id_to_group_name($account_id)
-{
-	// XXX deprecated
-	return phoromatic_server::account_id_to_group_name($account_id);
-}
 function create_new_phoromatic_account($register_username, $register_password, $register_password_confirm, $register_email, $seed_accountid = null)
 {
 	// REGISTER NEW USER
 	if(strlen($register_username) < 4 || strpos($register_username, ' ') !== false)
 	{
diff --git a/pts-core/phoromatic/public_html/phoromatic.php b/pts-core/phoromatic/public_html/phoromatic.php
index 203134c9b..cdacd24b3 100644
--- a/pts-core/phoromatic/public_html/phoromatic.php
+++ b/pts-core/phoromatic/public_html/phoromatic.php
@@ -193,11 +193,11 @@ if(empty($result))
 	$stmt->bindValue(':phodevi_properties', $PHODEVI_PROPERTIES);
 	$stmt->bindValue(':client_version', $CLIENT_VERSION);
 	$stmt->bindValue(':gsid', $GSID);
 	$stmt->bindValue(':access_ip', $_SERVER['REMOTE_ADDR']);
 	$stmt->bindValue(':local_ip', $LOCAL_IP);
-	$stmt->bindValue(':title', $HOSTNAME);
+	$stmt->bindValue(':title', pts_strings::simple($HOSTNAME));
 	$stmt->bindValue(':current_time', phoromatic_server::current_time());
 	$stmt->bindValue(':machine_self_id', $PTS_MACHINE_SELF_ID);
 	$stmt->bindValue(':core_version', $CLIENT_CORE_VERSION);
 	$stmt->bindValue(':network_mac', $NETWORK_CLIENT_MAC);
 
@@ -242,11 +242,11 @@ if(strtotime($result['LastCommunication']) < (time() - 300))
 {
 	// Avoid useless updates to the database if it's close to the same info in past 2 minutes
 	$stmt = phoromatic_server::$db->prepare('UPDATE phoromatic_systems SET LastIP = :access_ip, LocalIP = :local_ip, LastCommunication = :current_time, Hardware = :client_hardware, Software = :client_software, SystemProperties = :phodevi_properties, ClientVersion = :client_version, MachineSelfID = :machine_self_id, NetworkMAC = :network_mac, NetworkWakeOnLAN = :network_wol, CoreVersion = :core_version WHERE AccountID = :account_id AND SystemID = :system_id');
 	$stmt->bindValue(':account_id', $ACCOUNT_ID);
 	$stmt->bindValue(':system_id', SYSTEM_ID);
-	$stmt->bindValue(':client_hardware', $CLIENT_HARDWARE);
+	$stmt->bindValue(':client_hardware', pts_strings::simple($CLIENT_HARDWARE));
 	$stmt->bindValue(':client_software', $CLIENT_SOFTWARE);
 	$stmt->bindValue(':phodevi_properties', $PHODEVI_PROPERTIES);
 	$stmt->bindValue(':client_version', $CLIENT_VERSION);
 	$stmt->bindValue(':core_version', $CLIENT_CORE_VERSION);
 	$stmt->bindValue(':access_ip', $_SERVER['REMOTE_ADDR']);
diff --git a/pts-core/phoromatic/public_html/public.php b/pts-core/phoromatic/public_html/public.php
index d666cc309..8b1f0b7d4 100644
--- a/pts-core/phoromatic/public_html/public.php
+++ b/pts-core/phoromatic/public_html/public.php
@@ -1,12 +1,12 @@
 <?php
 
 /*
 	Phoronix Test Suite
 	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
-	Copyright (C) 2008 - 2021, Phoronix Media
-	Copyright (C) 2008 - 2021, Michael Larabel
+	Copyright (C) 2008 - 2022, Phoronix Media
+	Copyright (C) 2008 - 2022, Michael Larabel
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
 	the Free Software Foundation; either version 3 of the License, or
 	(at your option) any later version.
@@ -128,23 +128,23 @@ if(!empty($result_ids))
 		{
 			case 'ORIGINAL_DATA':
 				$system_name = null;
 				break;
 			case 'SYSTEM_NAME':
-				$system_name = phoromatic_system_id_to_name($row['SystemID'], $row['AccountID']);
+				$system_name = phoromatic_server::system_id_to_name($row['SystemID'], $row['AccountID']);
 				break;
 			case 'TRIGGER':
 				$system_name = $row['Trigger'];
 				break;
 			case 'TRIGGER_AND_SYSTEM':
-				$system_name = phoromatic_system_id_to_name($row['SystemID'], $row['AccountID']) . ': ' . $row['Trigger'];
+				$system_name = phoromatic_server::system_id_to_name($row['SystemID'], $row['AccountID']) . ': ' . $row['Trigger'];
 				break;
 			case 'SYSTEM_AND_SCHEDULE':
 				$system_name = phoromatic_schedule_id_to_name($row['ScheduleID']) . ': ' . $row['Trigger'];
 				break;
 			default:
-				$system_name = phoromatic_system_id_to_name($row['SystemID'], $row['AccountID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
+				$system_name = phoromatic_server::system_id_to_name($row['SystemID'], $row['AccountID']) . ' - ' . phoromatic_schedule_id_to_name($row['ScheduleID']) . ' - ' . $row['Trigger'];
 		}
 
 		$rf = new pts_result_file($composite_xml);
 		$rf->rename_run(null, $system_name);
 		$result_files[] = $rf;
@@ -153,57 +153,15 @@ if(!empty($result_ids))
 	$attributes = array('new_result_file_title' => $result_file_title);
 	$result_file = new pts_result_file(null, true);
 	$result_file->merge($result_files, $attributes);
 	$extra_attributes = array();
 
-	$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>';
+	$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();
 }
 else
 {
 	$time_limit = false;
 	$time_str = false;
@@ -283,11 +241,11 @@ else
 		if($results > 150)
 		{
 			break;
 		}
 
-		$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 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>';
 		$results++;
 	}
 	if($results == 0)
 	{
 		$main .= '<li class="light" style="text-align: center;">No Results Found</li>';

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>';