Fix install + admin bugs reported in issue #169

Addresses the five bugs found on master (6e139a1b) during a fresh
Docker install and admin testing:

1. Missing `details` column in gold_fin_log (HTTP 500 on finishing
   construction with gold, buying Gold Club, admin giving gold):
   - Add `details varchar(255)` to the gold_fin_log schema, matching
     every INSERT and the a2b2.php reader that already use it.
   - Fix the broken positional INSERT in Logging::goldFinLog() (it sent
     3 values for a 7-column table) which 500'd on the same gold path.

2. Admin "View Player Info" fatal error: `<? php` -> `<?php` in
   Admin/Templates/playerinfo.tpl.

3. "Reset Server" leaving the DB corrupted (Duplicate key name
   'idx_ft_bonus_xy'): move the croppers indexes inline into the
   CREATE TABLE IF NOT EXISTS so structure recreation is idempotent,
   and add `croppers` to the reset truncate list.

4. Install wizard crash on failed DB connection (mysqli_error(false)):
   use mysqli_connect_error() and show a friendly, actionable message
   (incl. the Docker "db" hostname hint).

5. PHP exposing errors/stack traces to end users: ship a production
   php.ini baseline + docker/php/zz-travianz.ini that turns off
   display_errors and logs to stderr instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
TravianZ Patcher
2026-06-03 08:32:00 +02:00
parent 6e139a1b61
commit 7a013c38e3
7 changed files with 34 additions and 9 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
<? php <?php
################################################################################# #################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ## ## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
+1 -1
View File
@@ -41,7 +41,7 @@ if($keepAdmin){
// 2. Golim tot - fără FK checks // 2. Golim tot - fără FK checks
mysqli_query($GLOBALS["link"], "SET FOREIGN_KEY_CHECKS=0"); mysqli_query($GLOBALS["link"], "SET FOREIGN_KEY_CHECKS=0");
$tables = ["a2b","abdata","activate","active","admin_log","alidata","ali_invite","ali_log","ali_permission","allimedal","artefacts","attacks","banlist","bdata","build_log","chat","deleting","demolition","diplomacy","enforcement","farmlist","fdata","forum_cat","forum_edit","forum_post","forum_survey","forum_topic","general","gold_fin_log","hero","illegal_log","links","login_log","market","market_log","mdata","medal","movement","ndata","online","odata","password","prisoners","raidlist","research","route","send","tdata","tech_log","training","units","vdata","wdata","ww_attacks","users"]; $tables = ["a2b","abdata","activate","active","admin_log","alidata","ali_invite","ali_log","ali_permission","allimedal","artefacts","attacks","banlist","bdata","build_log","chat","deleting","demolition","diplomacy","enforcement","farmlist","fdata","forum_cat","forum_edit","forum_post","forum_survey","forum_topic","general","gold_fin_log","hero","illegal_log","links","login_log","market","market_log","mdata","medal","movement","ndata","online","odata","password","prisoners","raidlist","research","route","send","tdata","tech_log","training","units","vdata","wdata","ww_attacks","croppers","users"];
foreach($tables as $t){ foreach($tables as $t){
mysqli_query($GLOBALS["link"], "TRUNCATE TABLE `".TB_PREFIX.$t."`"); mysqli_query($GLOBALS["link"], "TRUNCATE TABLE `".TB_PREFIX.$t."`");
+5
View File
@@ -23,6 +23,11 @@ RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
# Enable Apache modules # Enable Apache modules
RUN a2enmod rewrite headers RUN a2enmod rewrite headers
# Use the production PHP configuration as a baseline, then apply our overrides
# so that errors are hidden from end users and logged server-side instead.
RUN cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/php/zz-travianz.ini "$PHP_INI_DIR/conf.d/zz-travianz.ini"
# Set working directory # Set working directory
WORKDIR /var/www/html WORKDIR /var/www/html
+10 -1
View File
@@ -462,7 +462,16 @@ class MYSQLi_DB implements IDbConnection {
$this->dbname = $dbname; $this->dbname = $dbname;
// connect to the DB // connect to the DB
if (!$this->connect()) die(mysqli_error($this->dblink)); if (!$this->connect()) {
// $this->dblink is FALSE here, so we cannot call mysqli_error() on it.
// Use mysqli_connect_error() and show a friendly, actionable message.
$error = mysqli_connect_error();
die("Database connection failed: " . htmlspecialchars(
$error !== null && $error !== ''
? $error
: 'could not connect to the database server. Please check the host, port and credentials. (When running with Docker, the database host is usually "db", not "localhost".)'
));
}
// we will operate in UTF8 // we will operate in UTF8
mysqli_query($this->dblink,"SET NAMES 'UTF8'"); mysqli_query($this->dblink,"SET NAMES 'UTF8'");
+1 -1
View File
@@ -110,7 +110,7 @@ class Logging {
$log = "Finish construction and research with gold"; $log = "Finish construction and research with gold";
list($log) = $database->escape_input($log); list($log) = $database->escape_input($log);
$q = "Insert into " . TB_PREFIX . "gold_fin_log values (0,$wid,'$log')"; $q = "INSERT INTO " . TB_PREFIX . "gold_fin_log (wid, action, time, details) VALUES ($wid, 'Finish all constructions', " . time() . ", '$log')";
$database->query($q); $database->query($q);
} }
} }
+11
View File
@@ -0,0 +1,11 @@
; TravianZ production PHP settings
; -----------------------------------------------------------------------------
; Do NOT show PHP errors, warnings or stack traces to end users. Leaking server
; paths and internal structure is both a security risk and makes the game look
; unstable. Errors are still logged server-side (visible via `docker logs`).
display_errors = Off
display_startup_errors = Off
log_errors = On
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE & ~E_WARNING
; Send the error log to the container's stderr so it shows up in `docker logs web`.
error_log = /dev/stderr
+5 -5
View File
@@ -905,6 +905,7 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%gold_fin_log` (
gold int(11) NOT NULL DEFAULT 0, gold int(11) NOT NULL DEFAULT 0,
time int(11) NOT NULL DEFAULT 0, time int(11) NOT NULL DEFAULT 0,
log varchar(255) DEFAULT NULL, log varchar(255) DEFAULT NULL,
details varchar(255) DEFAULT NULL,
PRIMARY KEY (id), PRIMARY KEY (id),
KEY uid (uid), KEY uid (uid),
KEY time (time) KEY time (time)
@@ -1776,13 +1777,12 @@ CREATE TABLE IF NOT EXISTS %PREFIX%croppers (
fieldtype TINYINT UNSIGNED NOT NULL, -- 1 = 9c, 6 = 15c fieldtype TINYINT UNSIGNED NOT NULL, -- 1 = 9c, 6 = 15c
best_oasis_bonus TINYINT UNSIGNED NOT NULL, -- 0,25,50,75,100,125,150 best_oasis_bonus TINYINT UNSIGNED NOT NULL, -- 0,25,50,75,100,125,150
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CHECK (best_oasis_bonus IN (0,25,50,75,100,125,150)) CHECK (best_oasis_bonus IN (0,25,50,75,100,125,150)),
KEY idx_ft_bonus_xy (fieldtype, best_oasis_bonus, x, y),
KEY idx_xy (x, y),
KEY idx_bonus (best_oasis_bonus)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX idx_ft_bonus_xy ON %PREFIX%croppers (fieldtype, best_oasis_bonus, x, y);
CREATE INDEX idx_xy ON %PREFIX%croppers (x, y);
CREATE INDEX idx_bonus ON %PREFIX%croppers (best_oasis_bonus);
-- --
-- Dumping data for table `%prefix%croppers` -- Dumping data for table `%prefix%croppers`
-- --