query_port) { if ($server_xml->query_port['type'] == 'add') { return $server_port + $server_xml->query_port; } if ($server_xml->query_port['type'] == 'subtract') { return $server_port - $server_xml->query_port; } } return $server_port; } function get_start_cmd($remote,$server_xml,$home_info,$mod_id,$ip,$port,$db) { $last_param = json_decode($home_info['last_param'], True); $os = $remote->what_os(); $isAdmin = false; if(hasValue($_SESSION) && hasValue($_SESSION['user_id'])){ $isAdmin = $db->isAdmin($_SESSION['user_id']); } $cli_param_data['GAME_TYPE'] = $home_info['mods'][$mod_id]['mod_key']; $cli_param_data['IP'] = $ip; $cli_param_data['PORT'] = $port; $cli_param_data['HOSTNAME'] = $home_info['home_name']; $cli_param_data['PID_FILE'] = "ogp_game_startup.pid"; // Linux if( preg_match("/Linux/", $os) ) { if(preg_match("/_win(32|64)?$/", $home_info['game_key'])) { $home_path_wine = $remote->exec("winepath -w ".$home_info['home_path']); $home_path_wine = str_replace("\\","\\\\", $home_path_wine); $home_path_wine = trim($home_path_wine); $cli_param_data['BASE_PATH'] = $home_path_wine; $cli_param_data['HOME_PATH'] = $home_path_wine; $cli_param_data['SAVE_PATH'] = $home_path_wine; $cli_param_data['OUTPUT_PATH'] = $home_path_wine; $cli_param_data['USER_PATH'] = $home_path_wine; } else { $cli_param_data['BASE_PATH'] = $home_info['home_path']; $cli_param_data['HOME_PATH'] = $home_info['home_path']; $cli_param_data['SAVE_PATH'] = $home_info['home_path']; $cli_param_data['OUTPUT_PATH'] = $home_info['home_path']; $cli_param_data['USER_PATH'] = $home_info['home_path']; } } // Windows elseif( preg_match("/CYGWIN/", $os) ) { $home_path_win = $remote->exec("cygpath -w ".$home_info['home_path']); $home_path_win = str_replace("\\","\\\\", $home_path_win); $home_path_win = trim($home_path_win); $cli_param_data['BASE_PATH'] = $home_path_win; $cli_param_data['HOME_PATH'] = $home_path_win; $cli_param_data['SAVE_PATH'] = $home_path_win; $cli_param_data['OUTPUT_PATH'] = $home_path_win; $cli_param_data['USER_PATH'] = $home_path_win; } if ($server_xml->protocol == "gameq") { $cli_param_data['QUERY_PORT'] = get_query_port ($server_xml, $port); } elseif ($server_xml->protocol == "lgsl") { require('protocol/lgsl/lgsl_protocol.php'); $get_ports = lgsl_port_conversion((string)$server_xml->lgsl_query_name, $port, "", ""); $cli_param_data['QUERY_PORT'] = $get_ports['1']; } elseif ($server_xml->protocol == "teamspeak3") { $cli_param_data['QUERY_PORT'] = "10011"; } $cli_param_data['MAP'] = ($last_param === NULL or !isset($last_param['map'])) ? "" : $last_param['map']; $cli_param_data['PLAYERS'] = ($last_param === NULL or !isset($last_param['players'])) ? isset($home_info['mods'][$mod_id]['max_players']) ? $home_info['mods'][$mod_id]['max_players'] : "1" : $last_param['players']; $cli_param_data['CONTROL_PASSWORD'] = $home_info['control_password']; $start_cmd = ""; // If the template is empty then these are not needed. if ( $server_xml->cli_template ) { $start_cmd = $server_xml->cli_template; if ( $server_xml->cli_params ) { foreach ( $server_xml->cli_params->cli_param as $cli ) { // If s is found the param is seperated with space $add_space = preg_match( "/s/", $cli['options'] ) > 0 ? " " : ""; $cli_value = $cli_param_data[(string) $cli['id'] ]; // If q is found we add quotes around the value. if ( preg_match( "/q/", $cli['options'] ) > 0 ) { $cli_value = "\"".$cli_value."\""; } $start_cmd = preg_replace( "/%".$cli['id']."%/", $cli['cli_string'].$add_space.$cli_value, $start_cmd ); } } if ( $server_xml->reserve_ports ) { foreach ( $server_xml->reserve_ports->port as $reserve_port ) { // If s is found the param is seperated with space $add_space = preg_match( "/s/", $reserve_port['options'] ) > 0 ? " " : ""; $cli_value = $reserve_port['type'] == "add" ? $port + (string) $reserve_port: $port - (string) $reserve_port; // If q is found we add quotes around the value. if ( preg_match( "/q/", $reserve_port['options'] ) > 0 ) { $cli_value = "\"".$cli_value."\""; } $start_cmd = preg_replace( "/%".$reserve_port['id']."%/", $reserve_port['cli_string'].$add_space.$cli_value, $start_cmd ); } } } if ( $isAdmin ) { $home_info['access_rights'] = "ufpet"; } $param_access_enabled = preg_match("/p/",$home_info['access_rights']) > 0 ? TRUE : FALSE; if ($param_access_enabled && $last_param !== NULL and isset($server_xml->server_params->param) ) { foreach($server_xml->server_params->param as $param) { foreach ((array)$last_param as $paramKey => $paramValue) { if (!isset($paramValue)) $paramValue = (string)$param->default; if ($param['key'] == $paramKey) { if (0 == strlen($paramValue)) continue; if ($param['key'] == $paramValue) // it's a checkbox $new_param = $paramKey; elseif($param->option == "ns" or $param->options == "ns") $new_param = $paramKey.clean_server_param_value($paramValue, $server_xml->cli_allow_chars); elseif($param->option == "q" or $param->options == "q") $new_param = $paramKey . '"' . clean_server_param_value($paramValue, $server_xml->cli_allow_chars) . '"'; elseif($param->option == "s" or $param->options == "s") $new_param = $paramKey . ' ' . clean_server_param_value($paramValue, $server_xml->cli_allow_chars); else $new_param = $paramKey . ' "' . clean_server_param_value($paramValue, $server_xml->cli_allow_chars) . '"'; if ($param['id'] == NULL || $param['id'] == "") $start_cmd .= ' '.$new_param; else $start_cmd = preg_replace( "/%".$param['id']."%/", $new_param, $start_cmd ); } } if ($param['id'] != NULL && $param['id'] != ""){ $start_cmd = preg_replace( "/%".$param['id']."%/", '', $start_cmd ); } } } $extra_param_access_enabled = preg_match("/e/",$home_info['access_rights']) > 0 ? TRUE:FALSE; if ( array_key_exists('extra', (array)$last_param) && $extra_param_access_enabled ) $extra_default = $last_param['extra']; else $extra_default = $home_info['mods'][$mod_id]['extra_params']; $start_cmd .= " ".str_replace("\\\\", "\\", clean_server_param_value($extra_default, $server_xml->cli_allow_chars)); return $start_cmd; } // This function is used to batch stop/restart servers in background. function exec_operation( $action, $home_id, $mod_id, $ip, $port, $override = false ) { if(!is_numeric($port)) return FALSE; if(!preg_match("/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/",$ip)) return FALSE; global $db; $isAdmin = false; if(hasValue($_SESSION) && hasValue($_SESSION['user_id'])){ $isAdmin = $db->isAdmin($_SESSION['user_id']); } if($override || $isAdmin) $home_info = $db->getGameHome($home_id); else $home_info = $db->getUserGameHome($_SESSION['user_id'],$home_id); if( $home_info === FALSE ) return FALSE; $server_xml = read_server_config(SERVER_CONFIG_LOCATION."/".$home_info['home_cfg_file']); if ( !$server_xml ) return FALSE; require_once('includes/lib_remote.php'); $remote = new OGPRemoteLibrary($home_info['agent_ip'],$home_info['agent_port'],$home_info['encryption_key'],$home_info['timeout']); $os = $remote->what_os(); if ( $action != "stop" ) { if( $server_xml->replace_texts ) { $server_home = $home_info; if( isset($server_xml->lgsl_query_name) ) require_once('protocol/lgsl/lgsl_protocol.php'); require_once("modules/gamemanager/cfg_text_replace.php"); } } $screen_running = $remote->is_screen_running(OGP_SCREEN_TYPE_HOME,$home_info['home_id']) === 1; if ( $action == "stop" AND $screen_running ) { $remote_retval = $remote->remote_stop_server($home_info['home_id'], $ip, $port, $server_xml->control_protocol, $home_info['control_password'],$server_xml->control_protocol_type, $home_info['home_path']); $db->logger(get_lang_f('server_stopped', $home_info['home_name'] ) . "($ip:$port)"); if ( $remote_retval === -1 ) return FALSE; elseif( $remote_retval === -2 ) return FALSE; else { $firewall_settings = $db->getFirewallSettings($home_info['remote_server_id']); if ($firewall_settings['status'] == "enable") { $ip_ports = $db->getHomeIpPorts($home_info['home_id']); if (!is_array($ip_ports)) { $ip_ports = []; } foreach ((array)$ip_ports as $ip_port) { if ($server_xml->protocol == "gameq") { $query_port = get_query_port($server_xml, $ip_port['port']); } elseif ($server_xml->protocol == "lgsl") { require('protocol/lgsl/lgsl_protocol.php'); $get_ports = lgsl_port_conversion((string)$server_xml->lgsl_query_name, $ip_port['port'], "", ""); $query_port = $get_ports['1']; } elseif ($server_xml->protocol == "teamspeak3") { $query_port = "10011"; } set_firewall($remote, $firewall_settings, 'deny', $ip_port['port'], $ip_port['ip']); if(isset($query_port) and $query_port != "" and $query_port != $ip_port['port']) set_firewall($remote, $firewall_settings, 'deny', $query_port, $ip_port['ip']); } } return TRUE; } } elseif ( $action == "restart" AND $screen_running ) { $start_cmd = get_start_cmd($remote,$server_xml,$home_info,$mod_id,$ip,$port,$db); // Do text replacements in cfg file if( $server_xml->replace_texts ) { if (is_array($home_info['mods'][$mod_id])) { foreach($home_info['mods'][$mod_id] as $key => $value) { $home_info[$key] = $value; } } $server_home = $home_info; if( isset($server_xml->lgsl_query_name) ) require_once('protocol/lgsl/lgsl_protocol.php'); require_once("modules/gamemanager/cfg_text_replace.php"); } // Run pre-start commands if(isset($server_xml->pre_start) && !empty($server_xml->pre_start)){ $preStart = trim($server_xml->pre_start); }else{ $preStart = ""; } // Environment variables if(isset($server_xml->environment_variables) && !empty($server_xml->environment_variables)){ $envVars = trim($server_xml->environment_variables); }else{ $envVars = ""; } // Additional files to lock if(isset($server_xml->lock_files) && !empty($server_xml->lock_files)){ $lockFiles = trim($server_xml->lock_files); }else{ $lockFiles = ""; } if(!empty($lockFiles)){ // Linux only call if(preg_match("/Linux/", $os)){ $lockedFilesStatus = $remote->lock_additional_home_files($home_info['home_path'], $lockFiles, "lock"); } } $remote_retval = $remote->remote_restart_server($home_info['home_id'],$ip,$port,$server_xml->control_protocol, $home_info['control_password'],$server_xml->control_protocol_type,$home_info['home_path'], $server_xml->server_exec_name,$server_xml->exe_location,$start_cmd, $home_info['mods'][$mod_id]['cpu_affinity'], $home_info['mods'][$mod_id]['nice'], $preStart, $envVars, $server_xml->game_key, (isset( $server_xml->console_log ) ? $server_xml->console_log : "")); $db->logger(get_lang_f('server_restarted', $home_info['home_name']) . "($ip:$port)"); if ( $remote_retval === -1 ) return FALSE; else if ( $remote_retval === -2 ) return FALSE; else { $ip_id = $db->getIpIdByIp($ip); $db->delServerStatusCache($ip_id,$port); } } elseif ( $action == "start" AND ! $screen_running ) { $start_cmd = get_start_cmd($remote,$server_xml,$home_info,$mod_id,$ip,$port,$db); // Do text replacements in cfg file if( $server_xml->replace_texts ) { if (is_array($home_info['mods'][$mod_id])) { foreach($home_info['mods'][$mod_id] as $key => $value) { $home_info[$key] = $value; } } $server_home = $home_info; if( isset($server_xml->lgsl_query_name) ) require_once('protocol/lgsl/lgsl_protocol.php'); require_once("modules/gamemanager/cfg_text_replace.php"); } // Run pre-start commands if(isset($server_xml->pre_start) && !empty($server_xml->pre_start)){ $preStart = trim($server_xml->pre_start); }else{ $preStart = ""; } // Environment variables if(isset($server_xml->environment_variables) && !empty($server_xml->environment_variables)){ $envVars = trim($server_xml->environment_variables); }else{ $envVars = ""; } // Additional files to lock if(isset($server_xml->lock_files) && !empty($server_xml->lock_files)){ $lockFiles = trim($server_xml->lock_files); }else{ $lockFiles = ""; } if(!empty($lockFiles)){ // Linux only call if(preg_match("/Linux/", $os)){ $lockedFilesStatus = $remote->lock_additional_home_files($home_info['home_path'], $lockFiles, "lock"); } } $start_retval = $remote->universal_start($home_info['home_id'], $home_info['home_path'], $server_xml->server_exec_name, $server_xml->exe_location, $start_cmd, $port, $ip, $home_info['mods'][$mod_id]['cpu_affinity'], $home_info['mods'][$mod_id]['nice'], $preStart, $envVars, $server_xml->game_key, (isset( $server_xml->console_log ) ? $server_xml->console_log : "") ); $db->logger(get_lang('server_started') . " (".$home_info['home_name']." $ip:$port)"); if( $start_retval == AGENT_ERROR_NOT_EXECUTABLE or $start_retval <= 0) return FALSE; else { $firewall_settings = $db->getFirewallSettings($home_info['remote_server_id']); if ($firewall_settings['status'] == "enable") { $ip_ports = $db->getHomeIpPorts($home_info['home_id']); if (!is_array($ip_ports)) { $ip_ports = []; } foreach ((array)$ip_ports as $ip_port) { if ($server_xml->protocol == "gameq") { $query_port = get_query_port($server_xml, $ip_port['port']); } elseif ($server_xml->protocol == "lgsl") { require('protocol/lgsl/lgsl_protocol.php'); $get_ports = lgsl_port_conversion((string)$server_xml->lgsl_query_name, $ip_port['port'], "", ""); $query_port = $get_ports['1']; } elseif ($server_xml->protocol == "teamspeak3") { $query_port = "10011"; } set_firewall($remote, $firewall_settings, 'allow', $ip_port['port'], $ip_port['ip']); if(isset($query_port) and $query_port != "" and $query_port != $ip_port['port']) set_firewall($remote, $firewall_settings, 'allow', $query_port, $ip_port['ip']); } } $ip_id = $db->getIpIdByIp($ip); $db->delServerStatusCache($ip_id,$port); return TRUE; } } } function get_monitor_buttons($server_home, $server_xml) { global $db; $buttons = array(); $installed_modules = $db->getInstalledModules(); if (!is_array($installed_modules)) { $installed_modules = []; } foreach ((array)$installed_modules as $installed_module) { $buttons_file = "modules/$installed_module[folder]/monitor_buttons.php"; if(file_exists($buttons_file)) { require($buttons_file); if (is_array($module_buttons)) { $buttons = array_merge($buttons, $module_buttons); } unset($module_buttons); } } $buttons_html = ""; if (is_array($buttons)) { foreach ((array)$buttons as $button) $buttons_html .= $button."\n"; } return $buttons_html; } /** * Returns an HTML-formatted expiration label for the given server home_id. * * Source of truth: billing_orders.end_date (DATETIME, NULL means no date set). * billing_orders.home_id is the direct FK to server_homes.home_id. * Only rows where home_id != '0' are considered (home_id = '0' means not yet * provisioned). * * Color thresholds: * green – more than 10 days remaining (shows actual date, YYYY-MM-DD) * yellow – 4–10 days remaining (shows "X days remaining") * red – 1–3 days remaining (shows "X days remaining") * red – less than 1 day but not yet expired (shows "Less than 1 day remaining") * red – already expired/suspended (shows "Suspended") * red – no order or NULL/invalid end_date (shows "No expiration date found") * * Expiration grace rule: a server whose end_date falls on today is treated as * active for the full calendar day. The server only shows "Suspended" once * today's date is strictly after the expiration date (i.e. tomorrow onwards). * * @param int $home_id The server home ID. * @return string Safe HTML string ready for inline display. */ function get_server_billing_expiration_html(int $home_id): string { global $db; // Query billing_orders directly by home_id — the canonical FK relationship. // billing_orders.home_id is VARCHAR(255), so we quote the value in the query. // We exclude rows where home_id = '0' (not yet provisioned). // // Only canonical active statuses are considered: // 'Active' – provisioned and current (set by payment capture or admin creation) // 'Invoiced' – renewal invoice generated; service still running while unpaid // // Terminal statuses ('Expired', 'in-cart', 'cancelled', 'refunded') and legacy // statuses ('installed', 'paid', 'suspended') are not matched here. // Run normalize_billing_order_status.sql to migrate any legacy rows first. // // OGP_DB_PREFIX is replaced at runtime by the panel DB wrapper (str_replace). $rows = $db->resultQuery( "SELECT end_date FROM OGP_DB_PREFIXbilling_orders WHERE home_id = '" . intval($home_id) . "' AND home_id != '0' AND status IN ('Active','Invoiced') ORDER BY end_date DESC LIMIT 1" ); // resultQuery returns FALSE both on error and when 0 rows are found. // Either way, there is no billing order for this server. if ($rows === false) { return "No expiration date found"; } // end_date may be NULL (e.g. order created but payment not yet captured). if (empty($rows[0]['end_date'])) { return "No expiration date found"; } // Parse end_date using DateTime for PHP 8.3+ compatibility. try { $end_dt = new DateTime($rows[0]['end_date']); } catch (\Exception $e) { return "No expiration date found"; } // Compare dates only (strip time) so a server expiring on today's date is // still shown as active for the full calendar day (grace rule). $today_midnight = (new DateTime())->setTime(0, 0, 0); $end_midnight = (clone $end_dt)->setTime(0, 0, 0); $diff = $today_midnight->diff($end_midnight); if ($end_midnight < $today_midnight) { // Expiration date is before today — treat as suspended. return "Suspended"; } // $diff->days is the total number of whole days between today and end date. $days_remaining = (int)$diff->days; $display_date = htmlentities($end_dt->format('Y-m-d'), ENT_QUOTES, 'UTF-8'); if ($days_remaining > 10) { // More than 10 days: show the actual expiration date in green. return "" . $display_date . ""; } elseif ($days_remaining >= 4) { // 4–10 days: yellow warning (darkgoldenrod for WCAG contrast). return "" . htmlentities($days_remaining, ENT_QUOTES, 'UTF-8') . " days remaining"; } elseif ($days_remaining >= 1) { // 1–3 days: urgent red warning. return "" . htmlentities($days_remaining, ENT_QUOTES, 'UTF-8') . " days remaining"; } else { // Less than one full day but not yet expired. return "Less than 1 day remaining"; } } ?>