commit 802ca07cdcf56985166f3f742d07823017776453 Author: Thayol Date: Sat Aug 22 15:12:20 2026 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab13eef --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +config.php +stats.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..0cac607 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Generic Stats + +A generic stats page for PHP capable webservers. + +## Setup + +Create `config.php` based on `config.php.example`. diff --git a/config.php.example b/config.php.example new file mode 100644 index 0000000..bdbaddf --- /dev/null +++ b/config.php.example @@ -0,0 +1,23 @@ + [ + "mount_point" => "/", + "categories" => [ + "Additional Packages" => [ + "path" => "/opt", + "color" => "cornflowerblue", + ], + "User Pictures" => [ + "path" => "/home/myuser/pics", + "color" => "peachpuff", + ], + ], + ], +]; diff --git a/index.php b/index.php new file mode 100644 index 0000000..57ed8c9 --- /dev/null +++ b/index.php @@ -0,0 +1,109 @@ + 0 ? floor(log($bytes, 1024)) : 0; + $factor = min($factor, count($units) - 1); + + return sprintf("%.{$decimals}f %s", $bytes / (1024 ** $factor), $units[$factor]); +} + +if (!file_exists($stats_file)) { + $stats = [ + "storage" => $disks, + ]; + + foreach ($stats["storage"] as $disk_name => $disk_stats) { + $stats["storage"][$disk_name]["total_bytes"] = disk_total_space($disk_stats["mount_point"]); + $stats["storage"][$disk_name]["used_bytes"] = (int) trim(shell_exec('df --block-size=1 --output=used ' . escapeshellarg($disk_stats["mount_point"]) . ' | tail -1')); + $other_used = $stats["storage"][$disk_name]["used_bytes"]; + if (!isset($disk_stats["categories"])) { + $stats["storage"][$disk_name]["categories"] = []; + } + + foreach ($disk_stats["categories"] as $category_name => $category_stats) { + $stats["storage"][$disk_name]["categories"][$category_name]["bytes"] = (int) shell_exec('du -sb ' . escapeshellarg($stats["storage"][$disk_name]["categories"][$category_name]["path"]) . ' | cut -f1'); + $other_used -= $stats["storage"][$disk_name]["categories"][$category_name]["bytes"]; + } + + $stats["storage"][$disk_name]["categories"]["Other"] = [ + "color" => "white", + "bytes" => max(0, $other_used), + ]; + } + + $stats["time"] = time(); + + $stats = file_put_contents($stats_file, json_encode($stats), LOCK_EX); +} + +$stats = json_decode(file_get_contents($stats_file), true); + +if ($stats["time"] + $auto_recalculate_seconds < time()) { + header("Location: ?recalculate"); + exit(0); +} + +?> + + + + Stats + + + + + +
+
+

Storage

+ $disk_stats): ?> +

+ + + % +

+
+ $category_stats): ?> +
%; --color: ">
+ +
+
+ $category_stats): ?> +
+
">
+

+

%

+

+
+ +
+ +
+ +
+

Actions

+
+ + +
+
+ +
+ + diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..bc0b019 --- /dev/null +++ b/styles.css @@ -0,0 +1,81 @@ +* { + box-sizing: border-box; +} + +html, body { + background-color: black; + color: white; + font-family: sans-serif; + margin: 0; +} + +body { + display: flex; + align-items: center; + justify-content: center; +} + +h1, h2, h3, h4, h5, h6, p { + margin: 0; +} + +main { + min-width: min(100svw, 600px); + border: 1px solid white; + padding: 20px; + display: flex; + flex-flow: column nowrap; + gap: 10px; + + & > * { + flex: 0 0 auto; + display: flex; + flex-flow: column nowrap; + gap: 10px; + } +} + +.storage-gauge { + width: 100%; + height: 20px; + overflow: hidden; + border-radius: 10px; + background-color: grey; + display: flex; + flex-flow: row nowrap; + align-items: stretch; + + & > * { + flex: 0 0 auto; + display: inline-block; + width: var(--width); + background-color: var(--color); + } +} + +.storage-breakdown { + display: flex; + gap: 10px; + flex-flow: column nowrap; + + & > * { + flex: 0 0 auto; + display: flex; + flex-flow: row wrap; + align-items: center; + gap: 0.5em; + + & > * { + flex: 0 0 auto; + margin: 0; + } + } +} + +.storage-circle { + display: inline-block; + height: 1em; + width: 1em; + border-radius: 50%; + background-color: var(--color); +}