Merge pull request #161 from GameServerPanel/copilot/fix-update-panel-apache-paths
This commit is contained in:
commit
c56cce73fe
8 changed files with 449 additions and 152 deletions
|
|
@ -1,11 +1,9 @@
|
|||
$(function() {
|
||||
var methodToRows = {
|
||||
download_zip: ['#scm-row-url', '#scm-row-path', '#scm-row-post-script'],
|
||||
download_file: ['#scm-row-url', '#scm-row-path', '#scm-row-post-script'],
|
||||
steam_workshop: ['#scm-row-workshop-id', '#scm-row-workshop-app-id', '#scm-row-target-path-template', '#scm-row-optional-folder-name', '#scm-row-launch-param-additions', '#scm-row-config-edit-rule', '#scm-row-post-script'],
|
||||
download_zip: ['#scm-row-url', '#scm-row-path'],
|
||||
steam_workshop: ['#scm-row-workshop-id', '#scm-row-workshop-app-id', '#scm-row-target-path-template', '#scm-row-optional-folder-name'],
|
||||
post_script: ['#scm-row-post-script'],
|
||||
config_edit: ['#scm-row-path', '#scm-row-config-edit-rule', '#scm-row-post-script'],
|
||||
create_folder: ['#scm-row-path']
|
||||
config_edit: ['#scm-row-path', '#scm-row-config-edit-rule']
|
||||
};
|
||||
var allRows = [
|
||||
'#scm-row-url',
|
||||
|
|
@ -34,7 +32,7 @@ $(function() {
|
|||
var selectedOption = $method.find('option:selected');
|
||||
var helpText = selectedOption.data('help') || '';
|
||||
$help.text(helpText);
|
||||
$('#scm-path-label').text(value === 'config_edit' ? 'Config Target Path' : 'Target Path');
|
||||
$('#scm-path-label').text(value === 'config_edit' ? 'Config Target Path' : 'Target Path / Extract Path (optional)');
|
||||
}
|
||||
|
||||
$method.on('change', applyContentTypeUi);
|
||||
|
|
|
|||
|
|
@ -45,8 +45,9 @@ define('LANG_select_game_type', "Select Game Type");
|
|||
define('LANG_plugin', "Plugins / Mods");
|
||||
define('LANG_mappack', "Map Packs");
|
||||
define('LANG_config', "Config Packs");
|
||||
// Additional category labels (for future content types already defined in server_content_categories.php)
|
||||
if (!defined('LANG_version')) define('LANG_version', "Version");
|
||||
if (!defined('LANG_version')) {
|
||||
define('LANG_version', "Version");
|
||||
}
|
||||
define('LANG_server_content_version', "Server Versions");
|
||||
define('LANG_modpack', "Modpacks");
|
||||
define('LANG_workshop', "Workshop Content");
|
||||
|
|
@ -63,12 +64,12 @@ define('LANG_create_addon', "Create Server Content Item");
|
|||
define('LANG_addons_db', "Server Content Database");
|
||||
define('LANG_addon_has_been_created', "The server content item \"%s\" has been created.");
|
||||
define('LANG_remove_addon', "Remove");
|
||||
define('LANG_fill_the_url_address_to_a_compressed_file', "Please enter a URL for the compressed file to download.");
|
||||
define('LANG_fill_the_url_address_to_a_compressed_file', "Please enter a download URL.");
|
||||
define('LANG_fill_the_download_url', "Please enter a download URL.");
|
||||
define('LANG_fill_the_workshop_id', "Please enter a Workshop ID.");
|
||||
define('LANG_fill_the_target_install_path', "Please select a target install path.");
|
||||
define('LANG_fill_the_script_action_body', "Please enter a script/action body.");
|
||||
define('LANG_fill_the_config_edit_rule', "Please enter a config edit rule.");
|
||||
define('LANG_fill_the_target_install_path', "Please enter the config target and edit action.");
|
||||
define('LANG_fill_the_script_action_body', "Please enter the installer script/action.");
|
||||
define('LANG_fill_the_config_edit_rule', "Please enter the config target and edit action.");
|
||||
define('LANG_fill_the_addon_name', "Please enter a name for the server content item.");
|
||||
define('LANG_select_an_addon_type', "Please select a content type.");
|
||||
define('LANG_select_a_game_type', "Please select a game type.");
|
||||
|
|
@ -92,10 +93,8 @@ define('LANG_target_path_template', "Target Path");
|
|||
define('LANG_optional_folder_name', "Optional Folder Name");
|
||||
define('LANG_config_edit_rule', "Config Edit Rule");
|
||||
define('LANG_launch_param_additions', "Launch Parameter Additions");
|
||||
define('LANG_content_type_help_download_zip', "Downloads and extracts an archive into the target path.");
|
||||
define('LANG_content_type_help_download_file', "Downloads a single file without extraction.");
|
||||
define('LANG_content_type_help_steam_workshop', "Downloads/updates a Workshop item and applies it to the server.");
|
||||
define('LANG_content_type_help_post_script', "Runs a script/action only, with no URL required.");
|
||||
define('LANG_content_type_help_config_edit', "Applies config edit rules to a target path, with no URL required.");
|
||||
define('LANG_content_type_help_create_folder', "Creates target folders/paths only, with no URL required.");
|
||||
define('LANG_content_type_help_download_zip', "Downloads an archive/file from URL; extract path is optional.");
|
||||
define('LANG_content_type_help_steam_workshop', "Installs/updates a Workshop item with Workshop ID (no URL required).");
|
||||
define('LANG_content_type_help_post_script', "Runs a scripted installer action (no URL required).");
|
||||
define('LANG_content_type_help_config_edit', "Edits config at target path using provided action/rules (no URL required).");
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ function exec_ogp_module() {
|
|||
// Use the full category map so newly added types are accepted without
|
||||
// editing this file. The original three types are always present.
|
||||
$addon_types = get_server_content_type_keys();
|
||||
$addon_type = isset($_REQUEST['addon_type']) ? $_REQUEST['addon_type'] : "";
|
||||
$addon_type = isset($_REQUEST['addon_type']) ? scm_normalize_addon_type($_REQUEST['addon_type']) : "";
|
||||
|
||||
$state = isset($_REQUEST['state']) ? $_REQUEST['state'] : "";
|
||||
$pid = isset($_REQUEST['pid']) ? $_REQUEST['pid'] : -1;
|
||||
|
|
@ -556,12 +556,6 @@ function exec_ogp_module() {
|
|||
|
||||
return;
|
||||
}
|
||||
if ($addon_type === 'workshop') {
|
||||
scm_ensure_workshop_schema($db);
|
||||
$view->refresh('?m=addonsmanager&p=workshop_content&home_id='.(int)$home_id.'&mod_id='.(int)$mod_id.'&ip='.urlencode((string)$ip).'&port='.urlencode((string)$port), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<?php
|
||||
$addon_type_lang_key = "server_content_".$addon_type;
|
||||
|
|
|
|||
|
|
@ -47,11 +47,12 @@ function exec_ogp_module() {
|
|||
$fields['name'] = isset($_POST['name']) ? trim((string)$_POST['name']) : '';
|
||||
$fields['url'] = isset($_POST['url']) ? trim((string)$_POST['url']) : '';
|
||||
$fields['path'] = isset($_POST['path']) ? trim((string)$_POST['path']) : '';
|
||||
$fields['addon_type'] = isset($_POST['addon_type']) ? trim((string)$_POST['addon_type']) : '';
|
||||
$fields['addon_type'] = '';
|
||||
$fields['home_cfg_id'] = isset($_POST['home_cfg_id']) ? (int)$_POST['home_cfg_id'] : 0;
|
||||
$fields['post_script'] = isset($_POST['post_script']) ? trim((string)$_POST['post_script']) : '';
|
||||
$fields['group_id'] = isset($_POST['group_id']) ? (int)$_POST['group_id'] : 0;
|
||||
$fields['install_method'] = in_array($_POST['install_method'], $valid_install_methods) ? $_POST['install_method'] : 'download_zip';
|
||||
$posted_install_method = isset($_POST['install_method']) ? $_POST['install_method'] : '';
|
||||
$fields['install_method'] = in_array($posted_install_method, $valid_install_methods) ? $posted_install_method : 'download_zip';
|
||||
$fields['content_version'] = isset($_POST['content_version']) ? $_POST['content_version'] : '';
|
||||
$fields['requires_stop'] = !empty($_POST['requires_stop']) ? 1 : 0;
|
||||
$fields['backup_before_install'] = !empty($_POST['backup_before_install']) ? 1 : 0;
|
||||
|
|
@ -64,15 +65,12 @@ function exec_ogp_module() {
|
|||
$fields['optional_folder_name']= isset($_POST['optional_folder_name']) ? trim((string)$_POST['optional_folder_name']) : '';
|
||||
$fields['config_edit_rule'] = isset($_POST['config_edit_rule']) ? trim((string)$_POST['config_edit_rule']) : '';
|
||||
$fields['launch_param_additions'] = isset($_POST['launch_param_additions']) ? trim((string)$_POST['launch_param_additions']) : '';
|
||||
$fields['addon_type'] = scm_get_addon_type_from_install_method($fields['install_method']);
|
||||
|
||||
if ($fields['name'] === '')
|
||||
{
|
||||
print_failure(get_lang("fill_the_addon_name"));
|
||||
}
|
||||
elseif (empty($fields['addon_type']) || !in_array($fields['addon_type'], $addon_types))
|
||||
{
|
||||
print_failure(get_lang("select_an_addon_type"));
|
||||
}
|
||||
elseif (empty($fields['home_cfg_id']))
|
||||
{
|
||||
print_failure(get_lang("select_a_game_type"));
|
||||
|
|
@ -135,7 +133,7 @@ function exec_ogp_module() {
|
|||
$path = isset($addon_info['path']) ? $addon_info['path'] : "";
|
||||
$post_script = isset($addon_info['post_script']) ? $addon_info['post_script'] : "";
|
||||
$home_cfg_id = isset($addon_info['home_cfg_id']) ? $addon_info['home_cfg_id'] : "";
|
||||
$addon_type = isset($addon_info['addon_type']) ? $addon_info['addon_type'] : "";
|
||||
$addon_type = scm_normalize_addon_type(isset($addon_info['addon_type']) ? $addon_info['addon_type'] : "", $install_method);
|
||||
$group_id = isset($addon_info['group_id']) ? $addon_info['group_id'] : "";
|
||||
$install_method = isset($addon_info['install_method']) ? $addon_info['install_method'] : "download_zip";
|
||||
$content_version = isset($addon_info['content_version']) ? $addon_info['content_version'] : "";
|
||||
|
|
@ -208,10 +206,10 @@ function exec_ogp_module() {
|
|||
</tr>
|
||||
<tr id="scm-row-workshop-app-id">
|
||||
<td align="right">
|
||||
<b>Workshop App ID</b>
|
||||
<b>Game Compatibility (Workshop App ID)</b>
|
||||
</td>
|
||||
<td align="left">
|
||||
<input type="text" value="<?php echo htmlspecialchars($workshop_app_id, ENT_QUOTES, 'UTF-8'); ?>" name="workshop_app_id" size="85" placeholder="Optional override, e.g. 221100" />
|
||||
<input type="text" value="<?php echo htmlspecialchars($workshop_app_id, ENT_QUOTES, 'UTF-8'); ?>" name="workshop_app_id" size="85" placeholder="Optional App ID override, e.g. 221100" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="scm-row-target-path-template">
|
||||
|
|
@ -302,22 +300,6 @@ function exec_ogp_module() {
|
|||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
<b><?php print_lang('type'); ?></b>
|
||||
</td>
|
||||
<td align="left">
|
||||
<?php
|
||||
// Render a radio button for every registered content type.
|
||||
// New types automatically appear here once added to server_content_categories.php.
|
||||
foreach ((array)$addon_type_labels as $type_key => $type_label)
|
||||
{
|
||||
$checked = ( isset($addon_type) AND $type_key == $addon_type) ? 'checked' : '';
|
||||
echo '<input type="radio" name="addon_type" value="'.htmlspecialchars($type_key).'" '.$checked.'>'.htmlspecialchars($type_label).' ';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
<b><?php print_lang('show_to_group'); ?></b>
|
||||
|
|
@ -514,7 +496,6 @@ function exec_ogp_module() {
|
|||
}
|
||||
|
||||
$home_cfg_id = !empty($_GET['home_cfg_id']) && (int)$_GET['home_cfg_id'] > 0 ? (int)$_GET['home_cfg_id'] : 0;
|
||||
// Validate the requested addon_type against the full category map so new types are accepted.
|
||||
$addon_type = !empty($_GET['addon_type']) && in_array($_GET['addon_type'], $addon_types) ? $_GET['addon_type'] : "";
|
||||
$group_id = isset($_GET['group_id']) && is_numeric($_GET['group_id']) ? (int)$_GET['group_id'] : 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,17 +40,10 @@
|
|||
function get_server_content_categories()
|
||||
{
|
||||
return array(
|
||||
// ── Original types (must remain for backward compatibility) ──────────
|
||||
'plugin' => 'Plugins / Mods',
|
||||
'mappack' => 'Map Packs',
|
||||
'config' => 'Config Packs',
|
||||
|
||||
// ── Extended types (require addon_type VARCHAR(32) – db_version 2) ──
|
||||
'version' => 'Server Versions', // e.g. Minecraft jar switcher
|
||||
'modpack' => 'Modpacks', // e.g. CurseForge / ATLauncher packs
|
||||
'workshop' => 'Workshop Content', // Steam Workshop item bundles
|
||||
'script' => 'Scripted Installer', // Admin-defined install-only scripts
|
||||
'profile' => 'Server Profiles', // Full profile: configs + mods + scripts
|
||||
'file_download' => 'File Download / Archive',
|
||||
'workshop_item' => 'Steam Workshop Item',
|
||||
'config_edit' => 'Config Edit',
|
||||
'scripted_installer' => 'Scripted Installer',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -80,3 +73,34 @@ function get_server_content_type_keys()
|
|||
{
|
||||
return array_keys(get_server_content_categories());
|
||||
}
|
||||
|
||||
function scm_get_addon_type_from_install_method($install_method)
|
||||
{
|
||||
$install_method = trim((string)$install_method);
|
||||
$map = array(
|
||||
'download_zip' => 'file_download',
|
||||
'steam_workshop' => 'workshop_item',
|
||||
'config_edit' => 'config_edit',
|
||||
'post_script' => 'scripted_installer',
|
||||
);
|
||||
return isset($map[$install_method]) ? $map[$install_method] : 'file_download';
|
||||
}
|
||||
|
||||
function scm_normalize_addon_type($addon_type, $install_method = '')
|
||||
{
|
||||
$addon_type = trim((string)$addon_type);
|
||||
$categories = get_server_content_categories();
|
||||
if (isset($categories[$addon_type])) {
|
||||
return $addon_type;
|
||||
}
|
||||
if ($addon_type === 'workshop') {
|
||||
return 'workshop_item';
|
||||
}
|
||||
if ($addon_type === 'script') {
|
||||
return 'scripted_installer';
|
||||
}
|
||||
if ($addon_type === 'config') {
|
||||
return 'config_edit';
|
||||
}
|
||||
return scm_get_addon_type_from_install_method($install_method);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,55 +255,53 @@ function scm_get_cache_mode($db)
|
|||
function scm_get_install_methods()
|
||||
{
|
||||
return array(
|
||||
'download_zip' => 'Compressed file download',
|
||||
'download_file' => 'Direct file download',
|
||||
'steam_workshop' => 'Steam Workshop item',
|
||||
'post_script' => 'Script/action only',
|
||||
'config_edit' => 'Config edit only',
|
||||
'create_folder' => 'Folder/create path only',
|
||||
'download_zip' => 'File Download / Archive',
|
||||
'steam_workshop' => 'Steam Workshop Item',
|
||||
'config_edit' => 'Config Edit',
|
||||
'post_script' => 'Scripted Installer',
|
||||
);
|
||||
}
|
||||
|
||||
function scm_get_install_method_help_text()
|
||||
{
|
||||
return array(
|
||||
'download_zip' => 'Downloads and extracts an archive into the target path.',
|
||||
'download_file' => 'Downloads a single file to the target path without extraction.',
|
||||
'steam_workshop' => 'Downloads/updates a Steam Workshop item and applies it to the server path.',
|
||||
'post_script' => 'Runs only the post-install script/action body (no download).',
|
||||
'config_edit' => 'Applies config edit rules to a target config file/path.',
|
||||
'create_folder' => 'Creates the target directory path only.',
|
||||
'download_zip' => 'Downloads an archive or file from URL; extract path is optional.',
|
||||
'steam_workshop' => 'Installs a Steam Workshop item by Workshop ID without requiring URL.',
|
||||
'config_edit' => 'Applies config edits to the target file/path without requiring URL.',
|
||||
'post_script' => 'Runs an installer script/action body without requiring URL.',
|
||||
);
|
||||
}
|
||||
|
||||
function scm_get_install_method_required_fields()
|
||||
{
|
||||
return array(
|
||||
'download_zip' => array('url', 'path'),
|
||||
'download_file' => array('url', 'path'),
|
||||
'steam_workshop' => array('workshop_item_id', 'target_path_template'),
|
||||
'download_zip' => array('url'),
|
||||
'steam_workshop' => array('workshop_item_id'),
|
||||
'post_script' => array('post_script'),
|
||||
'config_edit' => array('path', 'config_edit_rule'),
|
||||
'create_folder' => array('path'),
|
||||
);
|
||||
}
|
||||
|
||||
function scm_get_install_method_validation_errors()
|
||||
{
|
||||
return array(
|
||||
'url' => 'Please enter a download URL.',
|
||||
'workshop_item_id' => 'Please enter a Workshop ID.',
|
||||
'target_path_template' => 'Please select a target install path.',
|
||||
'post_script' => 'Please enter a script/action body.',
|
||||
'config_edit_rule' => 'Please enter a config edit rule.',
|
||||
'path' => 'Please select a target install path.',
|
||||
'download_zip' => 'Please enter a download URL.',
|
||||
'steam_workshop' => 'Please enter a Workshop ID.',
|
||||
'config_edit' => 'Please enter the config target and edit action.',
|
||||
'post_script' => 'Please enter the installer script/action.',
|
||||
);
|
||||
}
|
||||
|
||||
function scm_get_install_method_default($value = '')
|
||||
{
|
||||
$methods = scm_get_install_methods();
|
||||
$value = trim((string)$value);
|
||||
if ($value === 'download_file') {
|
||||
$value = 'download_zip';
|
||||
}
|
||||
if ($value === 'create_folder') {
|
||||
$value = 'config_edit';
|
||||
}
|
||||
$methods = scm_get_install_methods();
|
||||
return isset($methods[$value]) ? $value : 'download_zip';
|
||||
}
|
||||
|
||||
|
|
@ -316,10 +314,29 @@ function scm_validate_install_method_payload($install_method, array $payload, &$
|
|||
$message = 'Invalid install/content type selected.';
|
||||
return false;
|
||||
}
|
||||
if ($install_method === 'config_edit') {
|
||||
$path = isset($payload['path']) ? trim((string)$payload['path']) : '';
|
||||
$rule = isset($payload['config_edit_rule']) ? trim((string)$payload['config_edit_rule']) : '';
|
||||
if ($path === '' || $rule === '') {
|
||||
$message = $errors['config_edit'];
|
||||
return false;
|
||||
}
|
||||
$message = '';
|
||||
return true;
|
||||
}
|
||||
if ($install_method === 'post_script') {
|
||||
$script = isset($payload['post_script']) ? trim((string)$payload['post_script']) : '';
|
||||
if ($script === '') {
|
||||
$message = $errors['post_script'];
|
||||
return false;
|
||||
}
|
||||
$message = '';
|
||||
return true;
|
||||
}
|
||||
foreach ($required[$install_method] as $field) {
|
||||
$value = isset($payload[$field]) ? trim((string)$payload[$field]) : '';
|
||||
if ($value === '') {
|
||||
$message = isset($errors[$field]) ? $errors[$field] : 'Missing required field.';
|
||||
$message = isset($errors[$install_method]) ? $errors[$install_method] : 'Missing required field.';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,24 +60,6 @@ function exec_ogp_module() {
|
|||
|
||||
foreach ((array)$categories as $type_key => $type_label)
|
||||
{
|
||||
if ($type_key === 'workshop')
|
||||
{
|
||||
$workshop_count = scm_get_workshop_saved_count($db, (int)$home_id);
|
||||
if ($printed_any_cell)
|
||||
echo "</td><td>\n";
|
||||
else
|
||||
echo "<td>\n";
|
||||
$printed_any_cell = true;
|
||||
echo "<a href='?m=addonsmanager&p=workshop_content" .
|
||||
"&home_id=" . (int)$home_id .
|
||||
"&mod_id=" . (int)$mod_id .
|
||||
"&ip=" . htmlspecialchars($ip) .
|
||||
"&port=" . htmlspecialchars($port) . "'>" .
|
||||
"Workshop Content (" . (int)$workshop_count . ")" .
|
||||
"</a>\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$items = $db->resultQuery(
|
||||
"SELECT DISTINCT addon_id, name, game_name " .
|
||||
"FROM OGP_DB_PREFIXaddons " .
|
||||
|
|
|
|||
|
|
@ -379,19 +379,41 @@ return ['success' => true, 'file' => $archive_file];
|
|||
|
||||
function gsp_backup_apache_configs($backup_dir)
|
||||
{
|
||||
$apache_source = '/etc/apache2/sites-available';
|
||||
if (!is_dir($apache_source)) {
|
||||
return ['success' => false, 'error' => 'Apache sites-available path not found: ' . $apache_source];
|
||||
$available_source = '/etc/apache2/sites-available';
|
||||
$enabled_source = '/etc/apache2/sites-enabled';
|
||||
if (!is_dir($available_source)) {
|
||||
return ['success' => false, 'error' => 'Apache sites-available path not found: ' . $available_source];
|
||||
}
|
||||
$dest = $backup_dir . '/apache-sites-available';
|
||||
if (!@mkdir($dest, 0755, true) && !is_dir($dest)) {
|
||||
$dest = $backup_dir . '/apache-configs';
|
||||
$dest_available = $dest . '/sites-available';
|
||||
$dest_enabled = $dest . '/sites-enabled';
|
||||
if (!@mkdir($dest_available, 0755, true) && !is_dir($dest_available)) {
|
||||
return ['success' => false, 'error' => 'Cannot create apache backup directory.'];
|
||||
}
|
||||
$files = glob($apache_source . '/*.conf') ?: [];
|
||||
foreach ($files as $file) {
|
||||
@copy($file, $dest . '/' . basename($file));
|
||||
if (!@mkdir($dest_enabled, 0755, true) && !is_dir($dest_enabled)) {
|
||||
return ['success' => false, 'error' => 'Cannot create apache enabled backup directory.'];
|
||||
}
|
||||
return ['success' => true, 'path' => $dest, 'count' => count($files)];
|
||||
$count = 0;
|
||||
foreach ((glob($available_source . '/*.conf') ?: []) as $file) {
|
||||
if (@copy($file, $dest_available . '/' . basename($file))) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if (is_dir($enabled_source)) {
|
||||
foreach ((glob($enabled_source . '/*') ?: []) as $file) {
|
||||
$dst = $dest_enabled . '/' . basename($file);
|
||||
if (is_link($file)) {
|
||||
$target = @readlink($file);
|
||||
if ($target !== false) {
|
||||
@symlink($target, $dst);
|
||||
$count++;
|
||||
}
|
||||
} elseif (is_file($file) && @copy($file, $dst)) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ['success' => true, 'path' => $dest, 'count' => $count];
|
||||
}
|
||||
|
||||
function gsp_prune_old_backups($max_backups = 5)
|
||||
|
|
@ -593,6 +615,7 @@ function gsp_copy_tree($src_root, $dst_root, $base_rel = '')
|
|||
{
|
||||
$copied = 0;
|
||||
$skipped = [];
|
||||
$copied_files = [];
|
||||
$source = rtrim($src_root, '/');
|
||||
$iter = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
|
|
@ -613,9 +636,12 @@ continue;
|
|||
}
|
||||
if (gsp_copy_file($item->getPathname(), $dst)) {
|
||||
$copied++;
|
||||
if (count($copied_files) < 200) {
|
||||
$copied_files[] = $rel;
|
||||
}
|
||||
}
|
||||
return ['copied' => $copied, 'skipped' => $skipped];
|
||||
}
|
||||
return ['copied' => $copied, 'skipped' => $skipped, 'copied_files' => $copied_files];
|
||||
}
|
||||
|
||||
function gsp_updater_watch_list()
|
||||
|
|
@ -694,7 +720,11 @@ function gsp_apply_layout_sync($source_root)
|
|||
$top_level = scandir($source_root);
|
||||
$skip = ['.', '..', '.git', '.github', '.gitignore', '.vscode'];
|
||||
$copied = 0;
|
||||
$panel_copied = 0;
|
||||
$website_copied = 0;
|
||||
$skipped = [];
|
||||
$copied_files = [];
|
||||
gsp_update_log('Layout sync source mapping: ' . $source_root . '/Panel => ' . GSP_PANEL_DIR . ' ; ' . $source_root . '/Website => ' . GSP_WEBSITE_DIR);
|
||||
foreach ((array)$top_level as $entry) {
|
||||
if (in_array($entry, $skip, true)) {
|
||||
continue;
|
||||
|
|
@ -713,19 +743,32 @@ continue;
|
|||
}
|
||||
if (gsp_copy_file($src, $dst)) {
|
||||
$copied++;
|
||||
if (count($copied_files) < 200) {
|
||||
$copied_files[] = $rel;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (is_dir($src)) {
|
||||
$part = gsp_copy_tree($src, GSP_ROOT_DIR, $entry);
|
||||
$copied += $part['copied'];
|
||||
$copied_files = array_merge($copied_files, array_slice((array)$part['copied_files'], 0, max(0, 200 - count($copied_files))));
|
||||
if ($entry === 'Panel') {
|
||||
$panel_copied += $part['copied'];
|
||||
}
|
||||
if ($entry === 'Website') {
|
||||
$website_copied += $part['copied'];
|
||||
}
|
||||
$skipped = array_merge($skipped, $part['skipped']);
|
||||
}
|
||||
}
|
||||
return [
|
||||
'success' => true,
|
||||
'files_copied' => $copied,
|
||||
'panel_files_copied' => $panel_copied,
|
||||
'website_files_copied' => $website_copied,
|
||||
'skipped' => array_values(array_unique($skipped)),
|
||||
'copied_files' => array_slice(array_values(array_unique($copied_files)), 0, 200),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -792,13 +835,27 @@ if (!$sync['success']) {
|
|||
return $sync;
|
||||
}
|
||||
gsp_update_log('Layout sync complete: copied=' . $sync['files_copied'] . ', skipped=' . count($sync['skipped']));
|
||||
gsp_update_log('Layout sync totals: Panel=' . intval($sync['panel_files_copied']) . ', Website=' . intval($sync['website_files_copied']));
|
||||
if (!empty($sync['skipped'])) {
|
||||
gsp_update_log('Preserved paths: ' . implode(', ', array_slice($sync['skipped'], 0, 50)));
|
||||
}
|
||||
if (!empty($sync['copied_files'])) {
|
||||
$copied_sample = array_slice((array)$sync['copied_files'], 0, 50);
|
||||
gsp_update_log('Copied file sample: ' . implode(', ', $copied_sample));
|
||||
$addons_updates = array_values(array_filter((array)$sync['copied_files'], function ($rel) {
|
||||
return strpos($rel, 'Panel/modules/addonsmanager/') === 0;
|
||||
}));
|
||||
if (!empty($addons_updates)) {
|
||||
gsp_update_log('Addonsmanager files copied: ' . implode(', ', array_slice($addons_updates, 0, 50)));
|
||||
}
|
||||
}
|
||||
return [
|
||||
'success' => true,
|
||||
'files_copied' => $sync['files_copied'],
|
||||
'panel_files_copied' => $sync['panel_files_copied'],
|
||||
'website_files_copied' => $sync['website_files_copied'],
|
||||
'preserved' => $sync['skipped'],
|
||||
'copied_files' => $sync['copied_files'],
|
||||
'patches' => $patches['run'],
|
||||
];
|
||||
}
|
||||
|
|
@ -885,6 +942,9 @@ gsp_update_log("Update to {$ref} (type={$update_type}) complete");
|
|||
return [
|
||||
'success' => true,
|
||||
'files_copied' => $apply['files_copied'],
|
||||
'panel_files_copied' => isset($apply['panel_files_copied']) ? $apply['panel_files_copied'] : 0,
|
||||
'website_files_copied' => isset($apply['website_files_copied']) ? $apply['website_files_copied'] : 0,
|
||||
'copied_files' => isset($apply['copied_files']) ? $apply['copied_files'] : [],
|
||||
'backup_dir' => $backup['backup_dir'],
|
||||
'preserved' => $apply['preserved'],
|
||||
'patches' => $apply['patches'],
|
||||
|
|
@ -1016,8 +1076,9 @@ if (!$db_restore['success']) {
|
|||
gsp_update_log('Revert warning: ' . $db_restore['error']);
|
||||
}
|
||||
|
||||
if ($restore_apache && is_dir($backup_dir . '/apache-sites-available')) {
|
||||
$apache_restore = gsp_restore_apache_backup($backup_dir . '/apache-sites-available', true);
|
||||
if ($restore_apache && (is_dir($backup_dir . '/apache-configs') || is_dir($backup_dir . '/apache-sites-available'))) {
|
||||
$apache_backup_dir = is_dir($backup_dir . '/apache-configs') ? ($backup_dir . '/apache-configs') : ($backup_dir . '/apache-sites-available');
|
||||
$apache_restore = gsp_restore_apache_backup($apache_backup_dir, true);
|
||||
if (!$apache_restore['success']) {
|
||||
gsp_update_log('Revert apache restore warning: ' . $apache_restore['error']);
|
||||
}
|
||||
|
|
@ -1033,6 +1094,46 @@ gsp_update_log('Revert complete: ' . $backup_ts);
|
|||
return ['success' => true, 'files_restored' => 0];
|
||||
}
|
||||
|
||||
function gsp_get_apache_vhost_target_path($filename)
|
||||
{
|
||||
$name = strtolower((string)$filename);
|
||||
if (strpos($name, 'panel.') === 0) {
|
||||
return GSP_PANEL_DIR;
|
||||
}
|
||||
if (strpos($name, 'gameservers.world') !== false) {
|
||||
return GSP_WEBSITE_DIR;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function gsp_is_apache_stale_path($path)
|
||||
{
|
||||
$path = trim((string)$path);
|
||||
$stale = [
|
||||
'/var/www/html/panel',
|
||||
'/var/www/html/GSP/Panel/GSP/Panel',
|
||||
'/var/www/html/GSP/Panel/modules/billing',
|
||||
];
|
||||
if (in_array($path, $stale, true)) {
|
||||
return true;
|
||||
}
|
||||
return (strpos($path, '/var/www/html/panel/') === 0 || strpos($path, '/var/www/html/GSP/Panel/modules/billing/') === 0);
|
||||
}
|
||||
|
||||
function gsp_parse_apache_cert_error_line($line)
|
||||
{
|
||||
$line = trim((string)$line);
|
||||
if (preg_match("/(SSLCertificate(?:File|KeyFile)):\\s*file '([^']+)' (does not exist(?: or is empty)?|is empty)/i", $line, $m)) {
|
||||
return [
|
||||
'directive' => $m[1],
|
||||
'path' => $m[2],
|
||||
'reason' => $m[3],
|
||||
'line' => $line,
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function gsp_scan_apache_configs()
|
||||
{
|
||||
$base = '/etc/apache2/sites-available';
|
||||
|
|
@ -1042,6 +1143,9 @@ $result = [
|
|||
'base' => $base,
|
||||
'files' => [],
|
||||
'issues' => [],
|
||||
'stale_issues' => [],
|
||||
'ssl_issues' => [],
|
||||
'planned_replacements' => [],
|
||||
'recommendations' => [],
|
||||
];
|
||||
if (!$result['available']) {
|
||||
|
|
@ -1049,64 +1153,156 @@ $result['success'] = false;
|
|||
$result['issues'][] = 'Apache sites-available directory not found.';
|
||||
return $result;
|
||||
}
|
||||
$stale = [
|
||||
'/var/www/html/panel',
|
||||
'/var/www/html/GSP/Panel/GSP/Panel',
|
||||
'/var/www/html/GSP/Panel/modules/billing',
|
||||
];
|
||||
$files = glob($base . '/*.conf') ?: [];
|
||||
foreach ($files as $file) {
|
||||
$lines = @file($file, FILE_IGNORE_NEW_LINES);
|
||||
if (!is_array($lines)) {
|
||||
continue;
|
||||
}
|
||||
$file_info = ['file' => $file, 'document_roots' => [], 'directories' => [], 'stale_hits' => []];
|
||||
foreach ($lines as $line) {
|
||||
$vhost = basename($file);
|
||||
$target = gsp_get_apache_vhost_target_path($vhost);
|
||||
$file_info = [
|
||||
'file' => $file,
|
||||
'vhost' => $vhost,
|
||||
'target' => $target,
|
||||
'document_roots' => [],
|
||||
'directories' => [],
|
||||
'stale_hits' => [],
|
||||
'ssl_hits' => [],
|
||||
];
|
||||
foreach ($lines as $line_number => $line) {
|
||||
if (preg_match('/^\s*DocumentRoot\s+(.+)$/i', $line, $m)) {
|
||||
$path = trim($m[1], "\"' ");
|
||||
$file_info['document_roots'][] = $path;
|
||||
if ($target !== null && $path !== $target && gsp_is_apache_stale_path($path)) {
|
||||
$msg = $vhost . ' stale DocumentRoot: ' . $path . ' -> ' . $target;
|
||||
$result['stale_issues'][] = $msg;
|
||||
$result['issues'][] = $msg;
|
||||
$result['planned_replacements'][] = ['vhost' => $vhost, 'directive' => 'DocumentRoot', 'from' => $path, 'to' => $target];
|
||||
$file_info['stale_hits'][] = $path;
|
||||
}
|
||||
}
|
||||
if (preg_match('/^\s*<Directory\s+(.+)>/i', $line, $m)) {
|
||||
$path = trim($m[1], "\"' ");
|
||||
$file_info['directories'][] = $path;
|
||||
if ($target !== null && $path !== $target && gsp_is_apache_stale_path($path)) {
|
||||
$msg = $vhost . ' stale <Directory>: ' . $path . ' -> ' . $target;
|
||||
$result['stale_issues'][] = $msg;
|
||||
$result['issues'][] = $msg;
|
||||
$result['planned_replacements'][] = ['vhost' => $vhost, 'directive' => '<Directory>', 'from' => $path, 'to' => $target];
|
||||
$file_info['stale_hits'][] = $path;
|
||||
}
|
||||
foreach ($stale as $stalePath) {
|
||||
if (strpos($line, $stalePath) !== false) {
|
||||
$file_info['stale_hits'][] = $stalePath;
|
||||
$result['issues'][] = basename($file) . ' contains stale path: ' . $stalePath;
|
||||
}
|
||||
if (preg_match('/^\s*(SSLCertificate(?:File|KeyFile))\s+(.+)$/i', $line, $m)) {
|
||||
$directive = $m[1];
|
||||
$path = trim($m[2], "\"' ");
|
||||
if ($path !== '' && (!file_exists($path) || @filesize($path) === 0)) {
|
||||
$reason = !file_exists($path) ? 'missing' : 'empty';
|
||||
$msg = $vhost . ' ' . $directive . ' ' . $path . ' is ' . $reason;
|
||||
$issue = ['vhost' => $vhost, 'directive' => $directive, 'path' => $path, 'reason' => $reason, 'line' => ($line_number + 1), 'message' => $msg];
|
||||
$result['ssl_issues'][] = $issue;
|
||||
$result['issues'][] = $msg;
|
||||
$file_info['ssl_hits'][] = $issue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($file_info['stale_hits'])) {
|
||||
if (stripos($file, 'gameservers.world') !== false) {
|
||||
$result['recommendations'][] = basename($file) . ' should target ' . GSP_WEBSITE_DIR;
|
||||
} else {
|
||||
$result['recommendations'][] = basename($file) . ' should target ' . GSP_PANEL_DIR;
|
||||
}
|
||||
if ($target !== null) {
|
||||
$result['recommendations'][] = $vhost . ' should target ' . $target;
|
||||
}
|
||||
$result['files'][] = $file_info;
|
||||
}
|
||||
$result['stale_issues'] = array_values(array_unique($result['stale_issues']));
|
||||
$result['issues'] = array_values(array_unique($result['issues']));
|
||||
return $result;
|
||||
}
|
||||
|
||||
function gsp_apache_configtest_only_cert_failures($configtest_output)
|
||||
{
|
||||
$lines = preg_split('/\r\n|\r|\n/', (string)$configtest_output);
|
||||
$seen = 0;
|
||||
foreach ((array)$lines as $line) {
|
||||
$line = trim((string)$line);
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
if (stripos($line, 'Syntax OK') !== false) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^AH[0-9]+:\s+/i', $line) && stripos($line, 'Could not reliably determine') !== false) {
|
||||
continue;
|
||||
}
|
||||
if (gsp_parse_apache_cert_error_line($line) !== null) {
|
||||
$seen++;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return $seen > 0;
|
||||
}
|
||||
|
||||
function gsp_extract_apache_configtest_cert_issues($configtest_output)
|
||||
{
|
||||
$issues = [];
|
||||
$lines = preg_split('/\r\n|\r|\n/', (string)$configtest_output);
|
||||
foreach ((array)$lines as $line) {
|
||||
$parsed = gsp_parse_apache_cert_error_line($line);
|
||||
if ($parsed !== null) {
|
||||
$issues[] = $parsed;
|
||||
}
|
||||
}
|
||||
return $issues;
|
||||
}
|
||||
|
||||
function gsp_restore_apache_backup($backup_dir, $reload_apache)
|
||||
{
|
||||
$target = '/etc/apache2/sites-available';
|
||||
$available_target = '/etc/apache2/sites-available';
|
||||
$enabled_target = '/etc/apache2/sites-enabled';
|
||||
if (!is_dir($backup_dir)) {
|
||||
return ['success' => false, 'error' => 'Apache backup folder not found.'];
|
||||
}
|
||||
$files = glob($backup_dir . '/*.conf') ?: [];
|
||||
foreach ($files as $file) {
|
||||
@copy($file, $target . '/' . basename($file));
|
||||
$available_backup = is_dir($backup_dir . '/sites-available') ? $backup_dir . '/sites-available' : $backup_dir;
|
||||
$enabled_backup = $backup_dir . '/sites-enabled';
|
||||
$restored = 0;
|
||||
foreach ((glob($available_backup . '/*.conf') ?: []) as $file) {
|
||||
if (@copy($file, $available_target . '/' . basename($file))) {
|
||||
$restored++;
|
||||
}
|
||||
}
|
||||
if (is_dir($enabled_backup)) {
|
||||
foreach ((glob($enabled_backup . '/*') ?: []) as $file) {
|
||||
$dst = $enabled_target . '/' . basename($file);
|
||||
if (is_link($dst) || is_file($dst)) {
|
||||
@unlink($dst);
|
||||
}
|
||||
if (is_link($file)) {
|
||||
$link_target = @readlink($file);
|
||||
if ($link_target !== false) {
|
||||
@symlink($link_target, $dst);
|
||||
$restored++;
|
||||
}
|
||||
} elseif (is_file($file) && @copy($file, $dst)) {
|
||||
$restored++;
|
||||
}
|
||||
}
|
||||
}
|
||||
$test = gsp_apache_configtest();
|
||||
if (!$test['success']) {
|
||||
if (gsp_apache_configtest_only_cert_failures($test['output'])) {
|
||||
return [
|
||||
'success' => true,
|
||||
'restored' => $restored,
|
||||
'configtest' => $test,
|
||||
'warnings' => ['Apache config restore completed, but SSL certificate file(s) are missing.'],
|
||||
'ssl_issues' => gsp_extract_apache_configtest_cert_issues($test['output']),
|
||||
];
|
||||
}
|
||||
return ['success' => false, 'error' => 'apache2ctl configtest failed after restore: ' . $test['output']];
|
||||
}
|
||||
$reload = ['success' => true, 'output' => 'Apache reload skipped'];
|
||||
if ($reload_apache) {
|
||||
gsp_apache_reload();
|
||||
$reload = gsp_apache_reload();
|
||||
}
|
||||
return ['success' => true, 'restored' => count($files)];
|
||||
return ['success' => true, 'restored' => $restored, 'configtest' => $test, 'reload' => $reload];
|
||||
}
|
||||
|
||||
function gsp_apache_configtest()
|
||||
|
|
@ -1136,6 +1332,31 @@ function gsp_fix_apache_paths($confirmed, $reload_apache)
|
|||
if (!$confirmed) {
|
||||
return ['success' => false, 'error' => 'Apache path fix requires explicit confirmation.'];
|
||||
}
|
||||
|
||||
function gsp_disable_ssl_vhost($vhost_file, $confirmed)
|
||||
{
|
||||
if (!$confirmed) {
|
||||
return ['success' => false, 'error' => 'SSL vhost disable requires confirmation.'];
|
||||
}
|
||||
$vhost = basename((string)$vhost_file);
|
||||
if (!preg_match('/\.conf$/', $vhost) || strpos($vhost, '-ssl') === false) {
|
||||
return ['success' => false, 'error' => 'Only SSL vhost .conf files can be disabled from this action.'];
|
||||
}
|
||||
$enabled_path = '/etc/apache2/sites-enabled/' . $vhost;
|
||||
if (!file_exists($enabled_path) && !is_link($enabled_path)) {
|
||||
return ['success' => true, 'message' => $vhost . ' is already disabled.'];
|
||||
}
|
||||
if (!@unlink($enabled_path)) {
|
||||
return ['success' => false, 'error' => 'Failed to disable SSL site: ' . $vhost];
|
||||
}
|
||||
$test = gsp_apache_configtest();
|
||||
if (!$test['success']) {
|
||||
return ['success' => false, 'error' => 'Disabled site but apache2ctl configtest still failed: ' . $test['output']];
|
||||
}
|
||||
$reload = gsp_apache_reload();
|
||||
gsp_update_log('Disabled SSL vhost in sites-enabled: ' . $vhost);
|
||||
return ['success' => true, 'configtest' => $test, 'reload' => $reload, 'message' => 'Disabled SSL vhost: ' . $vhost];
|
||||
}
|
||||
$scan = gsp_scan_apache_configs();
|
||||
if (!$scan['available']) {
|
||||
return ['success' => false, 'error' => 'Apache config folder not available.'];
|
||||
|
|
@ -1148,18 +1369,34 @@ return ['success' => false, 'error' => 'Could not create backup before apache fi
|
|||
|
||||
$base = '/etc/apache2/sites-available';
|
||||
$files = glob($base . '/*.conf') ?: [];
|
||||
$replace = [
|
||||
'/var/www/html/panel' => GSP_PANEL_DIR,
|
||||
'/var/www/html/GSP/Panel/GSP/Panel' => GSP_PANEL_DIR,
|
||||
'/var/www/html/GSP/Panel/modules/billing' => GSP_WEBSITE_DIR,
|
||||
];
|
||||
$changed = [];
|
||||
$planned = [];
|
||||
foreach ($files as $file) {
|
||||
$orig = @file_get_contents($file);
|
||||
if ($orig === false) {
|
||||
continue;
|
||||
}
|
||||
$new = strtr($orig, $replace);
|
||||
$vhost = basename($file);
|
||||
$target = gsp_get_apache_vhost_target_path($vhost);
|
||||
if ($target === null) {
|
||||
continue;
|
||||
}
|
||||
$new = preg_replace_callback('/(^\s*DocumentRoot\s+)(["\']?)([^"\']+)(\2\s*$)/mi', function ($m) use ($target, $vhost, &$planned) {
|
||||
$current = trim((string)$m[3]);
|
||||
if ($current === $target || !gsp_is_apache_stale_path($current)) {
|
||||
return $m[0];
|
||||
}
|
||||
$planned[] = ['vhost' => $vhost, 'directive' => 'DocumentRoot', 'from' => $current, 'to' => $target];
|
||||
return $m[1] . $m[2] . $target . $m[2];
|
||||
}, $orig);
|
||||
$new = preg_replace_callback('/(^\s*<Directory\s+)(["\']?)([^"\'>]+)(\2\s*>)/mi', function ($m) use ($target, $vhost, &$planned) {
|
||||
$current = trim((string)$m[3]);
|
||||
if ($current === $target || !gsp_is_apache_stale_path($current)) {
|
||||
return $m[0];
|
||||
}
|
||||
$planned[] = ['vhost' => $vhost, 'directive' => '<Directory>', 'from' => $current, 'to' => $target];
|
||||
return $m[1] . $m[2] . $target . $m[2] . '>';
|
||||
}, $new);
|
||||
if ($new !== $orig) {
|
||||
@file_put_contents($file, $new);
|
||||
$changed[] = $file;
|
||||
|
|
@ -1168,13 +1405,27 @@ $changed[] = $file;
|
|||
|
||||
$test = gsp_apache_configtest();
|
||||
if (!$test['success']) {
|
||||
$restore = gsp_restore_apache_backup($backup['backup_dir'] . '/apache-sites-available', false);
|
||||
$cert_only = gsp_apache_configtest_only_cert_failures($test['output']);
|
||||
if (!$cert_only) {
|
||||
$restore = gsp_restore_apache_backup($backup['backup_dir'] . '/apache-configs', false);
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'apache2ctl configtest failed; restored backup. Output: ' . $test['output']
|
||||
. ($restore['success'] ? '' : (' | restore failed: ' . $restore['error'])),
|
||||
];
|
||||
}
|
||||
gsp_update_log('Apache path fix completed but SSL certificates are missing: ' . $test['output']);
|
||||
return [
|
||||
'success' => true,
|
||||
'warning' => 'Apache paths fixed, but SSL certificate is missing.',
|
||||
'changed_files' => $changed,
|
||||
'backup_dir' => $backup['backup_dir'],
|
||||
'configtest' => $test,
|
||||
'planned_replacements' => $planned,
|
||||
'ssl_issues' => gsp_extract_apache_configtest_cert_issues($test['output']),
|
||||
'reload' => ['success' => false, 'output' => 'Apache reload skipped because SSL certificate files are missing.'],
|
||||
];
|
||||
}
|
||||
|
||||
$reload = ['success' => true, 'output' => 'Apache reload skipped'];
|
||||
if ($reload_apache) {
|
||||
|
|
@ -1182,12 +1433,19 @@ $reload = gsp_apache_reload();
|
|||
}
|
||||
|
||||
gsp_update_log('Apache path fix changed ' . count($changed) . ' file(s).');
|
||||
if (!empty($planned)) {
|
||||
$samples = array_slice($planned, 0, 20);
|
||||
foreach ($samples as $entry) {
|
||||
gsp_update_log('Apache replacement planned/applied: ' . $entry['vhost'] . ' ' . $entry['directive'] . ' ' . $entry['from'] . ' => ' . $entry['to']);
|
||||
}
|
||||
}
|
||||
return [
|
||||
'success' => true,
|
||||
'changed_files' => $changed,
|
||||
'backup_dir' => $backup['backup_dir'],
|
||||
'configtest' => $test,
|
||||
'reload' => $reload,
|
||||
'planned_replacements' => $planned,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -1293,10 +1551,26 @@ print_failure('Patch application failed: ' . htmlspecialchars($run['error']));
|
|||
} elseif ($action === 'fix_apache') {
|
||||
$apache_fix = gsp_fix_apache_paths(true, true);
|
||||
if ($apache_fix['success']) {
|
||||
if (!empty($apache_fix['warning'])) {
|
||||
print_success(htmlspecialchars($apache_fix['warning']) . ' Updated files: ' . intval(count($apache_fix['changed_files'])) . '.');
|
||||
echo "<p style='color:#8a6d3b;'><strong>Renew SSL certificate:</strong> <code>certbot --apache -d gameservers.world -d www.gameservers.world</code></p>\n";
|
||||
} else {
|
||||
print_success('Apache paths fixed successfully. Updated files: ' . intval(count($apache_fix['changed_files'])) . '.');
|
||||
}
|
||||
if (!empty($apache_fix['configtest']['output'])) {
|
||||
echo "<p><strong>apache2ctl configtest output:</strong><br><pre style='white-space:pre-wrap;max-height:220px;overflow:auto;'>" . htmlspecialchars($apache_fix['configtest']['output']) . "</pre></p>\n";
|
||||
}
|
||||
} else {
|
||||
print_failure('Apache path fix failed: ' . htmlspecialchars($apache_fix['error']));
|
||||
}
|
||||
} elseif ($action === 'disable_ssl_vhost') {
|
||||
$vhost = isset($_POST['gsp_ssl_vhost']) ? trim($_POST['gsp_ssl_vhost']) : '';
|
||||
$disable = gsp_disable_ssl_vhost($vhost, true);
|
||||
if ($disable['success']) {
|
||||
print_success(htmlspecialchars(isset($disable['message']) ? $disable['message'] : 'SSL vhost disabled.'));
|
||||
} else {
|
||||
print_failure('Disable SSL vhost failed: ' . htmlspecialchars($disable['error']));
|
||||
}
|
||||
} elseif ($action === 'backup_only') {
|
||||
$result = gsp_create_full_backup('backup-only', 'manual', false);
|
||||
if ($result['success']) {
|
||||
|
|
@ -1315,7 +1589,7 @@ print_success('Updater files changed and were updated first. Restarting update w
|
|||
$auto_restart_payload = ['action' => 'update_release', 'nonce' => $result['restart_nonce'], 'version' => $version];
|
||||
} elseif ($result['success']) {
|
||||
print_success('Panel updated to release <strong>' . htmlspecialchars($version) . '</strong>. '
|
||||
. intval($result['files_copied']) . ' file(s) copied.');
|
||||
. intval($result['files_copied']) . ' file(s) copied (Panel: ' . intval($result['panel_files_copied']) . ', Website: ' . intval($result['website_files_copied']) . ').');
|
||||
} else {
|
||||
print_failure('Update failed: ' . htmlspecialchars($result['error']));
|
||||
}
|
||||
|
|
@ -1327,7 +1601,7 @@ print_success('Updater files changed and were updated first. Restarting stable u
|
|||
$auto_restart_payload = ['action' => 'update_stable', 'nonce' => $result['restart_nonce']];
|
||||
} elseif ($result['success']) {
|
||||
print_success('Panel updated to GitHub Stable (<strong>' . htmlspecialchars($stable_branch) . '</strong>). '
|
||||
. intval($result['files_copied']) . ' file(s) copied.');
|
||||
. intval($result['files_copied']) . ' file(s) copied (Panel: ' . intval($result['panel_files_copied']) . ', Website: ' . intval($result['website_files_copied']) . ').');
|
||||
} else {
|
||||
print_failure('Update failed: ' . htmlspecialchars($result['error']));
|
||||
}
|
||||
|
|
@ -1338,7 +1612,7 @@ print_success('Updater files changed and were updated first. Restarting unstable
|
|||
$auto_restart_payload = ['action' => 'update_unstable', 'nonce' => $result['restart_nonce']];
|
||||
} elseif ($result['success']) {
|
||||
print_success('Panel updated to GitHub Unstable (<strong>' . htmlspecialchars($unstable_branch) . '</strong>). '
|
||||
. intval($result['files_copied']) . ' file(s) copied.');
|
||||
. intval($result['files_copied']) . ' file(s) copied (Panel: ' . intval($result['panel_files_copied']) . ', Website: ' . intval($result['website_files_copied']) . ').');
|
||||
} else {
|
||||
print_failure('Update failed: ' . htmlspecialchars($result['error']));
|
||||
}
|
||||
|
|
@ -1438,12 +1712,40 @@ echo "<br><br><h3>Apache Configuration Status</h3>\n";
|
|||
echo "<table class='center'>\n";
|
||||
echo "<tr><td><strong>Config Directory:</strong></td><td><code>" . htmlspecialchars($apache_scan_result['base']) . "</code></td></tr>\n";
|
||||
echo "<tr><td><strong>Configs Found:</strong></td><td>" . intval(count($apache_scan_result['files'])) . "</td></tr>\n";
|
||||
echo "<tr><td><strong>Stale Path Hits:</strong></td><td>" . intval(count($apache_scan_result['issues'])) . "</td></tr>\n";
|
||||
echo "<tr><td><strong>Stale Path Hits:</strong></td><td>" . intval(count($apache_scan_result['stale_issues'])) . "</td></tr>\n";
|
||||
echo "<tr><td><strong>SSL Certificate Issues:</strong></td><td>" . intval(count($apache_scan_result['ssl_issues'])) . "</td></tr>\n";
|
||||
echo "<tr><td><strong>Recommended Panel Path:</strong></td><td><code>" . htmlspecialchars(GSP_PANEL_DIR) . "</code></td></tr>\n";
|
||||
echo "<tr><td><strong>Recommended Website Path:</strong></td><td><code>" . htmlspecialchars(GSP_WEBSITE_DIR) . "</code></td></tr>\n";
|
||||
echo "</table>\n";
|
||||
if (!empty($apache_scan_result['issues'])) {
|
||||
echo "<p style='color:#a94442;'><strong>Apache path issues:</strong><br>" . implode('<br>', array_map('htmlspecialchars', array_unique($apache_scan_result['issues']))) . "</p>\n";
|
||||
if (!empty($apache_scan_result['stale_issues'])) {
|
||||
echo "<p style='color:#a94442;'><strong>Apache stale path issues:</strong><br>" . implode('<br>', array_map('htmlspecialchars', array_unique($apache_scan_result['stale_issues']))) . "</p>\n";
|
||||
}
|
||||
if (!empty($apache_scan_result['planned_replacements'])) {
|
||||
echo "<p><strong>Planned replacements:</strong></p><table class='center'><tr><th>Vhost</th><th>Directive</th><th>Current</th><th>Replacement</th></tr>";
|
||||
foreach ((array)$apache_scan_result['planned_replacements'] as $plan_row) {
|
||||
echo "<tr><td>" . htmlspecialchars($plan_row['vhost']) . "</td><td>" . htmlspecialchars($plan_row['directive']) . "</td><td><code>" . htmlspecialchars($plan_row['from']) . "</code></td><td><code>" . htmlspecialchars($plan_row['to']) . "</code></td></tr>";
|
||||
}
|
||||
echo "</table>";
|
||||
}
|
||||
if (!empty($apache_scan_result['ssl_issues'])) {
|
||||
echo "<p style='color:#8a6d3b;'><strong>SSL certificate issues:</strong><br>";
|
||||
foreach ((array)$apache_scan_result['ssl_issues'] as $ssl_issue) {
|
||||
echo htmlspecialchars($ssl_issue['vhost'] . ' ' . $ssl_issue['directive'] . ': ' . $ssl_issue['path'] . ' (' . $ssl_issue['reason'] . ')') . "<br>";
|
||||
}
|
||||
echo "</p>\n";
|
||||
echo "<p style='color:#8a6d3b;'><strong>Renew certificate command:</strong> <code>certbot --apache -d gameservers.world -d www.gameservers.world</code></p>";
|
||||
foreach ((array)$apache_scan_result['ssl_issues'] as $ssl_issue) {
|
||||
$vhost = basename((string)$ssl_issue['vhost']);
|
||||
if (strpos($vhost, '-ssl.conf') === false) {
|
||||
continue;
|
||||
}
|
||||
echo "<form method='POST' style='display:inline-block;margin-right:8px;'>";
|
||||
echo "<input type='hidden' name='gsp_update_action' value='disable_ssl_vhost'>";
|
||||
echo "<input type='hidden' name='gsp_update_csrf' value='" . htmlspecialchars($csrf_token) . "'>";
|
||||
echo "<input type='hidden' name='gsp_ssl_vhost' value='" . htmlspecialchars($vhost) . "'>";
|
||||
echo "<button type='submit' onclick='return confirm(\"Disable broken SSL site " . htmlspecialchars($vhost) . " in sites-enabled?\\n\\nThis keeps path fixes while SSL certs are missing.\");'>Disable Broken SSL Vhost: " . htmlspecialchars($vhost) . "</button>";
|
||||
echo "</form>";
|
||||
}
|
||||
}
|
||||
echo "<form method='POST'>\n";
|
||||
echo "<input type='hidden' name='gsp_update_action' value='fix_apache'>\n";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue