diff --git a/modules/config_games/config_servers.php b/modules/config_games/config_servers.php index 9d55ebb7..0e4d15ce 100644 --- a/modules/config_games/config_servers.php +++ b/modules/config_games/config_servers.php @@ -169,6 +169,60 @@ function config_games_validate_xml_file(string $config_file): array return []; } +/** + * Script-like element names whose text content is shell/batch code. + * These nodes should be stored as CDATA sections so that characters such as + * '<', '>', '&', etc. survive round-trips through the XML parser unchanged. + */ +function config_games_script_node_names(): array +{ + return ['pre_install', 'post_install', 'pre_start', 'post_start', 'precmd', 'postcmd']; +} + +/** + * Auto-sanitize raw XML text: for every script-like element whose text content + * contains a bare '<' outside an existing CDATA block, wrap that content in a + * CDATA section so the file becomes well-formed. Non-script elements are left + * untouched. + * + * Assumptions / limitations: + * - Script elements are treated as leaf nodes (no child elements expected). + * Nested XML tags inside a script block are not supported and the regex + * will not handle them correctly. + * - The detection of an already-present CDATA section relies on the opening + * tag being immediately followed by ']*)?>(?!\s*/si', + function ($m) use ($tag) { + $attrs = $m[1]; + $content = $m[2]; + // Only wrap if the content contains a raw '<' character. XML + // entities such as < do not contain a literal '<' so they + // are not matched here and do not trigger CDATA wrapping. + if (strpos($content, '<') === false) { + return $m[0]; + } + return '<' . $tag . $attrs . '>'; + }, + $xml + ); + } + return $xml; +} + function config_games_print_editor_css() { static $printed = false; @@ -388,13 +442,19 @@ function config_games_save_xml($db, $home_cfg_id, array $nodesPayload) continue; } $hasChildren = !empty($nodeData['has_children']); + $nodeName = strtolower(($slashPos = strrpos($path, '/')) !== false ? substr($path, $slashPos + 1) : $path); + $isScriptNode = in_array($nodeName, config_games_script_node_names(), true); if (array_key_exists('value', (array)$nodeData)) { $normalizedValue = config_games_normalize_newlines($nodeData['value']); while ($domNode->firstChild) { $domNode->removeChild($domNode->firstChild); } if ($normalizedValue !== '') { - $domNode->appendChild($dom->createTextNode($normalizedValue)); + if ($isScriptNode) { + $domNode->appendChild($dom->createCDATASection($normalizedValue)); + } else { + $domNode->appendChild($dom->createTextNode($normalizedValue)); + } } } elseif (!$hasChildren) { while ($domNode->firstChild) { @@ -530,9 +590,11 @@ function exec_ogp_module() { if ($cfg_info !== FALSE) { $config_file = SERVER_CONFIG_LOCATION . $cfg_info['home_cfg_file']; $raw_content = $_POST['raw_xml_content']; + // Apply best-effort auto-fix: wrap bare '<' chars in script blocks with CDATA. + $sanitized_content = config_games_sanitize_xml_scripts($raw_content); // Write to a temp file for validation $tmp = tempnam(sys_get_temp_dir(), 'gsp_xml_'); - file_put_contents($tmp, $raw_content); + file_put_contents($tmp, $sanitized_content); $xmlErrors = config_games_validate_xml_file($tmp); @unlink($tmp); if (!empty($xmlErrors)) { @@ -542,7 +604,7 @@ function exec_ogp_module() { } echo ""; } else { - if (file_put_contents($config_file, $raw_content) !== false) { + if (file_put_contents($config_file, $sanitized_content) !== false) { print_success(get_lang('configs_updated_ok')); $config = read_server_config($config_file); if ($config !== FALSE) { diff --git a/modules/config_games/server_configs/dayz_arma2co_win32.xml b/modules/config_games/server_configs/dayz_arma2co_win32.xml index c2ad3a6b..12baa823 100644 --- a/modules/config_games/server_configs/dayz_arma2co_win32.xml +++ b/modules/config_games/server_configs/dayz_arma2co_win32.xml @@ -65,7 +65,7 @@ Make sure if you install a MOD, you list the name here or else it wont get loade - +"..\_alsoRun.pid" echo %%P' \ > _alsoRun.bat - - +]]> diff --git a/modules/config_games/server_configs/dayz_epoch_mod_win32.xml b/modules/config_games/server_configs/dayz_epoch_mod_win32.xml index b5175c72..df70c72a 100644 --- a/modules/config_games/server_configs/dayz_epoch_mod_win32.xml +++ b/modules/config_games/server_configs/dayz_epoch_mod_win32.xml @@ -65,7 +65,7 @@ Make sure if you install a MOD, you list the name here or else it wont get loade - +"..\_alsoRun.pid" echo %%P' \ > _alsoRun.bat - - +]]>