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 . '>' . $tag . '>';
+ },
+ $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
-
-
+]]>