Podcast-server/admin/system.php

235 lines
11 KiB
PHP

<?php
require_once '../includes/db.php';
require_once '../includes/functions.php';
requireRole('admin');
// --- Handle Actions ---
$successMsg = '';
$errorMsg = '';
// Delete Backup
if (isset($_POST['delete_backup'])) {
$fileToDelete = basename($_POST['file_name']);
$filePath = "backups/" . $fileToDelete;
if (file_exists($filePath)) {
unlink($filePath);
logActivity($_SESSION['admin_id'], 'BACKUP_DELETE', "Deleted backup: $fileToDelete");
$successMsg = "Backup deleted successfully.";
}
}
// --- Resource Monitoring Calculations ---
$totalSpace = disk_total_space("/");
$freeSpace = disk_free_space("/");
$usedSpace = $totalSpace - $freeSpace;
$usedPercent = round(($usedSpace / $totalSpace) * 100, 1);
function getDirSize($dir) {
$size = 0;
if (is_dir($dir)) {
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $file) {
$size += $file->getSize();
}
}
return $size;
}
$audioSize = getDirSize("../assets/uploads/audio");
$imageSize = getDirSize("../assets/uploads/images");
$podcastPercent = round(($audioSize / $totalSpace) * 100, 2);
$load = sys_getloadavg();
$cpuLoad = $load[0] * 100 / 4;
// --- Backup List ---
$backupDir = "backups";
if (!is_dir($backupDir)) mkdir($backupDir, 0755, true);
$backups = array_filter(glob($backupDir . "/*.tar.gz"), 'is_file');
// Sort by date (mtime) descending
usort($backups, function($a, $b) {
return filemtime($b) - filemtime($a);
});
// --- Activity Logs ---
$stmt = $pdo->query("SELECT * FROM activity_log ORDER BY timestamp DESC LIMIT 100");
$logs = $stmt->fetchAll();
function formatBytes($bytes, $precision = 2) {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>System Management - <?php echo getSetting($pdo, 'site_title'); ?></title>
<link rel="stylesheet" href="../assets/css/style.css">
<style>
.system-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; margin-top: 2rem; }
.gauge-container { text-align: center; margin-top: 1rem; }
.gauge-bar { background: rgba(255,255,255,0.05); height: 12px; border-radius: 6px; overflow: hidden; margin-top: 10px; }
.gauge-fill { height: 100%; transition: width 1s ease-out; }
.backup-list { width: 100%; border-collapse: collapse; margin-top: 1.5rem; }
.backup-list th, .backup-list td { padding: 1rem; text-align: left; border-bottom: 1px solid var(--glass-border); }
.status-badge { padding: 0.25rem 0.75rem; border-radius: 20px; font-size: 0.75rem; font-weight: 600; }
.log-window {
background: rgba(15, 23, 42, 0.8);
border: 1px solid var(--glass-border);
border-radius: 12px;
height: 300px;
overflow-y: scroll;
padding: 1rem;
font-family: 'Courier New', Courier, monospace;
font-size: 0.85rem;
color: #10b981;
}
.log-entry { margin-bottom: 0.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid rgba(255,255,255,0.05); }
.log-time { color: var(--text-muted); margin-right: 1rem; }
.log-action { font-weight: 600; text-transform: uppercase; margin-right: 1rem; }
</style>
</head>
<body>
<nav>
<a href="<?php echo PROJECT_ROOT_URL; ?>/" class="logo">Admin Dashboard</a>
<div class="nav-links">
<a href="dashboard.php">Episodes</a>
<a href="upload.php">Upload New</a>
<a href="settings.php">Site Settings</a>
<a href="users.php">Manage Users</a>
<a href="system.php" style="color: var(--primary-color);">System</a>
<a href="logout.php">Logout</a>
</div>
</nav>
<div class="container" style="margin-top: 3rem;">
<?php if ($successMsg): ?>
<p style="color: #10b981; margin-bottom: 2rem;"><?php echo $successMsg; ?></p>
<?php endif; ?>
<h2>System Resource Overview</h2>
<div class="system-grid">
<div class="episode-card" style="margin-bottom: 0;">
<h3>Disk Storage</h3>
<div class="gauge-container">
<div style="display: flex; justify-content: space-between; font-size: 0.9rem;">
<span>Used: <?php echo formatBytes($usedSpace); ?></span>
<span>Total: <?php echo formatBytes($totalSpace); ?></span>
</div>
<div class="gauge-bar"><div class="gauge-fill" style="width: <?php echo $usedPercent; ?>%; background: var(--primary-color);"></div></div>
<p style="margin-top: 1rem; font-size: 0.8rem; color: var(--text-muted);">Podcast Files: <?php echo formatBytes($audioSize); ?> (<?php echo $podcastPercent; ?>% of total)</p>
</div>
</div>
<div class="episode-card" style="margin-bottom: 0;">
<h3>Server Load</h3>
<div class="gauge-container">
<div style="display: flex; justify-content: space-between; font-size: 0.9rem;">
<span>CPU Load</span>
<span><?php echo round($cpuLoad, 1); ?>%</span>
</div>
<div class="gauge-bar"><div class="gauge-fill" style="width: <?php echo min(100, $cpuLoad); ?>%; background: <?php echo $cpuLoad > 80 ? '#ef4444' : '#10b981'; ?>;"></div></div>
</div>
</div>
</div>
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 4rem;">
<h2>System Backups</h2>
<form action="backup_handler.php" method="POST">
<button type="submit" name="generate_backup" class="btn btn-primary">🚀 Generate Full Backup</button>
</form>
</div>
<div class="episode-card" style="margin-top: 2rem;">
<?php if (empty($backups)): ?>
<p style="text-align: center; color: var(--text-muted); padding: 2rem;">No backups found.</p>
<?php else: ?>
<table class="backup-list">
<thead>
<tr>
<th>Backup Name</th>
<th>Date Created</th>
<th>Size</th>
<th>Type</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($backups as $file):
$name = basename($file);
$date = date("F j, Y, g:i a", filemtime($file));
$size = formatBytes(filesize($file));
$type = strpos($name, 'db') !== false ? 'Database' : (strpos($name, 'audio') !== false ? 'Audio' : 'Site');
?>
<tr>
<td style="font-family: monospace; font-size: 0.85rem;"><?php echo $name; ?></td>
<td><?php echo $date; ?></td>
<td><?php echo $size; ?></td>
<td><span class="status-badge" style="background: rgba(99,102,241,0.1); color: var(--primary-color);"><?php echo $type; ?></span></td>
<td style="display: flex; gap: 1rem;">
<a href="<?php echo $file; ?>" download style="color: var(--primary-color); text-decoration: none; font-weight: 600;">Download</a>
<form method="POST" onsubmit="return confirm('Delete this backup file?')">
<input type="hidden" name="file_name" value="<?php echo $name; ?>">
<button type="submit" name="delete_backup" style="background: none; border: none; color: #ef4444; cursor: pointer; font-weight: 600; padding: 0;">Delete</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<div style="margin-top: 4rem;">
<h2>System Activity Log</h2>
<div class="log-window">
<?php foreach ($logs as $log):
$color = (strpos($log['action'], 'FAILED') !== false || strpos($log['action'], 'UNAUTHORIZED') !== false) ? '#ef4444' : '#10b981';
?>
<div class="log-entry">
<span class="log-time">[<?php echo $log['timestamp']; ?>]</span>
<span class="log-action" style="color: <?php echo $color; ?>;"><?php echo $log['action']; ?></span>
<span class="log-user">User: <?php echo htmlspecialchars($log['username']); ?></span>
<div style="margin-left: 2rem; color: #94a3b8; margin-top: 0.25rem;">
Details: <?php echo htmlspecialchars($log['details']); ?>
<span style="font-size: 0.75rem; opacity: 0.5;">(IP: <?php echo $log['ip_address']; ?>)</span>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div style="margin-top: 4rem; padding: 3rem; background: rgba(239, 68, 68, 0.05); border: 1px solid rgba(239, 68, 68, 0.2); border-radius: 24px;">
<h2 style="color: #ef4444;">System Restoration</h2>
<p style="color: var(--text-muted); margin-top: 1rem;">Upload your backup .tar.gz files to restore the system.</p>
<form action="restore_handler.php" method="POST" enctype="multipart/form-data" style="margin-top: 2rem; display: grid; gap: 1.5rem;" onsubmit="return confirm('DANGER: This will overwrite your entire site and database. Are you absolutely sure?')">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem;">
<div class="form-group">
<label>Audio Backup (.tar.gz)</label>
<input type="file" name="backup_audio" accept=".tar.gz,.gz" required>
</div>
<div class="form-group">
<label>Database Backup (.tar.gz)</label>
<input type="file" name="backup_db" accept=".tar.gz,.gz" required>
</div>
<div class="form-group">
<label>Site Files Backup (.tar.gz)</label>
<input type="file" name="backup_site" accept=".tar.gz,.gz" required>
</div>
</div>
<button type="submit" class="btn" style="background: #ef4444; color: white;">Start System Restoration</button>
</form>
</div>
</div>
<?php include '../includes/footer.php'; ?>
</body>
</html>