public static function run($r)
 {
     $result = $r[0];
     $result_file = new pts_result_file($result);
     $result_file_identifiers = $result_file->get_system_identifiers();
     if (count($result_file_identifiers) < 2) {
         echo PHP_EOL . 'There are not multiple test runs in this result file.' . PHP_EOL;
         return false;
     }
     $remove_identifiers = explode(',', pts_user_io::prompt_text_menu('Select the test run(s) to remove', $result_file_identifiers, true));
     $keep_identifiers = array();
     foreach ($result_file_identifiers as $identifier) {
         if (!in_array($identifier, $remove_identifiers)) {
             array_push($keep_identifiers, $identifier);
         }
     }
     foreach (array('test-logs', 'system-logs', 'installation-logs') as $dir_name) {
         foreach ($remove_identifiers as $remove_identifier) {
             if (is_dir(PTS_SAVE_RESULTS_PATH . $r[0] . '/' . $dir_name . '/' . $remove_identifier)) {
                 pts_file_io::delete(PTS_SAVE_RESULTS_PATH . $r[0] . '/' . $dir_name . '/' . $remove_identifier, null, true);
             }
         }
     }
     $extract_select = new pts_result_merge_select($result, $keep_identifiers);
     $extract_result = pts_merge::merge_test_results($extract_select);
     pts_client::save_test_result($r[0] . '/composite.xml', $extract_result);
     pts_client::display_web_page(PTS_SAVE_RESULTS_PATH . $r[0] . '/index.html');
 }
 public static function run($r)
 {
     pts_client::$display->generic_heading('Available Tests');
     $test_count = 0;
     foreach (pts_openbenchmarking::available_tests(false) as $identifier) {
         $repo = substr($identifier, 0, strpos($identifier, '/'));
         $id = substr($identifier, strlen($repo) + 1);
         $repo_index = pts_openbenchmarking::read_repository_index($repo);
         if (!in_array(phodevi::operating_system(), $repo_index['tests'][$id]['supported_platforms']) || empty($repo_index['tests'][$id]['title'])) {
             // Don't show unsupported tests
             continue;
         }
         echo sprintf('%-30ls - %-35ls %-9ls', $identifier, $repo_index['tests'][$id]['title'], $repo_index['tests'][$id]['test_type']) . PHP_EOL;
         $test_count++;
     }
     foreach (pts_file_io::glob(PTS_TEST_PROFILE_PATH . 'local/*/test-definition.xml') as $path) {
         $test_profile = new pts_test_profile('local/' . basename(dirname($path)));
         if ($test_profile->get_title() != null && $test_profile->is_supported(false)) {
             echo sprintf('%-30ls - %-35ls %-9ls', $test_profile->get_identifier(), $test_profile->get_title(), $test_profile->get_test_hardware_type()) . PHP_EOL;
             $test_count++;
         }
     }
     if ($test_count == 0) {
         echo PHP_EOL . 'No tests found. Please check that you have Internet connectivity to download test profile data from OpenBenchmarking.org. The Phoronix Test Suite has documentation on configuring the network setup, proxy settings, and PHP network options. Please contact Phoronix Media if you continuing to experience problems.' . PHP_EOL . PHP_EOL;
     }
 }
 public static function render_page_process($PATH)
 {
     $suite_dir = phoromatic_server::phoromatic_account_suite_path($_SESSION['AccountID']);
     $main = '<h1>Local Suites</h1><p>These are test suites created by you or another account within your group. Suites are an easy collection of test profiles. New suits can be trivially made via the <a href="/?build_suite">build suite</a> page.</p>';
     $suite_count = 0;
     foreach (pts_file_io::glob($suite_dir . '*/suite-definition.xml') as $xml_path) {
         $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 .= '<div style="max-height: 200px; overflow-y: scroll;">';
         foreach ($test_suite->get_contained_test_result_objects() as $tro) {
             $main .= '<h3>' . $tro->test_profile->get_title() . ' [' . $tro->test_profile->get_identifier() . ']</h3>';
             $main .= '<p>' . $tro->get_arguments_description() . '</p>';
         }
         $main .= '</div>';
         $main .= '<hr />';
     }
     if ($suite_count == 0) {
         $main .= '<h1>No Test Suites Found</h1>';
     }
     echo phoromatic_webui_header_logged_in();
     echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
     echo phoromatic_webui_footer();
 }
 public static function client_commands_array()
 {
     $options = array('Test Installation' => array(), 'Testing' => array(), 'Batch Testing' => array(), 'OpenBenchmarking.org' => array(), 'System' => array(), 'Information' => array(), 'Asset Creation' => array(), 'Result Management' => array(), 'Result Analytics' => array(), 'Other' => array());
     foreach (pts_file_io::glob(PTS_COMMAND_PATH . '*.php') as $option_php_file) {
         $option_php = basename($option_php_file, '.php');
         $name = str_replace('_', '-', $option_php);
         if (!in_array(pts_strings::first_in_string($name, '-'), array('dump', 'task'))) {
             include_once $option_php_file;
             $reflect = new ReflectionClass($option_php);
             $constants = $reflect->getConstants();
             $doc_description = isset($constants['doc_description']) ? constant($option_php . '::doc_description') : 'No summary is available.';
             $doc_section = isset($constants['doc_section']) ? constant($option_php . '::doc_section') : 'Other';
             $name = isset($constants['doc_use_alias']) ? constant($option_php . '::doc_use_alias') : $name;
             $skip = isset($constants['doc_skip']) ? constant($option_php . '::doc_skip') : false;
             $doc_args = array();
             if ($skip) {
                 continue;
             }
             if (method_exists($option_php, 'argument_checks')) {
                 $doc_args = call_user_func(array($option_php, 'argument_checks'));
             }
             if (!empty($doc_section) && !isset($options[$doc_section])) {
                 $options[$doc_section] = array();
             }
             array_push($options[$doc_section], array($name, $doc_args, $doc_description));
         }
     }
     return $options;
 }
 public static function delete($object, $ignore_files = null, $remove_root_directory = false)
 {
     // Delete files and/or directories
     if ($object == false) {
         return false;
     }
     if (is_dir($object)) {
         $object = pts_strings::add_trailing_slash($object);
     }
     foreach (pts_file_io::glob($object . '*') as $to_remove) {
         if (is_file($to_remove) || is_link($to_remove)) {
             if (is_array($ignore_files) && in_array(basename($to_remove), $ignore_files)) {
                 continue;
                 // Don't remove the file
             } else {
                 unlink($to_remove);
             }
         } else {
             if (is_dir($to_remove)) {
                 self::delete($to_remove, $ignore_files, true);
             }
         }
     }
     if ($remove_root_directory && is_dir($object) && count(pts_file_io::glob($object . '/*')) == 0) {
         rmdir($object);
     }
 }
 public function get_vendors_list()
 {
     $package_files = pts_file_io::glob(PTS_EXDEP_PATH . 'xml/*-packages.xml');
     foreach ($package_files as &$file) {
         $file = basename(substr($file, 0, strpos($file, '-packages.xml')));
     }
     return $package_files;
 }
 public static function run($r)
 {
     pts_file_io::unlink(getenv('PTS_EXT_LAUNCH_SCRIPT_DIR') . '/web-server-launcher');
     if (PHP_VERSION_ID < 50400) {
         echo 'Running an unsupported PHP version. PHP 5.4+ is required to use this feature.' . PHP_EOL . PHP_EOL;
         return false;
     }
     $server_launcher = '#!/bin/sh' . PHP_EOL;
     $web_port = 0;
     $remote_access = pts_config::read_user_config('PhoronixTestSuite/Options/Server/RemoteAccessPort', 'FALSE');
     $remote_access = is_numeric($remote_access) && $remote_access > 1 ? $remote_access : false;
     $blocked_ports = array(2049, 3659, 4045, 6000);
     if ($remote_access) {
         // ALLOWING SERVER TO BE REMOTELY ACCESSIBLE
         $server_ip = '0.0.0.0';
         $fp = false;
         $errno = null;
         $errstr = null;
         if (($fp = fsockopen('127.0.0.1', $remote_access, $errno, $errstr, 5)) != false) {
             trigger_error('Port ' . $remote_access . ' is already in use by another server process. Close that process or change the Phoronix Test Suite server port via ' . pts_config::get_config_file_location() . ' to proceed.', E_USER_ERROR);
             fclose($fp);
             return false;
         } else {
             $web_port = $remote_access;
             $web_socket_port = pts_config::read_user_config('PhoronixTestSuite/Options/Server/WebSocketPort', '');
             if ($web_socket_port == null || !is_numeric($web_socket_port)) {
                 $web_socket_port = $web_port - 1;
             }
         }
     } else {
         echo PHP_EOL . PHP_EOL . 'You must first configure the remote GUI/WEBUI settings via:' . pts_config::get_config_file_location() . PHP_EOL . PHP_EOL;
         return false;
     }
     // WebSocket Server Setup
     $server_launcher .= 'export PTS_WEBSOCKET_PORT=' . $web_socket_port . PHP_EOL;
     $server_launcher .= 'export PTS_WEBSOCKET_SERVER=GUI' . PHP_EOL;
     $server_launcher .= 'cd ' . getenv('PTS_DIR') . ' && PTS_MODE="CLIENT" ' . getenv('PHP_BIN') . ' pts-core/phoronix-test-suite.php start-ws-server &' . PHP_EOL;
     $server_launcher .= 'websocket_server_pid=$!' . PHP_EOL;
     // HTTP Server Setup
     if (strpos(getenv('PHP_BIN'), 'hhvm')) {
         echo PHP_EOL . 'Unfortunately, the HHVM built-in web server has abandoned upstream. Users will need to use the PHP binary or other alternatives.' . PHP_EOL . PHP_EOL;
         return false;
     } else {
         $server_launcher .= getenv('PHP_BIN') . ' -S ' . $server_ip . ':' . $web_port . ' -t ' . PTS_CORE_PATH . 'web-interface/ 2> /dev/null  &' . PHP_EOL;
         //2> /dev/null
     }
     $server_launcher .= 'http_server_pid=$!' . PHP_EOL;
     $server_launcher .= 'sleep 1' . PHP_EOL;
     $server_launcher .= 'echo "The Web Interface Is Accessible At: http://localhost:' . $web_port . '"' . PHP_EOL;
     $server_launcher .= PHP_EOL . 'echo -n "Press [ENTER] to kill server..."' . PHP_EOL . 'read var_name';
     // Shutdown / Kill Servers
     $server_launcher .= PHP_EOL . 'kill $http_server_pid';
     $server_launcher .= PHP_EOL . 'kill $websocket_server_pid';
     $server_launcher .= PHP_EOL . 'rm -f ~/.phoronix-test-suite/run-lock*';
     file_put_contents(getenv('PTS_EXT_LAUNCH_SCRIPT_DIR') . '/web-server-launcher', $server_launcher);
 }
 public static function run($r)
 {
     $identifier = $r[0];
     $test_xml_files = pts_file_io::glob(PTS_SAVE_RESULTS_PATH . $identifier . '/test-*.xml');
     if (count($test_xml_files) == 0) {
         echo PHP_EOL . 'No test XML data was found.' . PHP_EOL;
         return false;
     }
     pts_client::save_test_result($identifier . '/composite.xml', pts_merge::merge_test_results_array($test_xml_files));
     pts_client::regenerate_graphs($identifier, 'The ' . $identifier . ' result file XML has been rebuilt.');
 }
 public static function run($r)
 {
     $options = array();
     foreach (pts_file_io::glob(PTS_COMMAND_PATH . '*.php') as $option_php) {
         $name = str_replace('_', '-', basename($option_php, '.php'));
         if (!in_array(pts_strings::first_in_string($name, '-'), array('dump', 'debug', 'task'))) {
             array_push($options, $name);
         }
     }
     $is_true = isset($r[0]) && $r[0] == 'TRUE';
     echo implode($is_true ? ' ' : PHP_EOL, $options) . ($is_true ? null : PHP_EOL);
 }
 public static function read_sensor()
 {
     // Reads the system's temperature
     $temp_c = -1;
     if (phodevi::is_linux()) {
         $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/device/temp3_input', 'POSITIVE_NUMERIC', array('name' => '!coretemp,!radeon,!nouveau'));
         if ($raw_temp == -1) {
             $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/device/temp2_input', 'POSITIVE_NUMERIC', array('name' => '!coretemp,!radeon,!nouveau'));
         }
         if ($raw_temp == -1) {
             $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/device/temp1_input', 'POSITIVE_NUMERIC', array('name' => '!coretemp,!radeon,!nouveau'));
         }
         if ($raw_temp == -1) {
             $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/temp1_input', 'POSITIVE_NUMERIC');
         }
         if ($raw_temp != -1) {
             if ($raw_temp > 1000) {
                 $raw_temp = $raw_temp / 1000;
             }
             $temp_c = pts_math::set_precision($raw_temp, 2);
         }
         if ($temp_c == -1) {
             $acpi = phodevi_linux_parser::read_acpi(array('/thermal_zone/THM1/temperature', '/thermal_zone/TZ00/temperature', '/thermal_zone/TZ01/temperature'), 'temperature');
             if (($end = strpos($acpi, ' ')) > 0) {
                 $temp_c = substr($acpi, 0, $end);
             }
         }
         if ($temp_c == -1) {
             $sensors = phodevi_linux_parser::read_sensors(array('Sys Temp', 'Board Temp'));
             if ($sensors != false && is_numeric($sensors)) {
                 $temp_c = $sensors;
             }
         }
         if ($temp_c == -1 && is_file('/sys/class/thermal/thermal_zone0/temp')) {
             $temp_c = pts_file_io::file_get_contents('/sys/class/thermal/thermal_zone0/temp');
             if ($temp_c > 1000) {
                 $temp_c = pts_math::set_precision($temp_c / 1000, 1);
             }
         }
     } else {
         if (phodevi::is_bsd()) {
             $acpi = phodevi_bsd_parser::read_sysctl(array('hw.sensors.acpi_tz1.temp0', 'hw.acpi.thermal.tz1.temperature'));
             if (($end = strpos($acpi, ' degC')) > 0 || ($end = strpos($acpi, 'C')) > 0) {
                 $acpi = substr($acpi, 0, $end);
                 if (is_numeric($acpi)) {
                     $temp_c = $acpi;
                 }
             }
         }
     }
     return $temp_c;
 }
 public static function get_supported_devices()
 {
     if (phodevi::is_linux()) {
         $blockdev_dir = '/sys/block/';
         $glob_regex = '{[shvm]d*,nvme*,mmcblk*}';
         $disk_array = pts_file_io::glob($blockdev_dir . $glob_regex, GLOB_BRACE);
         $supported = array();
         foreach ($disk_array as $check_disk) {
             $stat_path = $check_disk . '/stat';
             if (is_file($stat_path) && pts_file_io::file_get_contents($stat_path) != null) {
                 array_push($supported, basename($check_disk));
             }
         }
         return $supported;
     }
     return NULL;
 }
 public static function read_sensor()
 {
     $iowait = -1;
     if (phodevi::is_linux() && is_file('/proc/stat')) {
         $start_stat = pts_file_io::file_get_contents('/proc/stat');
         sleep(1);
         $end_stat = pts_file_io::file_get_contents('/proc/stat');
         $start_stat = explode(' ', substr($start_stat, 0, strpos($start_stat, "\n")));
         $end_stat = explode(' ', substr($end_stat, 0, strpos($end_stat, "\n")));
         for ($i = 2, $diff_cpu_total = 0; $i < 9; $i++) {
             $diff_cpu_total += $end_stat[$i] - $start_stat[$i];
         }
         $diff_iowait = $end_stat[6] - $start_stat[6];
         $iowait = pts_math::set_precision(1000 * $diff_iowait / $diff_cpu_total / 10, 2);
     }
     return $iowait;
 }
 public static function get_supported_devices()
 {
     if (phodevi::is_linux()) {
         $disk_list = shell_exec("ls -1 /sys/class/block | grep '^[shv]d[a-z]\$'");
         // TODO make this native PHP
         $disk_array = explode("\n", $disk_list);
         $supported = array();
         foreach ($disk_array as $check_disk) {
             $stat_path = '/sys/class/block/' . $check_disk . '/stat';
             if (is_file($stat_path) && pts_file_io::file_get_contents($stat_path) != null) {
                 array_push($supported, $check_disk);
             }
         }
         return $supported;
     }
     return NULL;
 }
 public static function audio_processor_string()
 {
     $audio = null;
     if (phodevi::is_macosx()) {
         // TODO: implement
     } else {
         if (phodevi::is_bsd()) {
             foreach (array('dev.hdac.0.%desc') as $dev) {
                 $dev = phodevi_bsd_parser::read_sysctl($dev);
                 if (!empty($dev)) {
                     $audio = $dev;
                 }
             }
         } else {
             if (phodevi::is_windows()) {
                 // TODO: implement
             } else {
                 if (phodevi::is_linux()) {
                     foreach (pts_file_io::glob('/sys/class/sound/card*/hwC0D*/vendor_name') as $vendor_name) {
                         $card_dir = dirname($vendor_name) . '/';
                         if (!is_readable($card_dir . 'chip_name')) {
                             continue;
                         }
                         $vendor_name = pts_file_io::file_get_contents($vendor_name);
                         $chip_name = pts_file_io::file_get_contents($card_dir . 'chip_name');
                         $audio = $vendor_name . ' ' . $chip_name;
                         if (strpos($chip_name, 'HDMI') !== false || strpos($chip_name, 'DP') !== false) {
                             // If HDMI is in the audio string, likely the GPU-provided audio, so try to find the mainboard otherwise
                             $audio = null;
                         } else {
                             break;
                         }
                     }
                     if ($audio == null) {
                         $audio = phodevi_linux_parser::read_pci('Multimedia audio controller');
                     }
                     if ($audio == null) {
                         $audio = phodevi_linux_parser::read_pci('Audio device');
                     }
                 }
             }
         }
     }
     return $audio;
 }
 public static function read_sensor()
 {
     // speed in MB/s
     $speed = -1;
     if (phodevi::is_linux()) {
         static $sys_disk = null;
         if ($sys_disk == null) {
             foreach (pts_file_io::glob('/sys/class/block/sd*/stat') as $check_disk) {
                 if (pts_file_io::file_get_contents($check_disk) != null) {
                     $sys_disk = $check_disk;
                     break;
                 }
             }
         }
         $speed = phodevi_linux_parser::read_sys_disk_speed($sys_disk, 'READ');
     }
     return $speed;
 }
 public static function read_sensor()
 {
     // Report graphics processor temperature
     $temp_c = -1;
     if (phodevi::is_nvidia_graphics()) {
         $temp_c = phodevi_parser::read_nvidia_extension('GPUCoreTemp');
     } else {
         if (phodevi::is_ati_graphics() && phodevi::is_linux()) {
             $temp_c = phodevi_linux_parser::read_ati_overdrive('Temperature');
         } else {
             foreach (array_merge(array('/sys/class/drm/card0/device/temp1_input'), pts_file_io::glob('/sys/class/drm/card0/device/hwmon/hwmon*/temp1_input')) as $temp_input) {
                 // This works for at least Nouveau driver with Linux 2.6.37 era DRM
                 if (is_readable($temp_input) == false) {
                     continue;
                 }
                 $temp_input = pts_file_io::file_get_contents($temp_input);
                 if (is_numeric($temp_input)) {
                     if ($temp_input > 1000) {
                         $temp_input /= 1000;
                     }
                     $temp_c = $temp_input;
                     break;
                 }
             }
             if ($temp_c == -1 && is_readable('/sys/kernel/debug/dri/0/i915_emon_status')) {
                 // Intel thermal
                 $i915_emon_status = file_get_contents('/sys/kernel/debug/dri/0/i915_emon_status');
                 $temp = strpos($i915_emon_status, 'GMCH temp: ');
                 if ($temp !== false) {
                     $temp = substr($i915_emon_status, $temp + 11);
                     $temp = substr($temp, 0, strpos($temp, PHP_EOL));
                     if (is_numeric($temp) && $temp > 0) {
                         $temp_c = $temp;
                     }
                 }
             }
         }
     }
     if ($temp_c > 1000 || $temp_c < 9) {
         // Invalid data
         return -1;
     }
     return $temp_c;
 }
 public static function read_sensor()
 {
     // Determine the current processor frequency
     $cpu_core = 0;
     // TODO: for now just monitoring the first core
     $info = 0;
     if (phodevi::is_linux()) {
         // First, the ideal way, with modern CPUs using CnQ or EIST and cpuinfo reporting the current
         if (is_file('/sys/devices/system/cpu/cpu' . $cpu_core . '/cpufreq/scaling_cur_freq')) {
             $info = pts_file_io::file_get_contents('/sys/devices/system/cpu/cpu' . $cpu_core . '/cpufreq/scaling_cur_freq');
             $info = intval($info) / 1000;
         } else {
             if (is_file('/proc/cpuinfo')) {
                 $cpu_speeds = phodevi_linux_parser::read_cpuinfo('cpu MHz');
                 if (isset($cpu_speeds[0])) {
                     $cpu_core = isset($cpu_speeds[$cpu_core]) ? $cpu_core : 0;
                     $info = intval($cpu_speeds[$cpu_core]);
                 }
             }
         }
     } else {
         if (phodevi::is_solaris()) {
             $info = shell_exec('psrinfo -v | grep MHz');
             $info = substr($info, strrpos($info, 'at') + 3);
             $info = trim(substr($info, 0, strpos($info, 'MHz')));
         } else {
             if (phodevi::is_bsd()) {
                 $info = phodevi_bsd_parser::read_sysctl('dev.cpu.0.freq');
             } else {
                 if (phodevi::is_macosx()) {
                     $info = phodevi_osx_parser::read_osx_system_profiler('SPHardwareDataType', 'ProcessorSpeed');
                     if (($cut_point = strpos($info, ' ')) > 0) {
                         $info = substr($info, 0, $cut_point);
                         $info = str_replace(',', '.', $info);
                     }
                     if ($info < 100) {
                         $info *= 1000;
                     }
                 }
             }
         }
     }
     return pts_math::set_precision($info, 2);
 }
 public static function run($r)
 {
     if (pts_openbenchmarking_client::user_name() == false) {
         echo PHP_EOL . 'You must first be logged into an OpenBenchmarking.org account.' . PHP_EOL;
         echo PHP_EOL . 'Create An Account: http://openbenchmarking.org/';
         echo PHP_EOL . 'Log-In Command: phoronix-test-suite openbenchmarking-setup' . PHP_EOL . PHP_EOL;
         return false;
     }
     foreach (pts_types::identifiers_to_test_profile_objects($r, true, true) as $test_profile) {
         // validate_test_profile
         if (pts_validation::validate_test_profile($test_profile)) {
             pts_client::$display->generic_heading($test_profile);
             $zip_file = PTS_OPENBENCHMARKING_SCRATCH_PATH . $test_profile->get_identifier_base_name() . '-' . $test_profile->get_test_profile_version() . '.zip';
             $zip_created = pts_compression::zip_archive_create($zip_file, pts_file_io::glob($test_profile->get_resource_dir() . '*'));
             if ($zip_created == false) {
                 echo PHP_EOL . 'Failed to create zip file.' . PHP_EOL;
                 return false;
             }
             if (filesize($zip_file) > 104857) {
                 echo PHP_EOL . 'The test profile package is too big.' . PHP_EOL;
                 return false;
             }
             $commit_description = pts_user_io::prompt_user_input('Enter a test commit description', false);
             echo PHP_EOL;
             $server_response = pts_openbenchmarking::make_openbenchmarking_request('upload_test_profile', array('tp_identifier' => $test_profile->get_identifier_base_name(), 'tp_sha1' => sha1_file($zip_file), 'tp_zip' => base64_encode(file_get_contents($zip_file)), 'tp_zip_name' => basename($zip_file), 'commit_description' => $commit_description));
             echo PHP_EOL;
             $json = json_decode($server_response, true);
             if (isset($json['openbenchmarking']['upload']['error']) && !empty($json['openbenchmarking']['upload']['error'])) {
                 echo 'ERROR: ' . $json['openbenchmarking']['upload']['error'] . PHP_EOL;
             }
             if (isset($json['openbenchmarking']['upload']['id']) && !empty($json['openbenchmarking']['upload']['id'])) {
                 echo 'Command: phoronix-test-suite benchmark ' . $json['openbenchmarking']['upload']['id'] . PHP_EOL;
             }
             if (isset($json['openbenchmarking']['upload']['url']) && !empty($json['openbenchmarking']['upload']['url'])) {
                 pts_openbenchmarking::refresh_repository_lists(null, true);
                 echo 'URL: ' . $json['openbenchmarking']['upload']['url'] . PHP_EOL;
             }
             echo PHP_EOL;
             // TODO: chmod +x the .sh files, appropriate permissions elsewhere
             unlink($zip_file);
         }
     }
 }
 private function cpu_freq_linux()
 {
     $frequency = -1;
     // First, the ideal way, with modern CPUs using CnQ or EIST and cpuinfo reporting the current frequency.
     if (is_file('/sys/devices/system/cpu/' . $this->cpu_to_monitor . '/cpufreq/scaling_cur_freq')) {
         $frequency = pts_file_io::file_get_contents('/sys/devices/system/cpu/' . $this->cpu_to_monitor . '/cpufreq/scaling_cur_freq');
         $frequency = intval($frequency) / 1000;
     } else {
         if (is_file('/proc/cpuinfo')) {
             $cpu_speeds = phodevi_linux_parser::read_cpuinfo('cpu MHz');
             $cpu_number = intval(substr($this->cpu_to_monitor, 3));
             //cut 'cpu' from the beginning
             if (!isset($cpu_speeds[$cpu_number])) {
                 return -1;
             }
             $frequency = intval($cpu_speeds[$cpu_number]);
         }
     }
     return $frequency;
 }
 public static function run($r)
 {
     $result_file = new pts_result_file($r[0]);
     $result_file_identifiers = $result_file->get_system_identifiers();
     if (count($result_file_identifiers) < 2) {
         echo PHP_EOL . 'There are not multiple test runs in this result file.' . PHP_EOL;
         return false;
     }
     $remove_identifiers = explode(',', pts_user_io::prompt_text_menu('Select the test run(s) to remove', $result_file_identifiers, true));
     $result_file->remove_run($remove_identifiers);
     $result_dir = dirname($result_file->get_file_location()) . '/';
     foreach (array('test-logs', 'system-logs', 'installation-logs') as $dir_name) {
         foreach ($remove_identifiers as $remove_identifier) {
             if (is_dir($result_dir . $dir_name . '/' . $remove_identifier)) {
                 pts_file_io::delete($result_dir . $dir_name . '/' . $remove_identifier, null, true);
             }
         }
     }
     pts_client::save_test_result($result_file->get_file_location(), $result_file->get_xml());
     pts_client::display_web_page($result_dir . '/index.html');
 }
    public static function render_page_process($PATH)
    {
        echo phoromatic_webui_header_logged_in();
        $main = '<h1>Cache Settings</h1>
				<h2>Test Profile Download Cache</h2>
				<p>Below are a list of files for verification/debugging purposes that are currently cached by the Phoromatic Server and available for Phoronix Test Suite client systems to download. These are files that are needed by various test profiles in the Phoronix Test Suite. To add more data to this Phoromatic Server cache, from the server run <strong>phoronix-test-suite make-download-cache</strong> while passing the names of any tests/suites you wish to have download and generate a cache for so they can be made available to the Phoronix Test Suite clients on your network.</p>';
        $dc = pts_strings::add_trailing_slash(pts_strings::parse_for_home_directory(pts_config::read_user_config('PhoronixTestSuite/Options/Installation/CacheDirectory', PTS_DOWNLOAD_CACHE_PATH)));
        $dc_exists = is_file($dc . 'pts-download-cache.json');
        if ($dc_exists) {
            $cache_json = file_get_contents($dc . 'pts-download-cache.json');
            $cache_json = json_decode($cache_json, true);
        }
        if (is_file($dc . 'pts-download-cache.json')) {
            if ($cache_json && isset($cache_json['phoronix-test-suite']['download-cache'])) {
                $total_file_size = 0;
                $main .= '<table style="margin: 0 auto;"><tr><th>File</th><th>Size</th></tr>';
                foreach ($cache_json['phoronix-test-suite']['download-cache'] as $file_name => $inf) {
                    $total_file_size += $cache_json['phoronix-test-suite']['download-cache'][$file_name]['file_size'];
                    $main .= '<tr><td>' . $file_name . '</td><td>' . round(max(0.1, $cache_json['phoronix-test-suite']['download-cache'][$file_name]['file_size'] / 1000000), 1) . 'MB</td></tr>';
                }
                $main .= '</table>';
                $main .= '<p><strong>' . count($cache_json['phoronix-test-suite']['download-cache']) . ' Files / ' . round($total_file_size / 1000000) . ' MB Cache Size</strong></p>';
            }
        } else {
            $main .= '<h3>No download cache file could be found; on the Phoromatic Server you should run <strong>phoronix-test-suite make-download-cache</strong>.</h3>';
            // TODO XXX implement from the GUI
        }
        $main .= '<hr /><h2>OpenBenchmarking.org Cache Data</h2>';
        $main .= '<p>Below is information pertaining to the OpenBenchmarking.org cache present on the Phoromatic Server. To update this cache, run <strong>phoronix-test-suite make-openbenchmarking-cache</strong> from the server.</p>';
        $index_files = pts_file_io::glob(PTS_OPENBENCHMARKING_SCRATCH_PATH . '*.index');
        $main .= '<table style="margin: 0 auto;"><tr><th>Repository</th><th>Last Updated</th></tr>';
        foreach ($index_files as $index_file) {
            $index_data = json_decode(file_get_contents($index_file), true);
            $main .= '<tr><td>' . basename($index_file, '.index') . '</td><td>' . date('d F Y H:i', $index_data['main']['generated']) . '</td></tr>';
        }
        $main .= '</table>';
        echo phoromatic_webui_main($main, phoromatic_webui_right_panel_logged_in());
        echo phoromatic_webui_footer();
    }
 private function sys_temp_linux()
 {
     $temp_c = -1;
     $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/device/temp3_input', 'POSITIVE_NUMERIC', array('name' => '!coretemp,!radeon,!nouveau'));
     if ($raw_temp == -1) {
         $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/device/temp2_input', 'POSITIVE_NUMERIC', array('name' => '!coretemp,!radeon,!nouveau'));
     }
     if ($raw_temp == -1) {
         $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/device/temp1_input', 'POSITIVE_NUMERIC', array('name' => '!coretemp,!radeon,!nouveau'));
     }
     if ($raw_temp == -1) {
         $raw_temp = phodevi_linux_parser::read_sysfs_node('/sys/class/hwmon/hwmon*/temp1_input', 'POSITIVE_NUMERIC');
     }
     if ($raw_temp != -1) {
         if ($raw_temp > 1000) {
             $raw_temp = $raw_temp / 1000;
         }
         $temp_c = pts_math::set_precision($raw_temp, 2);
     }
     if ($temp_c == -1) {
         $acpi = phodevi_linux_parser::read_acpi(array('/thermal_zone/THM1/temperature', '/thermal_zone/TZ00/temperature', '/thermal_zone/TZ01/temperature'), 'temperature');
         if (($end = strpos($acpi, ' ')) > 0) {
             $temp_c = substr($acpi, 0, $end);
         }
     }
     if ($temp_c == -1) {
         $sensors = phodevi_linux_parser::read_sensors(array('Sys Temp', 'Board Temp'));
         if ($sensors != false && is_numeric($sensors)) {
             $temp_c = $sensors;
         }
     }
     if ($temp_c == -1 && is_file('/sys/class/thermal/thermal_zone0/temp')) {
         $temp_c = pts_file_io::file_get_contents('/sys/class/thermal/thermal_zone0/temp');
         if ($temp_c > 1000) {
             $temp_c = pts_math::set_precision($temp_c / 1000, 1);
         }
     }
     return $temp_c;
 }
 protected static function search_local_test_suites($q)
 {
     $ret = null;
     $suite_dir = phoromatic_server::phoromatic_account_suite_path($_SESSION['AccountID']);
     foreach (pts_file_io::glob($suite_dir . '*/suite-definition.xml') as $xml_path) {
         $id = basename(dirname($xml_path));
         $test_suite = new pts_test_suite($xml_path);
         $match = false;
         if (stripos($test_suite->get_title(), $q) === 0 || stripos($test_suite->get_description(), $q) !== false) {
             $match = true;
         } else {
             foreach ($test_suite->get_contained_test_result_objects() as $tro) {
                 if (stripos($tro->test_profile->get_identifier(), $q) !== false || stripos($tro->test_profile->get_title(), $q) === 0) {
                     $match = true;
                 }
             }
         }
         if ($match) {
             $ret .= '<h3>' . $test_suite->get_title() . '</h3><p>' . $test_suite->get_description() . '<br /><a href="/?local_suites#' . $id . '">More Details</a></p>';
         }
     }
     return $ret;
 }
 protected static function setup_test_install_directory(&$test_install_request, $remove_old_files = false)
 {
     $identifier = $test_install_request->test_profile->get_identifier();
     pts_file_io::mkdir($test_install_request->test_profile->get_install_dir());
     if ($remove_old_files) {
         // Remove any (old) files that were installed
         $ignore_files = array('pts-install.xml', 'install-failed.log');
         foreach ($test_install_request->get_download_objects() as $download_object) {
             $ignore_files[] = $download_object->get_filename();
         }
         pts_file_io::delete($test_install_request->test_profile->get_install_dir(), $ignore_files);
     }
     pts_file_io::symlink(pts_core::user_home_directory() . '.Xauthority', $test_install_request->test_profile->get_install_dir() . '.Xauthority');
     pts_file_io::symlink(pts_core::user_home_directory() . '.drirc', $test_install_request->test_profile->get_install_dir() . '.drirc');
 }
 public static function render_page_process($PATH)
 {
     if ($_SESSION['AdminLevel'] != -40) {
         header('Location: /?main');
     }
     $main = null;
     if (isset($_POST['new_phoromatic_path']) && !empty($_POST['new_phoromatic_path'])) {
         $new_dir = dirname($_POST['new_phoromatic_path']);
         if (!is_dir($new_dir)) {
             $main .= '<h2 style="color: red;"><em>' . $new_dir . '</em> must be a valid directory.</h2>';
         } else {
             if (!is_writable($new_dir)) {
                 $main .= '<h2 style="color: red;"><em>' . $new_dir . '</em> is not a writable location.</h2>';
             } else {
                 if (!is_dir($_POST['new_phoromatic_path'])) {
                     if (mkdir($_POST['new_phoromatic_path']) == false) {
                         $main .= '<h2 style="color: red;">Failed to make directory <em>' . $_POST['new_phoromatic_path'] . '</em>.</h2>';
                     }
                 }
                 if (is_dir($_POST['new_phoromatic_path'])) {
                     $new_phoromatic_dir = pts_strings::add_trailing_slash($_POST['new_phoromatic_path']);
                     $d = glob($new_phoromatic_dir . '*');
                     if (!empty($d)) {
                         $new_phoromatic_dir .= 'phoromatic/';
                         pts_file_io::mkdir($new_phoromatic_dir);
                     }
                     $d = glob($new_phoromatic_dir . '*');
                     if (!empty($d)) {
                         $main .= '<h2 style="color: red;"><em>' . $new_phoromatic_dir . '</em> must be an empty directory.</h2>';
                     } else {
                         if (pts_file_io::copy(phoromatic_server::phoromatic_path(), $new_phoromatic_dir)) {
                             pts_config::user_config_generate(array('PhoromaticStorage' => $new_phoromatic_dir));
                             header('Location: /?admin');
                         } else {
                             $main .= '<h2 style="color: red;"><em>Failed to copy old Phoromatic data to new location.</h2>';
                         }
                     }
                 }
             }
         }
     }
     if (isset($_POST['new_dc_path']) && !empty($_POST['new_dc_path'])) {
         $new_dir = dirname($_POST['new_dc_path']);
         if (!is_dir($new_dir)) {
             $main .= '<h2 style="color: red;"><em>' . $new_dir . '</em> must be a valid directory.</h2>';
         } else {
             if (!is_writable($new_dir)) {
                 $main .= '<h2 style="color: red;"><em>' . $new_dir . '</em> is not a writable location.</h2>';
             } else {
                 if (!is_dir($_POST['new_dc_path'])) {
                     if (mkdir($_POST['new_dc_path']) == false) {
                         $main .= '<h2 style="color: red;">Failed to make directory <em>' . $_POST['new_dc_path'] . '</em>.</h2>';
                     }
                 }
                 if (is_dir($_POST['new_dc_path'])) {
                     $new_dc_dir = pts_strings::add_trailing_slash($_POST['new_dc_path']);
                     if (pts_file_io::copy(pts_strings::add_trailing_slash(pts_client::parse_home_directory(pts_config::read_user_config('PhoronixTestSuite/Options/Installation/CacheDirectory', PTS_DOWNLOAD_CACHE_PATH))), $new_dc_dir)) {
                         pts_config::user_config_generate(array('CacheDirectory' => $new_dc_dir));
                         header('Location: /?admin');
                     } else {
                         $main .= '<h2 style="color: red;"><em>Failed to copy old Phoromatic data to new location.</h2>';
                     }
                 }
             }
         }
     }
     if (isset($_POST['new_proxy_address']) && isset($_POST['new_proxy_port'])) {
         if (pts_network::http_get_contents('http://www.phoronix-test-suite.com/PTS', $_POST['new_proxy_address'], $_POST['new_proxy_port']) == 'PTS') {
             pts_config::user_config_generate(array('PhoronixTestSuite/Options/Networking/ProxyAddress' => $_POST['new_proxy_address'], 'PhoronixTestSuite/Options/Networking/ProxyPort' => $_POST['new_proxy_port']));
         } else {
             $main .= '<h2 style="color: red;">Failed to connect via proxy server.</h2>';
         }
     }
     if (isset($_POST['new_http_port']) && isset($_POST['new_ws_port'])) {
         if (empty($_POST['new_http_port']) || !is_numeric($_POST['new_http_port']) && $_POST['new_http_port'] != 'RANDOM') {
             $main .= '<h2 style="color: red;">The HTTP port must be a valid port number or <em>RANDOM</em>.</h2>';
         }
         if (empty($_POST['new_ws_port']) || !is_numeric($_POST['new_ws_port']) && $_POST['new_ws_port'] != 'RANDOM') {
             $main .= '<h2 style="color: red;">The WebSocket port must be a valid port number or <em>RANDOM</em>.</h2>';
         }
         pts_config::user_config_generate(array('PhoronixTestSuite/Options/Server/RemoteAccessPort' => $_POST['new_http_port'], 'PhoronixTestSuite/Options/Server/WebSocketPort' => $_POST['new_ws_port']));
     }
     if (isset($_POST['add_new_users_to_account'])) {
         if (empty($_POST['add_new_users_to_account'])) {
             phoromatic_server::save_setting('add_new_users_to_account', null);
         } else {
             $stmt = phoromatic_server::$db->prepare('SELECT COUNT(AccountID) AS AccountHitCount FROM phoromatic_accounts WHERE AccountID = :account_id');
             $stmt->bindValue(':account_id', $_POST['add_new_users_to_account']);
             $result = $stmt->execute();
             $row = $result->fetchArray();
             if (empty($row['AccountHitCount'])) {
                 $main .= '<h2 style="color: red;"><em>' . $_POST['add_new_users_to_account'] . '</em> is not a valid account ID.</h2>';
             } else {
                 phoromatic_server::save_setting('add_new_users_to_account', $_POST['add_new_users_to_account']);
             }
         }
     }
     if (isset($_POST['account_creation_alt'])) {
         phoromatic_server::save_setting('account_creation_alt', $_POST['account_creation_alt']);
     }
     if (isset($_POST['main_page_message'])) {
         phoromatic_server::save_setting('main_page_message', $_POST['main_page_message']);
     }
     if (isset($_POST['force_result_sharing'])) {
         phoromatic_server::save_setting('force_result_sharing', $_POST['force_result_sharing']);
     }
     if (isset($_POST['show_local_tests_only'])) {
         phoromatic_server::save_setting('show_local_tests_only', $_POST['show_local_tests_only']);
     }
     if (isset($_POST['new_admin_support_email'])) {
         phoromatic_server::save_setting('admin_support_email', $_POST['new_admin_support_email']);
     }
     if (isset($_POST['rebuild_results_db'])) {
         foreach (pts_file_io::glob(phoromatic_server::phoromatic_path() . 'accounts/*/results/*/composite.xml') as $composite_xml) {
             $account_id = basename(dirname(dirname(dirname($composite_xml))));
             $upload_id = basename(dirname($composite_xml));
             $result_file = new pts_result_file($composite_xml);
             // Validate the XML
             $relative_id = 0;
             foreach ($result_file->get_result_objects() as $result_object) {
                 $relative_id++;
                 $stmt = phoromatic_server::$db->prepare('INSERT INTO phoromatic_results_results (AccountID, UploadID, AbstractID, TestProfile, ComparisonHash) VALUES (:account_id, :upload_id, :abstract_id, :test_profile, :comparison_hash)');
                 $stmt->bindValue(':account_id', $account_id);
                 $stmt->bindValue(':upload_id', $upload_id);
                 $stmt->bindValue(':abstract_id', $relative_id);
                 $stmt->bindValue(':test_profile', $result_object->test_profile->get_identifier());
                 $stmt->bindValue(':comparison_hash', $result_object->get_comparison_hash(true, false));
                 $result = $stmt->execute();
             }
             if ($relative_id > 0) {
                 foreach ($result_file->get_systems() as $s) {
                     $stmt = phoromatic_server::$db->prepare('INSERT INTO phoromatic_results_systems (AccountID, UploadID, SystemIdentifier, Hardware, Software) VALUES (:account_id, :upload_id, :system_identifier, :hardware, :software)');
                     $stmt->bindValue(':account_id', $account_id);
                     $stmt->bindValue(':upload_id', $upload_id);
                     $stmt->bindValue(':system_identifier', $s->get_identifier());
                     $stmt->bindValue(':hardware', $s->get_hardware());
                     $stmt->bindValue(':software', $s->get_software());
                     $result = $stmt->execute();
                 }
             }
         }
     }
     $main .= '<h1>Phoromatic Server Configuration</h1>';
     $main .= '<h2>Phoromatic Storage Location</h2>';
     $main .= '<p>The Phoromatic Storage location is where all Phoromatic-specific test results, account data, and other information is archived. This path is controlled via the <em>' . pts_config::get_config_file_location() . '</em> configuration file with the <em>PhoromaticStorage</em> element. Adjusting the directory from the user configuration XML file is the recommended way to adjust the Phoromatic storage path when the Phoromatic Server is not running, while using the below form is an alternative method to attempt to live migrate the storage path.</p>';
     $main .= '<p><strong>Current Storage Path:</strong> ' . phoromatic_server::phoromatic_path() . '</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="update_phoromatic_path" method="post">';
     $main .= '<p><input type="text" name="new_phoromatic_path" value="' . (isset($_POST['new_phoromatic_path']) ? $_POST['new_phoromatic_path'] : null) . '" /></p>';
     $main .= '<p><input name="submit" value="Update Phoromatic Storage Location" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h2>Download Cache Location</h2>';
     $main .= '<p>The download cache is where the Phoronix Test Suite is able to make an archive of files needed by test profiles. The Phoromatic Server is then able to allow Phoronix Test Suite client systems on the intranet. To add test files to this cache on the Phoromatic Server, run <strong>phoronix-test-suite make-download-cache <em>&lt;the test identifers you wish to download and cache&gt;</em></strong>.</p>';
     $main .= '<p><strong>Current Download Cache Path:</strong> ' . pts_strings::add_trailing_slash(pts_client::parse_home_directory(pts_config::read_user_config('PhoronixTestSuite/Options/Installation/CacheDirectory', PTS_DOWNLOAD_CACHE_PATH))) . '</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="update_dc_path" method="post">';
     $main .= '<p><input type="text" name="new_dc_path" value="' . (isset($_POST['new_dc_path']) ? $_POST['new_dc_path'] : null) . '" /></p>';
     $main .= '<p><input name="submit" value="Update Download Cache Location" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h2>Network Proxy</h2>';
     $main .= '<p>If a network proxy is needed for the Phoromatic Server to access the open Internet, please provide the IP address and HTTP port address below.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="update_proxy" method="post">';
     $main .= '<p><strong>Proxy HTTP Port:</strong> <input type="text" name="new_proxy_port" size="4" value="' . (isset($_POST['new_proxy_port']) ? $_POST['new_proxy_port'] : pts_config::read_user_config('PhoronixTestSuite/Options/Networking/ProxyPort')) . '" /></p>';
     $main .= '<p><strong>Proxy IP Address:</strong> <input type="text" name="new_proxy_address" value="' . (isset($_POST['new_proxy_address']) ? $_POST['new_proxy_address'] : pts_config::read_user_config('PhoronixTestSuite/Options/Networking/ProxyAddress')) . '" /></p>';
     $main .= '<p><input name="submit" value="Update Network Proxy" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h2>Phoromatic Server Ports</h2>';
     $main .= '<p>The HTTP and WebSocket ports for the Phoromatic Server can be adjusted via this form or the user configuration XML file. The new ports will not go into effect until the Phoromatic Server instance has been restarted.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="update_ports" method="post">';
     $main .= '<p><strong>HTTP Port:</strong> <input type="text" name="new_http_port" size="4" value="' . (isset($_POST['new_http_port']) ? $_POST['new_http_port'] : pts_config::read_user_config('PhoronixTestSuite/Options/Server/RemoteAccessPort')) . '" /></p>';
     $main .= '<p><strong>WebSocket Port:</strong> <input type="text" name="new_ws_port" size="4" value="' . (isset($_POST['new_ws_port']) ? $_POST['new_ws_port'] : pts_config::read_user_config('PhoronixTestSuite/Options/Server/WebSocketPort')) . '" /></p>';
     $main .= '<p><input name="submit" value="Update Web Ports" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h2>Support Email Address</h2>';
     $main .= '<p>This email address will be shown as the sender of emails regarding new account registration and other non-group-related messages. This email address may also be shown as a support email address in case of user problems.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="support_email" method="post">';
     $main .= '<p><strong>E-Mail:</strong> <input type="text" name="new_admin_support_email" value="' . phoromatic_server::read_setting('admin_support_email') . '" /></p>';
     $main .= '<p><input name="submit" value="Update E-Mail Address" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h1>Account Creation</h1>';
     $main .= '<h2>Add To Existing Account</h2><p>Whenever a new account is created via the main log-in page, rather than creating a new group account, you can opt to have the account added as a viewer to an existing group of accounts. To do so, enter the account ID in the field below. The user is added to that account ID with viewer privileges while the main administrator for that account can elevate the privileges from their account\'s Users page. You can find the list of account IDs via the main rootadmin page account listing. Leave this field blank to disable the feature. This option only affects the creation of new accounts.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="add_accounts_to_one" method="post">';
     $main .= '<p><strong>Main Account ID:</strong> <input type="text" name="add_new_users_to_account" size="6" value="' . phoromatic_server::read_setting('add_new_users_to_account') . '" /></p>';
     $main .= '<p><input name="submit" value="Update Account Handling" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h1>Account Creation</h1>';
     $main .= '<p>By default, new accounts can be created at-will from the main page of the Phoromatic Server web interface. <strong>To disable the ability to create new accounts from the main welcome page</strong>, enter a message in the field below -- e.g. account creation disabled, contact XYZ department via email to request a new account, or other string to present to the user in place of the account creation box. Leave this box empty to allow new accounts to be created. HTML input is allowed.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="account_creation_text" method="post">';
     $main .= '<p><strong>Account Creation String:</strong> <textarea name="account_creation_alt" cols="50" rows="4">' . phoromatic_server::read_setting('account_creation_alt') . '</textarea></p>';
     $main .= '<p><input name="submit" value="Update Account Handling" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h1>Main Page Message</h1>';
     $main .= '<p>If you wish to present users with a custom message once logging into their Phoromatic account, set the HTML-allowed string below and it will be shown on the main page once logging in.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="main_page_message" method="post">';
     $main .= '<p><strong>Main Page Message String:</strong> <textarea name="main_page_message" cols="50" rows="4">' . phoromatic_server::read_setting('main_page_message') . '</textarea></p>';
     $main .= '<p><input name="submit" value="Update Main Page Message" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h1>Force Results To Be Shared</h1>';
     $main .= '<p>If you wish to force that all accounts/groups on this Phoromatic Server instance are shared/viewable amongst other groups on this server, set this value to True. Otherwise the result sharing is limited to each group\'s selected option on the account settings page.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="force_result_share" method="post">';
     $main .= '<p><strong>Force Result Sharing:</strong> <select name="force_result_sharing"><option value="0">False</option><option value="1" ' . (phoromatic_server::read_setting('force_result_sharing') ? 'selected="selected"' : null) . '>True</option></select></p>';
     $main .= '<p><input name="submit" value="Update" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h1>Only Advertise Tests With Files Locally Cached</h1>';
     $main .= '<p>Enabling this option will only advertise test profiles on the Phoromatic Server web interface if the needed files for that test are present within the Phoromatic Server\'s PTS download cache. This feature is particularly useful for environments where the client test system lacks direct Internet access.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="show_local_tests_only" method="post">';
     $main .= '<p><strong>Only Advertise Cached Tests:</strong> <select name="show_local_tests_only"><option value="0">False</option><option value="1" ' . (phoromatic_server::read_setting('show_local_tests_only') ? 'selected="selected"' : null) . '>True</option></select></p>';
     $main .= '<p><input name="submit" value="Update" type="submit" /></p>';
     $main .= '</form>';
     $main .= '<hr /><h1>Rebuild Results/Systems SQLite Tables</h1>';
     $main .= '<p>If you somehow damaged some of your SQLite tables, this option will attempt to rebuild the phoromatic_results_results and phoromatic_results_systems tables.</p>';
     $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="rebuild_results_db" method="post">';
     $main .= '<p><strong>Force Results Table Rebuild:</strong> <select name="rebuild_results_db"><option value="0">False</option><option value="1" ' . (phoromatic_server::read_setting('rebuild_results_db') ? 'selected="selected"' : null) . '>True</option></select></p>';
     $main .= '<p><input name="submit" value="Rebuild Results Table" type="submit" /></p>';
     $main .= '</form>';
     echo phoromatic_webui_header_logged_in();
     echo phoromatic_webui_main($main, phoromatic_webui_right_panel_logged_in());
     echo phoromatic_webui_footer();
 }
// INIT
define('PHOROMATIC_SERVER', true);
//ini_set('memory_limit', '64M');
define('PTS_MODE', 'WEB_CLIENT');
define('PTS_AUTO_LOAD_OBJECTS', true);
//error_reporting(E_ALL);
include '../../pts-core.php';
pts_core::init();
if (isset($_GET['index'])) {
    $requested_repo = str_replace(array('..', '/'), null, $_GET['repo']);
    $repo_index = pts_openbenchmarking::read_repository_index($requested_repo, false);
    echo $repo_index;
    pts_logger::add_to_log($_SERVER['REMOTE_ADDR'] . ' downloaded a copy of the ' . $requested_repo . ' OpenBenchmarking.org repository index');
} else {
    if (isset($_GET['repos'])) {
        $index_files = pts_file_io::glob(PTS_OPENBENCHMARKING_SCRATCH_PATH . '*.index');
        $json_repos = array();
        foreach ($index_files as $index_file) {
            $index_data = json_decode(file_get_contents($index_file), true);
            $json_repos['repos'][basename($index_file, '.index')] = array('title' => basename($index_file, '.index'), 'generated' => $index_data['main']['generated']);
        }
        echo json_encode($json_repos);
    } else {
        if (isset($_GET['test'])) {
            $repo = str_replace(array('..', '/'), null, $_GET['repo']);
            $test = str_replace(array('..', '/'), null, $_GET['test']);
            if (pts_openbenchmarking::is_repository($repo)) {
                pts_logger::add_to_log($_SERVER['REMOTE_ADDR'] . ' requested a copy of the ' . $repo . '/' . $test . ' test profile');
                $realpath_file = realpath(PTS_OPENBENCHMARKING_SCRATCH_PATH . $repo . '/' . $test . '.zip');
                if (is_file($realpath_file) && strpos($realpath_file, PTS_OPENBENCHMARKING_SCRATCH_PATH) === 0) {
                    echo base64_encode(file_get_contents($realpath_file));
 public static function saved_test_results()
 {
     $results = array();
     $ignore_ids = array();
     foreach (pts_file_io::glob(PTS_SAVE_RESULTS_PATH . '*/composite.xml') as $result_file) {
         $identifier = basename(dirname($result_file));
         if (!in_array($identifier, $ignore_ids)) {
             array_push($results, $identifier);
         }
     }
     return $results;
 }
    public static function render_page_process($PATH)
    {
        $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'])) {
            $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'), '');
                $box = '<h1>Account Created</h1>
				<p>Your account has been created. You may now log-in to begin utilizing the Phoronix Test Suite\'s Phoromatic.</p>
				<form name="login_form" id="login_form" action="?login" method="post" onsubmit="return phoromatic_login(this);">
				<p><div style="width: 200px; font-weight: bold; float: left;">User:</div> <input type="text" name="username" /></p>
				<p><div style="width: 200px; font-weight: bold; float: left;">Password:</div> <input type="password" name="password" /></p>
				<p><div style="width: 200px; font-weight: bold; float: left;">&nbsp;</div> <input type="submit" value="Submit" /></p>
				</form>';
                echo phoromatic_webui_box($box);
                echo phoromatic_webui_footer();
            }
        } else {
            if (isset($_POST['username']) && isset($_POST['password']) && strtolower($_POST['username']) == 'rootadmin') {
                $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>
				<p>The root admin password has not yet been set for this system. It can be set by running on the system: <strong>phoronix-test-suite phoromatic.set-root-admin-password</strong>.</p>';
                    echo phoromatic_webui_box($box);
                    echo phoromatic_webui_footer();
                    return false;
                } else {
                    if (hash('sha256', 'PTS' . $_POST['password']) != $admin_pw) {
                        echo phoromatic_webui_header(array('Invalid Password'), '');
                        $box = '<h1>Root Admin Password Incorrect</h1>
				<p>The root admin password is incorrect.</p>';
                        echo phoromatic_webui_box($box);
                        echo phoromatic_webui_footer();
                        return false;
                    } else {
                        session_regenerate_id();
                        $_SESSION['UserID'] = 0;
                        $_SESSION['UserName'] = '******';
                        $_SESSION['AccountID'] = 0;
                        $_SESSION['AdminLevel'] = -40;
                        $_SESSION['CreatedOn'] = null;
                        $_SESSION['CoreVersionOnSignOn'] = PTS_CORE_VERSION;
                        session_write_close();
                        header('Location: /?admin');
                    }
                }
            } else {
                if (isset($_POST['username']) && isset($_POST['password'])) {
                    $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'];
                        $user = $matching_user['UserName'];
                        $hashed_password = $matching_user['Password'];
                        $account_id = $matching_user['AccountID'];
                        $admin_level = $matching_user['AdminLevel'];
                        if ($admin_level < 1) {
                            pts_logger::add_to_log($_SERVER['REMOTE_ADDR'] . ' attempted to log-in to a disabled account: ' . $_POST['username']);
                            phoromatic_error_page('Disabled Account', 'The log-in is not possible as this account has been disabled.');
                            return false;
                        }
                        if ($user == $_POST['username']) {
                            $account_salt = phoromatic_server::$db->querySingle('SELECT Salt FROM phoromatic_accounts WHERE AccountID = \'' . $account_id . '\'');
                        } else {
                            $account_salt = null;
                        }
                        if ($account_salt != null && hash('sha256', $account_salt . $_POST['password']) == $hashed_password) {
                            session_regenerate_id();
                            $_SESSION['UserID'] = $user_id;
                            $_SESSION['UserName'] = $user;
                            $_SESSION['AccountID'] = $account_id;
                            $_SESSION['AdminLevel'] = $admin_level;
                            $_SESSION['CreatedOn'] = $created_on;
                            $_SESSION['CoreVersionOnSignOn'] = PTS_CORE_VERSION;
                            $account_salt = phoromatic_server::$db->exec('UPDATE phoromatic_users SET LastIP = \'' . $_SERVER['REMOTE_ADDR'] . '\', LastLogin = \'' . phoromatic_server::current_time() . '\' WHERE UserName = "******"');
                            session_write_close();
                            pts_file_io::mkdir(phoromatic_server::phoromatic_account_path($account_id));
                            pts_file_io::mkdir(phoromatic_server::phoromatic_account_result_path($account_id));
                            pts_file_io::mkdir(phoromatic_server::phoromatic_account_system_path($account_id));
                            pts_file_io::mkdir(phoromatic_server::phoromatic_account_suite_path($account_id));
                            echo phoromatic_webui_header(array('Welcome, ' . $user), '');
                            $box = '<h1>Log-In Successful</h1>
					<p><strong>' . $user . '</strong>, we are now redirecting you to your account portal. If you are not redirected within a few seconds, please <a href="?main">click here</a>.<script type="text/javascript">window.location.href = "?main";</script></p>';
                            echo phoromatic_webui_box($box);
                            echo phoromatic_webui_footer();
                            pts_logger::add_to_log($_SERVER['REMOTE_ADDR'] . ' successfully logged in as user: '******'REMOTE_ADDR'] . ' failed a log-in attempt as: ' . $_POST['username']);
                            phoromatic_error_page('Invalid Information', 'The user-name or password did not match our records.');
                            return false;
                        }
                    } else {
                        pts_logger::add_to_log($_SERVER['REMOTE_ADDR'] . ' failed a log-in attempt as: ' . $_POST['username']);
                        phoromatic_error_page('Invalid Information', 'The user-name was not found within our system.');
                        return false;
                    }
                } else {
                    echo phoromatic_webui_header(array(), '');
                    $box = '<h1>Welcome</h1>
			<p>You must log-in to your Phoromatic account or create an account to access this service.</p>
			<p>Phoromatic is the remote management and test orchestration system for the Phoronix Test Suite. Phoromatic allows the automatic scheduling of tests, remote installation of new tests, and the management of multiple test systems over a LAN or WAN all through an intuitive, easy-to-use web interface. Tests can be scheduled to automatically run on a routine basis across multiple test systems. The test results are then available from this central, secure location.</p>
			<p>Phoromatic makes it very easy to provide for automated scheduling of tests on multiple systems, is extremely extensible, allows various remote testing possibilities, makes it very trivial to manage multiple systems, and centralizes result management within an organization.</p>
			<p><a href="about.php">Learn more about Phoromatic</a>.</p>
			<hr />
			<h1>Log-In</h1>
			<form name="login_form" id="login_form" action="?login" method="post" onsubmit="return phoromatic_login(this);">
			<p><div style="width: 200px; font-weight: 500; float: left;">User:</div> <input type="text" name="username" /></p>
			<p><div style="width: 200px; font-weight: 500; float: left;">Password:</div> <input type="password" name="password" /></p>
			<p><div style="width: 200px; font-weight: 500; float: left;">&nbsp;</div> <input type="submit" value="Submit" /></p>
			</form>
			<hr />
			<h1>Register</h1>';
                    if (!empty($account_creation_string)) {
                        $box .= '<p>' . $account_creation_string . '</p>';
                    } else {
                        $box .= '
					<p>Creating a new Phoromatic account is free and easy. The public, open-source version of the Phoronix Test Suite client is limited in its Phoromatic server abilities when it comes to result management and local storage outside of the OpenBenchmarking.org cloud. For organizations looking for behind-the-firewall support and other enterprise features, <a href="http://www.phoronix-test-suite.com/?k=commercial">contact us</a>. To create a new account for this Phoromatic server, simply fill out the form below.</p>';
                        $box .= '<form name="register_form" id="register_form" action="?register" method="post" onsubmit="return phoromatic_initial_registration(this);">

					<div style="clear: both; font-weight: 500;">
					<div style="float: left; width: 25%;">Username</div>
					<div style="float: left; width: 25%;">Password</div>
					<div style="float: left; width: 25%;">Confirm Password</div>
					<div style="float: left; width: 25%;">Email Address</div>
					</div>

					<div style="clear: both;">
					<div style="float: left; width: 25%;"><input type="hidden" name="seed_accountid" value="' . (isset($_GET['seed_accountid']) ? $_GET['seed_accountid'] : null) . '" /><input type="text" name="register_username" /> <sup>1</sup></div>
					<div style="float: left; width: 25%;"><input type="password" name="register_password" /> <sup>2</sup></div>
					<div style="float: left; width: 25%;"><input type="password" name="register_password_confirm" /></div>
					<div style="float: left; width: 25%;"><input type="text" name="register_email" /> <sup>3</sup><br /><br /><input type="submit" value="Create Account" /></div>
					</div>

					</form>';
                        $box .= '<p style="font-size: 11px;"><sup>1</sup> Usernames shall be at least four characters long, not contain any spaces, and only be composed of normal ASCII characters.<br />
						<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 />
						</p>';
                    }
                    $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 />';
                    echo phoromatic_webui_box($box);
                    echo phoromatic_webui_footer();
                }
            }
        }
    }
 public static function validate_test_profile(&$test_profile)
 {
     if ($test_profile->get_file_location() == null) {
         echo PHP_EOL . 'ERROR: The file location of the XML test profile source could not be determined.' . PHP_EOL;
         return false;
     }
     // Validate the XML against the XSD Schemas
     libxml_clear_errors();
     // Now re-create the pts_test_profile object around the rewritten XML
     $test_profile = new pts_test_profile($test_profile->get_identifier());
     $valid = $test_profile->validate();
     if ($valid == false) {
         echo PHP_EOL . 'Errors occurred parsing the main XML.' . PHP_EOL;
         pts_validation::process_libxml_errors();
         return false;
     }
     // Rewrite the main XML file to ensure it is properly formatted, elements are ordered according to the schema, etc...
     $test_profile_writer = new pts_test_profile_writer();
     $test_profile_writer->rebuild_test_profile($test_profile);
     $test_profile_writer->save_xml($test_profile->get_file_location());
     // Now re-create the pts_test_profile object around the rewritten XML
     $test_profile = new pts_test_profile($test_profile->get_identifier());
     $valid = $test_profile->validate();
     if ($valid == false) {
         echo PHP_EOL . 'Errors occurred parsing the main XML.' . PHP_EOL;
         pts_validation::process_libxml_errors();
         return false;
     } else {
         echo PHP_EOL . 'Test Profile XML Is Valid.' . PHP_EOL;
     }
     // Validate the downloads file
     $download_xml_file = $test_profile->get_file_download_spec();
     if (empty($download_xml_file) == false) {
         $writer = new pts_test_profile_downloads_writer();
         $writer->rebuild_download_file($test_profile);
         $writer->save_xml($download_xml_file);
         $downloads_parser = new pts_test_downloads_nye_XmlReader($download_xml_file);
         $valid = $downloads_parser->validate();
         if ($valid == false) {
             echo PHP_EOL . 'Errors occurred parsing the downloads XML.' . PHP_EOL;
             pts_validation::process_libxml_errors();
             return false;
         } else {
             echo PHP_EOL . 'Test Downloads XML Is Valid.' . PHP_EOL;
         }
         // Validate the individual download files
         echo PHP_EOL . 'Testing File Download URLs.' . PHP_EOL;
         $files_missing = 0;
         $file_count = 0;
         foreach (pts_test_install_request::read_download_object_list($test_profile) as $download) {
             foreach ($download->get_download_url_array() as $url) {
                 $stream_context = pts_network::stream_context_create();
                 stream_context_set_params($stream_context, array('notification' => 'pts_stream_status_callback'));
                 $file_pointer = fopen($url, 'r', false, $stream_context);
                 if ($file_pointer == false) {
                     echo 'File Missing: ' . $download->get_filename() . ' / ' . $url . PHP_EOL;
                     $files_missing++;
                 } else {
                     fclose($file_pointer);
                 }
                 $file_count++;
             }
         }
         if ($files_missing > 0) {
             return false;
         }
     }
     // Validate the parser file
     $parser_file = $test_profile->get_file_parser_spec();
     if (empty($parser_file) == false) {
         $writer = self::rebuild_result_parser_file($parser_file);
         $writer->saveXMLFile($parser_file);
         $parser = new pts_parse_results_nye_XmlReader($parser_file);
         $valid = $parser->validate();
         if ($valid == false) {
             echo PHP_EOL . 'Errors occurred parsing the results parser XML.' . PHP_EOL;
             pts_validation::process_libxml_errors();
             return false;
         } else {
             echo PHP_EOL . 'Test Results Parser XML Is Valid.' . PHP_EOL;
         }
     }
     // Make sure no extra files are in there
     $allowed_files = pts_validation::test_profile_permitted_files();
     foreach (pts_file_io::glob($test_profile->get_resource_dir() . '*') as $tp_file) {
         if (!is_file($tp_file) || !in_array(basename($tp_file), $allowed_files)) {
             echo PHP_EOL . basename($tp_file) . ' is not allowed in the test package.' . PHP_EOL;
             return false;
         }
     }
     return true;
 }
    public static function render_page_process($PATH)
    {
        if (isset($_POST['suite_title'])) {
            //	echo '<pre>';
            //	var_dump($_POST);
            //	echo '</pre>';
            if (strlen($_POST['suite_title']) < 3) {
                echo '<h2>Suite title must be at least three characters.</h2>';
            }
            //echo 'TEST SUITE: ' . $_POST['suite_title'] . '<br />';
            //echo 'TEST SUITE: ' . $_POST['suite_description'] . '<br />';
            $tests = array();
            foreach ($_POST['test_add'] as $i => $test_identifier) {
                $test_prefix = $_POST['test_prefix'][$i];
                $args = array();
                $args_name = array();
                foreach ($_POST as $i => $v) {
                    if (strpos($i, $test_prefix) !== false && substr($i, -9) != '_selected') {
                        if (strpos($v, '||') !== false) {
                            $opts = explode('||', $v);
                            $a = array();
                            $d = array();
                            foreach ($opts as $opt) {
                                $t = explode('::', $opt);
                                array_push($a, $t[1]);
                                array_push($d, $t[0]);
                            }
                            array_push($args, $a);
                            array_push($args_name, $d);
                        } else {
                            array_push($args, array($v));
                            array_push($args_name, array($_POST[$i . '_selected']));
                        }
                    }
                }
                $test_args = array();
                $test_args_description = array();
                pts_test_run_options::compute_all_combinations($test_args, null, $args, 0);
                pts_test_run_options::compute_all_combinations($test_args_description, null, $args_name, 0, ' - ');
                foreach (array_keys($test_args) as $i) {
                    array_push($tests, array('test' => $test_identifier, 'description' => $test_args_description[$i], 'args' => $test_args[$i]));
                }
            }
            if (count($tests) < 1) {
                echo '<h2>You must add at least one test to the suite.</h2>';
            }
            $suite_writer = new pts_test_suite_writer();
            $version_bump = 0;
            do {
                $suite_version = '1.' . $version_bump . '.0';
                $suite_id = $suite_writer->clean_save_name_string($_POST['suite_title']) . '-' . $suite_version;
                $suite_dir = phoromatic_server::phoromatic_account_suite_path($_SESSION['AccountID'], $suite_id);
                $version_bump++;
            } while (is_dir($suite_dir));
            pts_file_io::mkdir($suite_dir);
            $save_to = $suite_dir . '/suite-definition.xml';
            $suite_writer->add_suite_information($_POST['suite_title'], $suite_version, $_SESSION['UserName'], 'System', $_POST['suite_description']);
            foreach ($tests as $m) {
                $suite_writer->add_to_suite($m['test'], $m['args'], $m['description']);
            }
            $suite_writer->save_xml($save_to);
            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) {
            $main .= '<h1>Build Suite</h1><p>A test suite in the realm of the Phoronix Test Suite, OpenBenchmarking.org, and Phoromatic is <strong>a collection of test profiles with predefined settings</strong>. Establishing a test suite makes it easy to run repetitive testing on the same set of test profiles by simply referencing the test suite name.</p>';
            $main .= '<form action="' . $_SERVER['REQUEST_URI'] . '" name="build_suite" id="build_suite" method="post" onsubmit="return validate_suite();">
			<h3>Title:</h3>
			<p><input type="text" name="suite_title" /></p>
			<h3>Description:</h3>
			<p><textarea name="suite_description" id="suite_description" cols="60" rows="2"></textarea></p>
			<h3>Tests In Schedule:</h3>
			<p><div id="test_details"></div></p>
			<h3>Add Another Test</h3>';
            $main .= '<select name="add_to_suite_select_test" id="add_to_suite_select_test" onchange="phoromatic_build_suite_test_details();">';
            $dc = pts_strings::add_trailing_slash(pts_client::parse_home_directory(pts_config::read_user_config('PhoronixTestSuite/Options/Installation/CacheDirectory', PTS_DOWNLOAD_CACHE_PATH)));
            $dc_exists = is_file($dc . 'pts-download-cache.json');
            foreach (pts_openbenchmarking::available_tests(false, true) as $test) {
                $cache_checked = false;
                if ($dc_exists) {
                    $cache_json = file_get_contents($dc . 'pts-download-cache.json');
                    $cache_json = json_decode($cache_json, true);
                    if ($cache_json && isset($cache_json['phoronix-test-suite']['cached-tests'])) {
                        $cache_checked = true;
                        if (!in_array($test, $cache_json['phoronix-test-suite']['cached-tests'])) {
                            continue;
                        }
                    }
                }
                if (!$cache_checked && phoromatic_server::read_setting('show_local_tests_only') && pts_test_install_request::test_files_in_cache($test, true, true) == false) {
                    continue;
                }
                $main .= '<option value="' . $test . '">' . $test . '</option>';
            }
            $main .= '</select>';
            $main .= '<p align="right"><input name="submit" value="Create Suite" type="submit" onclick="return pts_rmm_validate_suite();" /></p>';
        }
        echo '<div id="pts_phoromatic_main_area">' . $main . '</div>';
        echo phoromatic_webui_footer();
    }