mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-07-11 15:16:08 +00:00
feat(admin): add transparent debug error-log mode
Add an admin-controlled debug mode that captures PHP errors of all players into var/log/debug-players.log, to hunt remaining PHP 8.3 bugs from real play sessions. Fully transparent to players: no redirect, no gameplay change, errors are never displayed. - DB: new debug_log table (one row), mirroring the maintenance pattern. - Database: getDebugMode()/setDebugMode()/setDebugSettings(), defensive when the table is absent (no blank page). - Session: register a custom error + shutdown handler when enabled; the handler runs even when php.ini error_reporting masks warnings/notices, so capture is complete without a Docker rebuild. Auto-disables after a configurable window. - DebugErrorLogger: size-capped file with a single .log.1 rotation, honours the @ operator, never throws. - Admin: new "Debug Error Log" page (levels, size cap, auto-off, on-page viewer, clear, download) + debugLog action mod. - Menu: admin-only quick on/off widget (TZ_DEBUG_ON/OFF, EN/FR/RO). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Catalin Novgorodschi
parent
63c94fa961
commit
827354a622
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename debugLog.php ##
|
||||
## Type : Admin action (Debug Error Log) ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## ##
|
||||
## Handles the admin actions of the Debug Error Log page: ##
|
||||
## do=save -> persist capture settings (levels, size cap, auto-off) ##
|
||||
## do=toggle -> turn the debug capture on/off ##
|
||||
## do=clear -> empty the log file(s) ##
|
||||
## do=download -> stream the log file as a download ##
|
||||
#################################################################################
|
||||
|
||||
if(!isset($_SESSION)) session_start();
|
||||
if(($_SESSION['access'] ?? 0) < 9) die("Access denied: You are not Admin!");
|
||||
|
||||
include_once("../../Database.php");
|
||||
|
||||
// Resolve project root (max 5 levels up), like the rest of the codebase.
|
||||
$autoprefix = '';
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$autoprefix = str_repeat('../', $i);
|
||||
if (file_exists($autoprefix . 'autoloader.php')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$logFile = $autoprefix . 'var/log/debug-players.log';
|
||||
|
||||
$uid = (int)($_SESSION['id_user'] ?? 0);
|
||||
$do = $_REQUEST['do'] ?? '';
|
||||
|
||||
switch ($do) {
|
||||
|
||||
case 'save':
|
||||
$database->setDebugSettings(
|
||||
isset($_POST['lvl_warning']),
|
||||
isset($_POST['lvl_notice']),
|
||||
isset($_POST['lvl_deprecated']),
|
||||
isset($_POST['lvl_fatal']),
|
||||
$_POST['max_size_mb'] ?? 5,
|
||||
$_POST['auto_off_hours'] ?? 6
|
||||
);
|
||||
$database->query("Insert into ".TB_PREFIX."admin_log values (0,".$uid.",'Changed Debug Error Log settings',".time().")");
|
||||
break;
|
||||
|
||||
case 'toggle':
|
||||
$active = (int)($_POST['active'] ?? 0);
|
||||
$database->setDebugMode($active, $uid);
|
||||
$database->query("Insert into ".TB_PREFIX."admin_log values (0,".$uid.",'".($active ? 'Enabled' : 'Disabled')." Debug Error Log',".time().")");
|
||||
break;
|
||||
|
||||
case 'clear':
|
||||
@file_put_contents($logFile, '');
|
||||
@unlink($logFile . '.1');
|
||||
$database->query("Insert into ".TB_PREFIX."admin_log values (0,".$uid.",'Cleared Debug Error Log',".time().")");
|
||||
break;
|
||||
|
||||
case 'download':
|
||||
if (is_file($logFile) && filesize($logFile) > 0) {
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
header('Content-Disposition: attachment; filename="debug-players-'.date('Ymd-His').'.log"');
|
||||
header('Content-Length: ' . filesize($logFile));
|
||||
readfile($logFile);
|
||||
} else {
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
echo "The debug log is empty.";
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
header("Location: ../../../Admin/admin.php?p=debug_log");
|
||||
exit;
|
||||
+61
-3
@@ -8878,12 +8878,70 @@ public function setMaintenance($active, $uid=0) {
|
||||
$active = (int)$active;
|
||||
$uid = (int)$uid;
|
||||
// REPLACE creează rândul dacă nu există
|
||||
return $this->query("REPLACE INTO ".TB_PREFIX."maintenance
|
||||
(id, active, started_by, started_at)
|
||||
return $this->query("REPLACE INTO ".TB_PREFIX."maintenance
|
||||
(id, active, started_by, started_at)
|
||||
VALUES (1, $active, $uid, $time)");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Debug error-log mode (admin-controlled, transparent to players).
|
||||
* Returns the single config row, falling back to safe defaults when the
|
||||
* table does not exist yet (so deploying the code before creating the table
|
||||
* never produces a blank page).
|
||||
*/
|
||||
public function getDebugMode() {
|
||||
$default = [
|
||||
'active' => 0,
|
||||
'lvl_warning' => 1,
|
||||
'lvl_notice' => 1,
|
||||
'lvl_deprecated' => 1,
|
||||
'lvl_fatal' => 1,
|
||||
'max_size_mb' => 5,
|
||||
'auto_off_hours' => 6,
|
||||
'started_by' => null,
|
||||
'started_at' => null,
|
||||
];
|
||||
try {
|
||||
$res = @mysqli_query($this->dblink, "SELECT * FROM ".TB_PREFIX."debug_log WHERE id=1 LIMIT 1");
|
||||
if (!$res) {
|
||||
return $default;
|
||||
}
|
||||
$row = mysqli_fetch_assoc($res);
|
||||
return $row ?: $default;
|
||||
} catch (\Throwable $e) {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the debug mode on/off (stamps who/when on activation).
|
||||
*/
|
||||
public function setDebugMode($active, $uid = 0) {
|
||||
$active = (int)$active;
|
||||
$uid = (int)$uid;
|
||||
$time = time();
|
||||
return $this->query("UPDATE ".TB_PREFIX."debug_log
|
||||
SET active = $active, started_by = $uid, started_at = $time
|
||||
WHERE id = 1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist the debug capture parameters (levels, size cap, auto-off window).
|
||||
*/
|
||||
public function setDebugSettings($warning, $notice, $deprecated, $fatal, $maxSizeMb, $autoOffHours) {
|
||||
$warning = $warning ? 1 : 0;
|
||||
$notice = $notice ? 1 : 0;
|
||||
$deprecated = $deprecated ? 1 : 0;
|
||||
$fatal = $fatal ? 1 : 0;
|
||||
$maxSizeMb = max(1, (int)$maxSizeMb);
|
||||
$autoOffHours = max(0, (int)$autoOffHours);
|
||||
return $this->query("UPDATE ".TB_PREFIX."debug_log
|
||||
SET lvl_warning = $warning, lvl_notice = $notice, lvl_deprecated = $deprecated,
|
||||
lvl_fatal = $fatal, max_size_mb = $maxSizeMb, auto_off_hours = $autoOffHours
|
||||
WHERE id = 1");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changed the actual capital with a new one
|
||||
*
|
||||
|
||||
@@ -1932,6 +1932,8 @@ tz_def('TZ_CONSTRUCT_WAREHOUSE', 'Construct Warehouse.');
|
||||
tz_def('TZ_CP_DAY', 'CP/day');
|
||||
tz_def('TZ_CROP_25_5_GOLD', 'Crop +25% (5 gold)');
|
||||
tz_def('TZ_DATE_AND_TIME', 'Date and time');
|
||||
tz_def('TZ_DEBUG_OFF', 'Debug log OFF');
|
||||
tz_def('TZ_DEBUG_ON', 'Debug log ON');
|
||||
tz_def('TZ_DECLARE_WAR', 'declare war');
|
||||
tz_def('TZ_DEFAULT', 'Default:');
|
||||
tz_def('TZ_DELETE_ACCOUNT', 'Delete account?');
|
||||
|
||||
@@ -1931,6 +1931,8 @@ define('TZ_CONSTRUCT_WAREHOUSE', 'Construisez un entrepôt.');
|
||||
define('TZ_CP_DAY', 'PC/jour');
|
||||
define('TZ_CROP_25_5_GOLD', 'Céréales +25% (5 or)');
|
||||
define('TZ_DATE_AND_TIME', 'Date et heure');
|
||||
define('TZ_DEBUG_OFF', 'Journal debug DÉSACTIVÉ');
|
||||
define('TZ_DEBUG_ON', 'Journal debug ACTIVÉ');
|
||||
define('TZ_DECLARE_WAR', 'déclarer la guerre');
|
||||
define('TZ_DEFAULT', 'Par défaut :');
|
||||
define('TZ_DELETE_ACCOUNT', 'Supprimer le compte ?');
|
||||
|
||||
@@ -1926,6 +1926,8 @@ define('TZ_CONSTRUCT_WAREHOUSE', 'Construiește un depozit.');
|
||||
define('TZ_CP_DAY', 'PC/zi');
|
||||
define('TZ_CROP_25_5_GOLD', 'Grâne +25% (5 aur)');
|
||||
define('TZ_DATE_AND_TIME', 'Data și ora');
|
||||
define('TZ_DEBUG_OFF', 'Jurnal debug OPRIT');
|
||||
define('TZ_DEBUG_ON', 'Jurnal debug PORNIT');
|
||||
define('TZ_DECLARE_WAR', 'declară război');
|
||||
define('TZ_DEFAULT', 'Implicit:');
|
||||
define('TZ_DELETE_ACCOUNT', 'Ștergi contul?');
|
||||
|
||||
@@ -129,6 +129,21 @@ function __construct() {
|
||||
}
|
||||
}
|
||||
|
||||
// === DEBUG ERROR LOG (admin-controlled, transparent to players) ===
|
||||
// When enabled from the admin panel, capture the selected PHP errors of
|
||||
// every player into var/log/debug-players.log. Auto-disables itself after
|
||||
// the configured window so a forgotten debug session cannot run forever.
|
||||
$dbg = $database->getDebugMode();
|
||||
if (!empty($dbg['active'])) {
|
||||
$autoOff = (int)($dbg['auto_off_hours'] ?? 0);
|
||||
if ($autoOff > 0 && !empty($dbg['started_at'])
|
||||
&& ($dbg['started_at'] + $autoOff * 3600) < $this->time) {
|
||||
$database->setDebugMode(0, $this->uid ?? 0);
|
||||
} else {
|
||||
\App\Utils\DebugErrorLogger::enable($dbg, $this->uid ?? 0, $this->username ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
$this->referrer = $_SESSION['url'] ?? "/";
|
||||
$this->url = $_SESSION['url'] = $_SERVER['PHP_SELF'];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user