fix: address code review feedback on config_loader and admin_config

Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/db724497-3491-4f98-a8b5-4e93bd2c8b79

Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-05-06 16:02:48 +00:00 committed by GitHub
parent 4dff8d597c
commit f1be97e0ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 17 additions and 9 deletions

View file

@ -123,8 +123,7 @@ function billing_admin_build_config(string $existingContent, array $vals): strin
$dataDirLine = ($dataDir !== '' && $dataDir !== 'auto')
? '$SITE_DATA_DIR = ' . $q($dataDir) . ';'
: '$SITE_DATA_DIR = realpath(__DIR__ . \'/..\')'
. ' . DIRECTORY_SEPARATOR . \'data\';';
: "\$SITE_DATA_DIR = realpath(__DIR__ . '/..') . DIRECTORY_SEPARATOR . 'data';";
return '<?php' . "\n"
. '###############################################' . "\n"
@ -220,7 +219,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save_
$existingContent = (string)file_get_contents($cfgPath);
$newContent = billing_admin_build_config($existingContent, $formVals);
// Backup before write
// Backup before write.
// Note: the backup copy and subsequent file_put_contents are not covered by a
// single atomic lock. This is acceptable for an admin-only operation where
// concurrent writes are not expected.
$bakName = billing_admin_create_backup($cfgPath, $bakDir);
if (!$bakName) {
$status = 'Failed to create backup. Aborting save.';
@ -268,6 +270,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save_
$status = 'Config must start with <?php';
$statusType = 'error';
} else {
// Backup then write (admin-only operation; concurrent writes are not expected).
$bakName = billing_admin_create_backup($cfgPath, $bakDir);
if (!$bakName) {
$status = 'Failed to create backup. Aborting save.';

View file

@ -14,7 +14,7 @@
* Panel-child detection:
* Walk up from modules/billing/includes/ looking for the pattern
* <ancestor>/includes/config.inc.php that contains the GSP panel DB variables
* ($db_host, $db_user, $db_name, $table_prefix). Stop after four levels.
* ($db_host, $db_user, $db_name, $table_prefix). Stop after six levels.
*
* Config sync:
* If the panel config DB variables differ from the billing config file on disk, the loader
@ -44,9 +44,11 @@ if (!function_exists('_billing_extract_db_vars_from_file')) {
}
$result = [];
foreach (['db_host', 'db_port', 'db_user', 'db_pass', 'db_name', 'table_prefix', 'db_type'] as $var) {
// Match: $varname = "value"; or $varname="value"; (single or double quotes)
if (preg_match('/^\s*\$' . preg_quote($var, '/') . '\s*=\s*["\']([^"\']*)["\']/', $content, $m, 0, 0) ||
preg_match('/\$' . preg_quote($var, '/') . '\s*=\s*["\']([^"\']*)["\']/', $content, $m)) {
// Match: $varname = "value"; or $varname="value"; (single or double quotes, no escaped quotes)
// Note: credentials containing escaped quotes or special chars are not supported by this
// regex-based extractor — use var_export() to write values and keep creds simple.
if (preg_match('/^\s*\$' . preg_quote($var, '/') . '\s*=\s*"([^"]*)"/m', $content, $m) ||
preg_match('/^\s*\$' . preg_quote($var, '/') . "\s*=\s*'([^']*)'/m", $content, $m)) {
$result[$var] = $m[1];
}
}
@ -74,9 +76,12 @@ if (!function_exists('_billing_sync_db_vars_to_file')) {
continue;
}
$newVal = $panelVars[$var];
// Match any existing assignment for this var (single or double quotes)
// Match any existing assignment for this var (double or single quotes, no escaped quotes)
// Use var_export() to produce the replacement value so special characters are handled
// correctly (var_export produces a valid PHP string literal).
$pattern = '/^(\s*\$' . preg_quote($var, '/') . '\s*=\s*)["\'][^"\']*["\'](.*)$/m';
$newLine = '${1}"' . addslashes($newVal) . '"${2}';
$exportedVal = var_export($newVal, true); // produces 'value' with proper escaping
$newLine = '${1}' . str_replace('\\', '\\\\', $exportedVal) . '${2}';
$updated = preg_replace($pattern, $newLine, $content, 1, $count);
if ($count > 0 && $updated !== $content) {
$content = (string)$updated;