diff --git a/modules/config_games/config_servers.php b/modules/config_games/config_servers.php index 9d55ebb7..ee387950 100644 --- a/modules/config_games/config_servers.php +++ b/modules/config_games/config_servers.php @@ -169,6 +169,50 @@ 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. + * + * This is applied to raw XML submitted through the editor's "Raw XML" path + * before the validation step, giving a best-effort fix rather than a hard + * rejection for the most common authoring mistake. + * + * @param string $xml Raw XML string (may be malformed). + * @return string XML string with script content wrapped in CDATA where needed. + */ +function config_games_sanitize_xml_scripts(string $xml): string +{ + $tags = config_games_script_node_names(); + foreach ($tags as $tag) { + $xml = preg_replace_callback( + '/<' . preg_quote($tag, '/') . '(\s[^>]*)?>(?!\s*/si', + function ($m) use ($tag) { + $attrs = $m[1]; + $content = $m[2]; + // Only wrap if the content contains raw < that are not XML entities/tags. + if (strpos($content, '<') === false) { + return $m[0]; + } + return '<' . $tag . $attrs . '>'; + }, + $xml + ); + } + return $xml; +} + function config_games_print_editor_css() { static $printed = false; @@ -388,13 +432,19 @@ function config_games_save_xml($db, $home_cfg_id, array $nodesPayload) continue; } $hasChildren = !empty($nodeData['has_children']); + $nodeName = strtolower(substr($path, (int)strrpos($path, '/') + 1)); + $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 +580,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 +594,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 - - +]]>