fix menu
This commit is contained in:
parent
21696b36c5
commit
43f911dc93
4 changed files with 196 additions and 13 deletions
|
|
@ -26,6 +26,7 @@ function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
|
||||||
<a class="gsw-btn" href="./invoices.php">Invoice History</a>
|
<a class="gsw-btn" href="./invoices.php">Invoice History</a>
|
||||||
<a class="gsw-btn" href="admin_coupons.php">Manage Coupons</a>
|
<a class="gsw-btn" href="admin_coupons.php">Manage Coupons</a>
|
||||||
<a class="gsw-btn" href="admin_config.php">Edit Site Config</a>
|
<a class="gsw-btn" href="admin_config.php">Edit Site Config</a>
|
||||||
|
<a class="gsw-btn" href="admin_xml_editor.php">XML Config Editor</a>
|
||||||
<a class="gsw-btn" href="docs/xml_notes.php">XML Config Guide</a>
|
<a class="gsw-btn" href="docs/xml_notes.php">XML Config Guide</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
161
modules/billing/admin_xml_editor.php
Normal file
161
modules/billing/admin_xml_editor.php
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
<?php
|
||||||
|
require_once(__DIR__ . '/includes/admin_auth.php');
|
||||||
|
require_once(__DIR__ . '/includes/config_loader.php');
|
||||||
|
include(__DIR__ . '/includes/top.php');
|
||||||
|
include(__DIR__ . '/includes/menu.php');
|
||||||
|
|
||||||
|
$serverConfigDir = realpath(__DIR__ . '/../config_games/server_configs');
|
||||||
|
if ($serverConfigDir === false || !is_dir($serverConfigDir)) {
|
||||||
|
die('Server config directory not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$availableFiles = [];
|
||||||
|
$directoryIterator = new DirectoryIterator($serverConfigDir);
|
||||||
|
foreach ($directoryIterator as $fileInfo) {
|
||||||
|
if ($fileInfo->isFile() && strtolower($fileInfo->getExtension()) === 'xml') {
|
||||||
|
$availableFiles[] = $fileInfo->getFilename();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort($availableFiles, SORT_NATURAL | SORT_FLAG_CASE);
|
||||||
|
|
||||||
|
$selectedFile = '';
|
||||||
|
$fileContents = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$postedFile = $_POST['file'] ?? '';
|
||||||
|
$postedFile = basename(trim((string)$postedFile));
|
||||||
|
if ($postedFile === '' || !in_array($postedFile, $availableFiles, true)) {
|
||||||
|
$errors[] = 'Invalid file selected.';
|
||||||
|
} else {
|
||||||
|
$fullPath = $serverConfigDir . DIRECTORY_SEPARATOR . $postedFile;
|
||||||
|
if (!is_file($fullPath) || !is_readable($fullPath)) {
|
||||||
|
$errors[] = 'Selected file is missing or unreadable.';
|
||||||
|
} elseif (!is_writable($fullPath)) {
|
||||||
|
$errors[] = 'Selected file is not writable.';
|
||||||
|
} else {
|
||||||
|
$newContents = $_POST['xml_contents'] ?? '';
|
||||||
|
$backupDir = $serverConfigDir . DIRECTORY_SEPARATOR . '_backups';
|
||||||
|
if (!is_dir($backupDir)) {
|
||||||
|
@mkdir($backupDir, 0775, true);
|
||||||
|
}
|
||||||
|
$timestamp = date('Ymd-His');
|
||||||
|
$backupPath = $backupDir . DIRECTORY_SEPARATOR . $postedFile . '.' . $timestamp . '.bak';
|
||||||
|
$original = file_get_contents($fullPath);
|
||||||
|
if ($original === false) {
|
||||||
|
$errors[] = 'Unable to read original file for backup.';
|
||||||
|
} elseif (@file_put_contents($backupPath, $original) === false) {
|
||||||
|
$errors[] = 'Failed to create backup copy before saving.';
|
||||||
|
} elseif (@file_put_contents($fullPath, $newContents) === false) {
|
||||||
|
$errors[] = 'Failed to write new XML contents.';
|
||||||
|
} else {
|
||||||
|
$messages[] = 'Saved changes to ' . htmlspecialchars($postedFile, ENT_QUOTES, 'UTF-8') . ' (backup: ' . basename($backupPath) . ').';
|
||||||
|
$selectedFile = $postedFile;
|
||||||
|
$fileContents = $newContents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($selectedFile === '') {
|
||||||
|
$queryFile = $_GET['file'] ?? '';
|
||||||
|
$queryFile = basename(trim((string)$queryFile));
|
||||||
|
if ($queryFile !== '' && in_array($queryFile, $availableFiles, true)) {
|
||||||
|
$selectedFile = $queryFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($selectedFile !== '' && $fileContents === '') {
|
||||||
|
$fullPath = $serverConfigDir . DIRECTORY_SEPARATOR . $selectedFile;
|
||||||
|
if (is_file($fullPath) && is_readable($fullPath)) {
|
||||||
|
$fileContents = file_get_contents($fullPath);
|
||||||
|
if ($fileContents === false) {
|
||||||
|
$errors[] = 'Unable to read the selected file.';
|
||||||
|
$fileContents = '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Selected file is missing or unreadable.';
|
||||||
|
$selectedFile = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function billing_render_flash(array $items, string $cssClass): void {
|
||||||
|
if (!$items) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
echo '<div class="panel ' . $cssClass . '" style="margin-bottom:12px">';
|
||||||
|
foreach ($items as $item) {
|
||||||
|
echo '<div>' . $item . '</div>';
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Admin — XML Config Editor</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="css/header.css">
|
||||||
|
<style>
|
||||||
|
.editor-wrapper { max-width: 1100px; margin: 30px auto; background: rgba(0,0,0,0.6); padding: 24px; border-radius: 10px; }
|
||||||
|
.editor-wrapper h1 { margin-top: 0; color: #fff; }
|
||||||
|
.editor-layout { display: flex; flex-wrap: wrap; gap: 20px; }
|
||||||
|
.file-list { flex: 1 1 240px; max-height: 520px; overflow-y: auto; background: rgba(0,0,0,0.35); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; padding: 16px; }
|
||||||
|
.file-list h2 { margin-top: 0; font-size: 1rem; color: #a5b4fc; }
|
||||||
|
.file-list a { display: block; color: #7fb3ff; text-decoration: none; padding: 6px 4px; border-radius: 6px; }
|
||||||
|
.file-list a:hover { background: rgba(102, 126, 234, 0.25); }
|
||||||
|
.file-list a.active { background: rgba(102, 126, 234, 0.45); color: #fff; }
|
||||||
|
.editor-form { flex: 3 1 500px; }
|
||||||
|
textarea { width: 100%; min-height: 480px; font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; font-size: 14px; line-height: 1.4; padding: 12px; color: #e5e7eb; background: rgba(15, 23, 42, 0.85); border: 1px solid rgba(148, 163, 184, 0.4); border-radius: 8px; }
|
||||||
|
textarea:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.35); }
|
||||||
|
.editor-actions { margin-top: 16px; display: flex; gap: 12px; align-items: center; }
|
||||||
|
.editor-actions button { padding: 10px 18px; border: none; border-radius: 6px; background: #667eea; color: #fff; font-weight: 600; cursor: pointer; }
|
||||||
|
.editor-actions button:hover { background: #5563d6; }
|
||||||
|
.hint { color: #cbd5f5; font-size: 0.85rem; }
|
||||||
|
.panel.error div { color: #f87171; }
|
||||||
|
.panel.success div { color: #34d399; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="editor-wrapper">
|
||||||
|
<h1>XML Config Editor</h1>
|
||||||
|
<p class="hint">Editing files in <code><?php echo htmlspecialchars($serverConfigDir, ENT_QUOTES, 'UTF-8'); ?></code>. Each save creates a backup under <code>_backups/</code>.</p>
|
||||||
|
|
||||||
|
<?php billing_render_flash($messages, 'success'); ?>
|
||||||
|
<?php billing_render_flash($errors, 'error'); ?>
|
||||||
|
|
||||||
|
<div class="editor-layout">
|
||||||
|
<div class="file-list">
|
||||||
|
<h2>Server Config XML Files</h2>
|
||||||
|
<?php if (!$availableFiles): ?>
|
||||||
|
<p style="color:#e5e7eb;">No XML files found.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($availableFiles as $fileName): ?>
|
||||||
|
<?php $isActive = ($fileName === $selectedFile); ?>
|
||||||
|
<a href="admin_xml_editor.php?file=<?php echo urlencode($fileName); ?>" class="<?php echo $isActive ? 'active' : ''; ?>"><?php echo htmlspecialchars($fileName, ENT_QUOTES, 'UTF-8'); ?></a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="editor-form">
|
||||||
|
<?php if ($selectedFile === ''): ?>
|
||||||
|
<p style="color:#e5e7eb;">Select an XML file from the list to begin editing.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<form method="post" action="admin_xml_editor.php">
|
||||||
|
<input type="hidden" name="file" value="<?php echo htmlspecialchars($selectedFile, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<textarea name="xml_contents" spellcheck="false"><?php echo htmlspecialchars($fileContents, ENT_QUOTES, 'UTF-8'); ?></textarea>
|
||||||
|
<div class="editor-actions">
|
||||||
|
<button type="submit">Save Changes</button>
|
||||||
|
<span class="hint">Backup created before each save.</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php include(__DIR__ . '/includes/footer.php'); ?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -6,6 +6,27 @@
|
||||||
|
|
||||||
require_once(__DIR__ . '/session_bridge.php');
|
require_once(__DIR__ . '/session_bridge.php');
|
||||||
|
|
||||||
|
if (!function_exists('billing_nav_escape')) {
|
||||||
|
function billing_nav_escape($value) {
|
||||||
|
return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nav_prefix = '';
|
||||||
|
$scriptName = $_SERVER['SCRIPT_NAME'] ?? '';
|
||||||
|
if (is_string($scriptName) && $scriptName !== '') {
|
||||||
|
if (preg_match('#/modules/billing/(.*)$#', $scriptName, $match)) {
|
||||||
|
$subPath = $match[1];
|
||||||
|
if ($subPath !== '') {
|
||||||
|
$depth = substr_count($subPath, '/');
|
||||||
|
if ($depth > 0) {
|
||||||
|
$nav_prefix = str_repeat('../', $depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$nav_prefix = $nav_prefix ?: '';
|
||||||
|
|
||||||
// Check login status
|
// Check login status
|
||||||
// Primary check uses website_user_id, but some remote deployments may only set website_username.
|
// Primary check uses website_user_id, but some remote deployments may only set website_username.
|
||||||
// Treat presence of website_username as a fallback to consider the user logged in for UI purposes.
|
// Treat presence of website_username as a fallback to consider the user logged in for UI purposes.
|
||||||
|
|
@ -63,7 +84,7 @@ if ($is_logged_in) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<link rel="stylesheet" href="css/header.css">
|
<link rel="stylesheet" href="<?php echo billing_nav_escape($nav_prefix . 'css/header.css'); ?>">
|
||||||
|
|
||||||
<!-- site wrapper for scoping styles -->
|
<!-- site wrapper for scoping styles -->
|
||||||
<div id="gsw-site">
|
<div id="gsw-site">
|
||||||
|
|
@ -71,8 +92,8 @@ if ($is_logged_in) {
|
||||||
<div class="gsw-header">
|
<div class="gsw-header">
|
||||||
<div class="gsw-header-top">
|
<div class="gsw-header-top">
|
||||||
<div class="gsw-header-left">
|
<div class="gsw-header-left">
|
||||||
<a href="index.php" class="gsw-logo-link">
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'index.php'); ?>" class="gsw-logo-link">
|
||||||
<img src="images/logo-sm.png" alt="GameServers.World" class="gsw-logo">
|
<img src="<?php echo billing_nav_escape($nav_prefix . 'images/logo-sm.png'); ?>" alt="GameServers.World" class="gsw-logo">
|
||||||
<span class="gsw-site-name">GameServers.World</span>
|
<span class="gsw-site-name">GameServers.World</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -84,23 +105,23 @@ if ($is_logged_in) {
|
||||||
$return_to_param = $current;
|
$return_to_param = $current;
|
||||||
?>
|
?>
|
||||||
<?php if ($is_logged_in): ?>
|
<?php if ($is_logged_in): ?>
|
||||||
<a href="my_account.php" class="gsw-user-info">Welcome, <?php echo $username; ?></a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'my_account.php'); ?>" class="gsw-user-info">Welcome, <?php echo $username; ?></a>
|
||||||
<a href="logout.php?return_to=<?php echo urlencode($return_to_param); ?>" class="gsw-header-btn">Logout</a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'logout.php?return_to=' . urlencode($return_to_param)); ?>" class="gsw-header-btn">Logout</a>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a href="login.php?return_to=<?php echo urlencode($return_to_param); ?>" class="gsw-header-btn">Login</a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'login.php?return_to=' . urlencode($return_to_param)); ?>" class="gsw-header-btn">Login</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gsw-header-bottom">
|
<div class="gsw-header-bottom">
|
||||||
<nav class="gsw-header-nav">
|
<nav class="gsw-header-nav">
|
||||||
<a href="index.php" class="gsw-nav-link">Home</a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'index.php'); ?>" class="gsw-nav-link">Home</a>
|
||||||
<a href="serverlist.php" class="gsw-nav-link">Game Servers</a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'serverlist.php'); ?>" class="gsw-nav-link">Game Servers</a>
|
||||||
<a href="docs.php" class="gsw-nav-link">Documentation</a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'docs.php'); ?>" class="gsw-nav-link">Documentation</a>
|
||||||
<?php if ($is_logged_in): ?>
|
<?php if ($is_logged_in): ?>
|
||||||
<!-- My Account as a regular nav link, not a prominent button -->
|
<!-- My Account as a regular nav link, not a prominent button -->
|
||||||
<a href="my_account.php" class="gsw-nav-link">My Account</a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'my_account.php'); ?>" class="gsw-nav-link">My Account</a>
|
||||||
<a href="cart.php" class="gsw-nav-link">Cart
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'cart.php'); ?>" class="gsw-nav-link">Cart
|
||||||
<?php
|
<?php
|
||||||
$cart_count = 0;
|
$cart_count = 0;
|
||||||
if (file_exists(__DIR__ . '/cart_helper.php')) {
|
if (file_exists(__DIR__ . '/cart_helper.php')) {
|
||||||
|
|
@ -112,7 +133,7 @@ if ($is_logged_in) {
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ($is_logged_in && $is_admin): ?>
|
<?php if ($is_logged_in && $is_admin): ?>
|
||||||
<a href="admin.php" class="gsw-nav-link">Admin</a>
|
<a href="<?php echo billing_nav_escape($nav_prefix . 'admin.php'); ?>" class="gsw-nav-link">Admin</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<a href="http://panel.iaregamer.com" class="gsw-nav-link" target="_blank">Control Panel</a>
|
<a href="http://panel.iaregamer.com" class="gsw-nav-link" target="_blank">Control Panel</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Last Updated at 3:15pm on 2025-12-05
|
Last Updated at 11:40am on 2025-06-12
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue