From 5f4c62644df6d349a4093f11b190207cf981e44e Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Fri, 3 May 2024 16:00:32 +0200 Subject: [PATCH] DB/Errors * improve db error handling * web view should always result in an user friendly error if the db connection is missing or erronous * cli use should never fatal if the db connection is erronous. How are you going to fix it, d'uh. * if some CLISetup script requires a db connection check it individually --- aowow | 2 +- includes/database.class.php | 60 +++---- includes/kernel.php | 220 ++++++++++++----------- includes/shared.php | 26 --- includes/utilities.php | 4 +- index.php | 7 +- prQueue | 2 +- setup/setup.php | 3 - setup/tools/CLISetup.class.php | 4 +- setup/tools/clisetup/account.func.php | 8 + setup/tools/clisetup/build.func.php | 8 + setup/tools/clisetup/dbconfig.func.php | 20 ++- setup/tools/clisetup/setup.func.php | 6 + setup/tools/clisetup/siteconfig.func.php | 5 +- setup/tools/clisetup/sql.func.php | 8 + setup/tools/clisetup/sync.func.php | 8 + setup/tools/clisetup/update.func.php | 8 + setup/tools/dbc.class.php | 13 ++ setup/tools/filegen/realmMenu.func.php | 2 + setup/tools/sqlgen/source.func.php | 1 + template/bricks/footer.tpl.php | 2 +- 21 files changed, 230 insertions(+), 187 deletions(-) delete mode 100644 includes/shared.php diff --git a/aowow b/aowow index 5acd6a6a..050ed6a2 100755 --- a/aowow +++ b/aowow @@ -1,6 +1,6 @@ error) - die('Failed to connect to database on index #'.$idx.".\n"); - $interface->setErrorHandler(['DB', 'errorHandler']); - $interface->query('SET NAMES ?', 'utf8mb4'); if ($options['prefix']) $interface->setIdentPrefix($options['prefix']); + self::$interfaceCache[$idx] = &$interface; + + // should be caught by registered error handler + if (!$interface || !$interface->link) + return; + + $interface->query('SET NAMES ?', 'utf8mb4'); + // disable STRICT_TRANS_TABLES and STRICT_ALL_TABLES off. It prevents usage of implicit default values. // disable ONLY_FULL_GROUP_BY (Allows for non-aggregated selects in a group-by query) $extraModes = ['STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'ONLY_FULL_GROUP_BY', 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE', 'ERROR_FOR_DIVISION_BY_ZERO']; @@ -45,8 +49,6 @@ class DB if ($oldModes != $newModes) $interface->query("SET SESSION sql_mode = ?", implode(',', $newModes)); - - self::$interfaceCache[$idx] = &$interface; } public static function test(array $options, ?string &$err = '') : bool @@ -56,15 +58,14 @@ class DB if (strstr($options['host'], ':')) [$options['host'], $port] = explode(':', $options['host']); - if ($link = @mysqli_connect($options['host'], $options['user'], $options['pass'], $options['db'], $port ?: $defPort)) - mysqli_close($link); - else + if ($link = mysqli_connect($options['host'], $options['user'], $options['pass'], $options['db'], $port ?: $defPort)) { - $err = '['.mysqli_connect_errno().'] '.mysqli_connect_error(); - return false; + mysqli_close($link); + return true; } - return true; + $err = '['.mysqli_connect_errno().'] '.mysqli_connect_error(); + return false; } public static function errorHandler($message, $data) @@ -78,15 +79,17 @@ class DB // make number sensible again $data['code'] = abs($data['code']); - $error = "DB ERROR:

\n\n
".print_r($data, true)."
"; + if (defined('CFG_DEBUG') && CFG_DEBUG) + { + echo "\nDB ERROR\n"; + foreach ($data as $k => $v) + echo ' '.str_pad($k.':', 10).$v."\n"; + } - echo CLI ? strip_tags($error) : $error; - - if ($isError) - exit; + trigger_error($message, $isError ? E_USER_ERROR : E_USER_WARNING); } - public static function logger($self, $query, $trace) + public static function profiler($self, $query, $trace) { if ($trace) // actual query self::$logs[] = [substr(str_replace("\n", ' ', $query), 0, 200)]; @@ -97,7 +100,7 @@ class DB } } - public static function getLogs() + public static function getProfiles() { $out = '
';
         foreach (self::$logs as $i => [$l, $t])
@@ -122,7 +125,7 @@ class DB
 
     public static function isConnected($idx)
     {
-        return isset(self::$interfaceCache[$idx]);
+        return isset(self::$interfaceCache[$idx]) && self::$interfaceCache[$idx]->link;
     }
 
     public static function isConnectable($idx)
@@ -130,14 +133,6 @@ class DB
         return isset(self::$optionsCache[$idx]);
     }
 
-    private static function safeGetDB($idx)
-    {
-        if (!self::isConnected($idx))
-            self::connect($idx);
-
-        return self::getDB($idx);
-    }
-
     /**
      * @static
      * @return DbSimple_Mysql
@@ -147,7 +142,7 @@ class DB
         if (!isset(self::$optionsCache[DB_CHARACTERS.$realm]))
             die('Connection info not found for live database of realm #'.$realm.'. Aborted.');
 
-        return self::safeGetDB(DB_CHARACTERS.$realm);
+        return self::getDB(DB_CHARACTERS.$realm);
     }
 
     /**
@@ -156,7 +151,7 @@ class DB
      */
     public static function Auth()
     {
-        return self::safeGetDB(DB_AUTH);
+        return self::getDB(DB_AUTH);
     }
 
     /**
@@ -165,7 +160,7 @@ class DB
      */
     public static function World()
     {
-        return self::safeGetDB(DB_WORLD);
+        return self::getDB(DB_WORLD);
     }
 
     /**
@@ -174,12 +169,13 @@ class DB
      */
     public static function Aowow()
     {
-        return self::safeGetDB(DB_AOWOW);
+        return self::getDB(DB_AOWOW);
     }
 
     public static function load($idx, $config)
     {
         self::$optionsCache[$idx] = $config;
+        self::connect($idx);
     }
 }
 
diff --git a/includes/kernel.php b/includes/kernel.php
index ed74f5a2..31c21483 100644
--- a/includes/kernel.php
+++ b/includes/kernel.php
@@ -1,7 +1,25 @@
 '.implode(', ', $ext)." was not found. Please check if it should exist, using \"php -m\"\n\n";
+
+if (version_compare(PHP_VERSION, '8.0.0') < 0)
+    $error .= 'PHP Version 8.0 or higher required! Your version is '.PHP_VERSION.".\nCore functions are unavailable!\n";
+
+if ($error)
+    die(CLI ? strip_tags($error) : $error);
 
 
 if (file_exists('config/config.php'))
@@ -10,15 +28,6 @@ else
     $AoWoWconf = [];
 
 
-mb_internal_encoding('UTF-8');
-
-// OS_WIN as per compile info of php
-define('OS_WIN', substr(PHP_OS, 0, 3) == 'WIN');
-
-// WIN10 and later usually support ANSI escape sequences
-define('CLI_HAS_E', CLI && (!OS_WIN || (function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(STDOUT))));
-
-
 require_once 'includes/defines.php';
 require_once 'includes/libs/DbSimple/Generic.php';          // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master)
 require_once 'includes/utilities.php';                      // helper functions
@@ -78,6 +87,78 @@ spl_autoload_register(function ($class) {
         require_once 'pages/'.strtr($class, ['page' => '']).'.php';
 });
 
+set_error_handler(function($errNo, $errStr, $errFile, $errLine)
+{
+    // either from test function or handled separately
+    if (strstr($errStr, 'mysqli_connect') && $errNo == E_WARNING)
+        return true;
+
+    $errName = 'unknown error';                             // errors not in this list can not be handled by set_error_handler (as per documentation) or are ignored
+    $uGroup  = U_GROUP_EMPLOYEE;
+
+    if ($errNo == E_WARNING)                                // 0x0002
+        $errName = 'E_WARNING';
+    else if ($errNo == E_PARSE)                             // 0x0004
+        $errName = 'E_PARSE';
+    else if ($errNo == E_NOTICE)                            // 0x0008
+        $errName = 'E_NOTICE';
+    else if ($errNo == E_USER_ERROR)                        // 0x0100
+        $errName = 'E_USER_ERROR';
+    else if ($errNo == E_USER_WARNING)                      // 0x0200
+        $errName = 'E_USER_WARNING';
+    else if ($errNo == E_USER_NOTICE)                       // 0x0400
+    {
+        $errName = 'E_USER_NOTICE';
+        $uGroup  = U_GROUP_STAFF;
+    }
+    else if ($errNo == E_RECOVERABLE_ERROR)                 // 0x1000
+        $errName = 'E_RECOVERABLE_ERROR';
+
+    Util::addNote($uGroup, $errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine);
+    if (CLI)
+        CLI::write($errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine, $errNo & 0x40A ? CLI::LOG_WARN : CLI::LOG_ERROR);
+
+    if (DB::isConnected(DB_AOWOW))
+        DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
+            AOWOW_REVISION, $errNo, $errFile, $errLine, CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $errStr
+        );
+
+    return true;
+}, E_AOWOW);
+
+// handle exceptions
+set_exception_handler(function ($e)
+{
+    Util::addNote(U_GROUP_EMPLOYEE, 'Exception - '.$e->getMessage().' @ '.$e->getFile(). ':'.$e->getLine()."\n".$e->getTraceAsString());
+
+    if (DB::isConnected(DB_AOWOW))
+        DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
+            AOWOW_REVISION, $e->getCode(), $e->getFile(), $e->getLine(), CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $e->getMessage()
+        );
+
+    if (!CLI)
+        (new GenericPage())->error();
+    else
+        echo "\nException - ".$e->getMessage()."\n   ".$e->getFile(). '('.$e->getLine().")\n".$e->getTraceAsString()."\n\n";
+});
+
+// handle fatal errors
+register_shutdown_function(function()
+{
+    if (($e = error_get_last()) && $e['type'] & (E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR))
+    {
+        if (DB::isConnected(DB_AOWOW))
+            DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
+                AOWOW_REVISION, $e['type'], $e['file'], $e['line'], CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $e['message']
+            );
+
+        if (CLI)
+            echo "\nFatal Error - ".$e['message'].' @ '.$e['file']. ':'.$e['line']."\n\n";
+
+        // cant generate a page for web view :(
+        die();
+    }
+});
 
 // Setup DB-Wrapper
 if (!empty($AoWoWconf['aowow']['db']))
@@ -98,7 +179,7 @@ if (!empty($AoWoWconf['characters']))
 // load config to constants
 function loadConfig(bool $noPHP = false) : void
 {
-    $sets = DB::isConnectable(DB_AOWOW) ? DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, `value`, `flags` FROM ?_config') : [];
+    $sets = DB::isConnected(DB_AOWOW) ? DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, `value`, `flags` FROM ?_config') : [];
     foreach ($sets as $k => $v)
     {
         $php = $v['flags'] & CON_FLAG_PHP;
@@ -136,81 +217,14 @@ function loadConfig(bool $noPHP = false) : void
         else if (!defined('CFG_'.strtoupper($k)))
             define('CFG_'.strtoupper($k), $val);
     }
+
+    $required = ['CFG_SCREENSHOT_MIN_SIZE', 'CFG_CONTACT_EMAIL', 'CFG_NAME', 'CFG_NAME_SHORT', 'CFG_FORCE_SSL', 'CFG_DEBUG'];
+    foreach ($required as $r)
+        if (!defined($r))
+            define($r, '');
 }
 loadConfig();
 
-// handle non-fatal errors and notices
-error_reporting(!empty($AoWoWconf['aowow']) && CFG_DEBUG ? E_AOWOW : 0);
-set_error_handler(function($errNo, $errStr, $errFile, $errLine)
-{
-    $errName = 'unknown error';                             // errors not in this list can not be handled by set_error_handler (as per documentation) or are ignored
-    $uGroup  = U_GROUP_EMPLOYEE;
-
-    if ($errNo == E_WARNING)                                // 0x0002
-        $errName = 'E_WARNING';
-    else if ($errNo == E_PARSE)                             // 0x0004
-        $errName = 'E_PARSE';
-    else if ($errNo == E_NOTICE)                            // 0x0008
-        $errName = 'E_NOTICE';
-    else if ($errNo == E_USER_ERROR)                        // 0x0100
-        $errName = 'E_USER_ERROR';
-    else if ($errNo == E_USER_WARNING)                      // 0x0200
-        $errName = 'E_USER_WARNING';
-    else if ($errNo == E_USER_NOTICE)                       // 0x0400
-    {
-        $errName = 'E_USER_NOTICE';
-        $uGroup  = U_GROUP_STAFF;
-    }
-    else if ($errNo == E_RECOVERABLE_ERROR)                 // 0x1000
-        $errName = 'E_RECOVERABLE_ERROR';
-
-    Util::addNote($uGroup, $errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine);
-    if (CLI)
-        CLI::write($errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine, $errNo & 0x40A ? CLI::LOG_WARN : CLI::LOG_ERROR);
-
-    if (DB::isConnectable(DB_AOWOW))
-        DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
-            AOWOW_REVISION, $errNo, $errFile, $errLine, CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $errStr
-        );
-
-    return true;
-}, E_AOWOW);
-
-// handle exceptions
-set_exception_handler(function ($ex)
-{
-    Util::addNote(U_GROUP_EMPLOYEE, 'Exception - '.$ex->getMessage().' @ '.$ex->getFile(). ':'.$ex->getLine()."\n".$ex->getTraceAsString());
-
-    if (DB::isConnectable(DB_AOWOW))
-        DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
-            AOWOW_REVISION, $ex->getCode(), $ex->getFile(), $ex->getLine(), CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $ex->getMessage()
-        );
-
-    if (!CLI)
-        (new GenericPage())->error();
-    else
-        echo 'Exception - '.$ex->getMessage()."\n   ".$ex->getFile(). '('.$ex->getLine().")\n".$ex->getTraceAsString()."\n";
-});
-
-// handle fatal errors
-register_shutdown_function(function()
-{
-    if (($e = error_get_last()) && $e['type'] & (E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR))
-    {
-        Util::addNote(U_GROUP_EMPLOYEE, 'Fatal Error - '.$e['message'].' @ '.$e['file']. ':'.$e['line']);
-
-        if (DB::isConnectable(DB_AOWOW))
-            DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
-                AOWOW_REVISION, $e['type'], $e['file'], $e['line'], CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $e['message']
-            );
-
-        if (CLI)
-            echo 'Fatal Error - '.$e['message'].' @ '.$e['file']. ':'.$e['line']."\n";
-
-        // cant generate a page for web view :(
-        die();
-    }
-});
 
 $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($AoWoWconf['aowow']) && CFG_FORCE_SSL);
 if (defined('CFG_STATIC_HOST'))                             // points js to images & scripts
@@ -220,10 +234,15 @@ if (defined('CFG_SITE_HOST'))                               // points js to exec
     define('HOST_URL',   ($secure ? 'https://' : 'http://').CFG_SITE_HOST);
 
 
+// handle non-fatal errors and notices
+error_reporting(CFG_DEBUG ? E_AOWOW : 0);
+
+
 if (!CLI)
 {
-    if (!defined('CFG_SITE_HOST') || !defined('CFG_STATIC_HOST'))
-        die('error: SITE_HOST or STATIC_HOST not configured');
+    // not displaying the brb gnomes as static_host is missing, but eh...
+    if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD) || !defined('HOST_URL') || !defined('STATIC_URL'))
+        (new GenericPage())->maintenance();
 
     // Setup Session
     if (CFG_SESSION_CACHE_DIR && Util::writeDir(CFG_SESSION_CACHE_DIR))
@@ -234,47 +253,44 @@ if (!CLI)
     if (!session_start())
     {
         trigger_error('failed to start session', E_USER_ERROR);
-        exit;
+        (new GenericPage())->error();
     }
 
-    if (!empty($AoWoWconf['aowow']) && User::init())
+    if (User::init())
         User::save();                                       // save user-variables in session
 
     // set up some logging (~10 queries will execute before we init the user and load the config)
     if (CFG_DEBUG && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
     {
-        DB::Aowow()->setLogger(['DB', 'logger']);
-        DB::World()->setLogger(['DB', 'logger']);
+        DB::Aowow()->setLogger(['DB', 'profiler']);
+        DB::World()->setLogger(['DB', 'profiler']);
         if (DB::isConnected(DB_AUTH))
-            DB::Auth()->setLogger(['DB', 'logger']);
+            DB::Auth()->setLogger(['DB', 'profiler']);
 
         if (!empty($AoWoWconf['characters']))
             foreach ($AoWoWconf['characters'] as $idx => $__)
                 if (DB::isConnected(DB_CHARACTERS . $idx))
-                    DB::Characters($idx)->setLogger(['DB', 'logger']);
+                    DB::Characters($idx)->setLogger(['DB', 'profiler']);
     }
 
     // hard-override locale for this call (should this be here..?)
     // all strings attached..
-    if (!empty($AoWoWconf['aowow']))
+    if (isset($_GET['locale']))
     {
-        if (isset($_GET['locale']))
-        {
-            $loc = intVal($_GET['locale']);
-            if ($loc <= MAX_LOCALES && $loc >= 0 && (CFG_LOCALES & (1 << $loc)))
-                User::useLocale($loc);
-        }
-
-        Lang::load(User::$localeId);
+        $loc = intVal($_GET['locale']);
+        if ($loc <= MAX_LOCALES && $loc >= 0 && (CFG_LOCALES & (1 << $loc)))
+            User::useLocale($loc);
     }
 
+    Lang::load(User::$localeId);
+
     // parse page-parameters .. sanitize before use!
     $str = explode('&', mb_strtolower($_SERVER['QUERY_STRING'] ?? ''), 2)[0];
     $_   = explode('=', $str, 2);
     $pageCall  = $_[0];
     $pageParam = $_[1] ?? '';
 }
-else if (!empty($AoWoWconf['aowow']))
+else if (DB::isConnected(DB_AOWOW))
     Lang::load(LOCALE_EN);
 
 $AoWoWconf = null;                                          // empty auths
diff --git a/includes/shared.php b/includes/shared.php
deleted file mode 100644
index 84fb0ade..00000000
--- a/includes/shared.php
+++ /dev/null
@@ -1,26 +0,0 @@
-'.$r." was not found. Please check if it should exist, using \"php -m\"\n\n";
-
-if (version_compare(PHP_VERSION, '8.0.0') < 0)
-    $error .= 'PHP Version 8.0 or higher required! Your version is '.PHP_VERSION.".\nCore functions are unavailable!\n";
-
-if ($error)
-{
-    echo CLI ? strip_tags($error) : $error;
-    die();
-}
-
-
-// include all necessities, set up basics
-require_once 'includes/kernel.php';
-
-?>
diff --git a/includes/utilities.php b/includes/utilities.php
index 4a943faf..40141f80 100644
--- a/includes/utilities.php
+++ b/includes/utilities.php
@@ -175,14 +175,14 @@ abstract class CLI
                 $nCols = count($row);
 
             for ($j = 0; $j < $nCols - 1; $j++)             // don't pad last column
-                $pads[$j] = max($pads[$j] ?? 0, mb_strlen($row[$j]));
+                $pads[$j] = max($pads[$j] ?? 0, mb_strlen($row[$j] ?? ''));
         }
         self::write();
 
         foreach ($out as $row)
         {
             for ($i = 0; $i < $nCols - 1; $i++)             // don't pad last column
-                $row[$i] = str_pad($row[$i], $pads[$i] + 2);
+                $row[$i] = str_pad($row[$i] ?? '', $pads[$i] + 2);
 
             self::write('  '.implode($row), -1, $timestamp);
         }
diff --git a/index.php b/index.php
index c119ce0c..e570eeeb 100644
--- a/index.php
+++ b/index.php
@@ -1,16 +1,11 @@
 maintenance();
-
-
 $altClass = '';
 switch ($pageCall)
 {
diff --git a/prQueue b/prQueue
index 1d4fa298..a74bfe48 100755
--- a/prQueue
+++ b/prQueue
@@ -1,6 +1,6 @@
  false]);
             if ($dbc->error)
-            {
-                CLI::write('CLISetup::loadDBC() - required DBC '.$n.'.dbc not found!', CLI::LOG_ERROR);
                 return false;
-            }
 
             if (!$dbc->readFile())
             {
diff --git a/setup/tools/CLISetup.class.php b/setup/tools/CLISetup.class.php
index 8473e8c1..0bf06369 100644
--- a/setup/tools/CLISetup.class.php
+++ b/setup/tools/CLISetup.class.php
@@ -130,7 +130,7 @@ class CLISetup
                 self::$localeIds[] = $idx;
 
         // get site status
-        if (DB::isConnectable(DB_AOWOW))
+        if (DB::isConnected(DB_AOWOW))
             self::$lock = (int)DB::Aowow()->selectCell('SELECT `value` FROM ?_config WHERE `key` = "maintenance"');
         else
             self::$lock = self::LOCK_ON;
@@ -199,7 +199,7 @@ class CLISetup
 
     public static function siteLock(int $mode = self::LOCK_RESTORE) : void
     {
-        if (DB::isConnectable(DB_AOWOW))
+        if (DB::isConnected(DB_AOWOW))
             DB::Aowow()->query('UPDATE ?_config SET `value` = ?d WHERE `key` = "maintenance"', (int)!!($mode == self::LOCK_RESTORE ? self::$lock : $mode));
     }
 
diff --git a/setup/tools/clisetup/account.func.php b/setup/tools/clisetup/account.func.php
index defce766..c0189dc0 100644
--- a/setup/tools/clisetup/account.func.php
+++ b/setup/tools/clisetup/account.func.php
@@ -19,6 +19,14 @@ function account() : void
         'pass2' => ['Confirm Password', true ]
     );
 
+    if (!DB::isConnected(DB_AOWOW))
+    {
+        CLI::write('Database not yet set up!', CLI::LOG_WARN);
+        CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
+        CLI::write();
+        return;
+    }
+
     User::useLocale(LOCALE_EN);
     Lang::load(LOCALE_EN);
 
diff --git a/setup/tools/clisetup/build.func.php b/setup/tools/clisetup/build.func.php
index 87297309..dcfa78cb 100644
--- a/setup/tools/clisetup/build.func.php
+++ b/setup/tools/clisetup/build.func.php
@@ -13,6 +13,14 @@ if (!CLI)
 
 function build($syncMe = null) : array
 {
+    if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD))
+    {
+        CLI::write('Database not yet set up!', CLI::LOG_WARN);
+        CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
+        CLI::write();
+        return [];
+    }
+
     require_once 'setup/tools/fileGen.class.php';
 
     if(!FileGen::init($syncMe !== null ? FileGen::MODE_UPDATE : FileGen::MODE_NORMAL, $syncMe ?: []))
diff --git a/setup/tools/clisetup/dbconfig.func.php b/setup/tools/clisetup/dbconfig.func.php
index 76de2846..89817ac0 100644
--- a/setup/tools/clisetup/dbconfig.func.php
+++ b/setup/tools/clisetup/dbconfig.func.php
@@ -24,18 +24,19 @@ function dbconfig() : void
     );
     $testDB    = function($idx, $name, $dbInfo)
     {
-        $buff = '['.CLI::bold($idx).'] '.str_pad($name, 17);
+        $buff = ['['.CLI::bold($idx).']', $name];
 
         if ($dbInfo['host'])
         {
             DB::test($dbInfo, $errStr);
 
-            $buff .= $errStr ? CLI::red('ERR   ') : CLI::green('OK    ');
-            $buff .= 'mysqli://'.$dbInfo['user'].':'.str_pad('', mb_strlen($dbInfo['pass']), '*').'@'.$dbInfo['host'].'/'.$dbInfo['db'];
-            $buff .= ($dbInfo['prefix'] ? '    table prefix: '.$dbInfo['prefix'] : null).'    '.$errStr;
+            $buff[] = $errStr ? CLI::red('ERR') : CLI::green('OK');
+            $buff[] = 'mysqli://'.$dbInfo['user'].':'.($dbInfo['pass'] ? '**********' : '').'@'.$dbInfo['host'].'/'.$dbInfo['db'];
+            $buff[] = $dbInfo['prefix'] ? 'table prefix: '.$dbInfo['prefix'] : '';
+            $buff[] = $errStr;
         }
         else
-            $buff .= '      '.CLI::bold('');
+            $buff[] = CLI::bold('');
 
         return $buff;
     };
@@ -52,17 +53,18 @@ function dbconfig() : void
         CLI::write("select a numerical index to use the corresponding entry");
 
         $nCharDBs = 0;
+        $tblRows = [];
         foreach ($databases as $idx => $name)
         {
             if ($idx != 3)
-                CLI::write($testDB($idx, $name, $AoWoWconf[$name]));
+                $tblRows[] = $testDB($idx, $name, $AoWoWconf[$name]);
             else if (!empty($AoWoWconf[$name]))
                 foreach ($AoWoWconf[$name] as $charIdx => $dbInfo)
-                    CLI::write($testDB($idx + $nCharDBs++, $name.' ['.$charIdx.']', $AoWoWconf[$name][$charIdx]));
+                    $tblRows[] = $testDB($idx + $nCharDBs++, $name.' ['.$charIdx.']', $AoWoWconf[$name][$charIdx]);
         }
 
-        CLI::write("[".CLI::bold(3 + $nCharDBs)."] add an additional Character DB");
-        CLI::write();
+        $tblRows[] = ['['.CLI::bold(3 + $nCharDBs).']', 'add new character DB'];
+        CLI::writeTable($tblRows, true);
 
         while (true)
         {
diff --git a/setup/tools/clisetup/setup.func.php b/setup/tools/clisetup/setup.func.php
index 790d88ca..95c1d8c7 100644
--- a/setup/tools/clisetup/setup.func.php
+++ b/setup/tools/clisetup/setup.func.php
@@ -168,6 +168,12 @@ function setup() : void
             return false;
         };
 
+        if (!DB::isConnected(DB_AOWOW))
+        {
+            $error[] = ' * not connected to DB';
+            return false;
+        }
+
         $res   = DB::Aowow()->selectCol('SELECT `key` AS ARRAY_KEY, value FROM ?_config WHERE `key` IN ("site_host", "static_host", "force_ssl")');
         $prot  = $res['force_ssl'] ? 'https://' : 'http://';
         $cases = array(
diff --git a/setup/tools/clisetup/siteconfig.func.php b/setup/tools/clisetup/siteconfig.func.php
index 927fa457..019742ce 100644
--- a/setup/tools/clisetup/siteconfig.func.php
+++ b/setup/tools/clisetup/siteconfig.func.php
@@ -16,9 +16,10 @@ function siteconfig() : void
     $reqKeys    = ['site_host', 'static_host'];
     $updScripts = [];
 
-    if (!DB::isConnectable(DB_AOWOW))
+    if (!DB::isConnected(DB_AOWOW))
     {
-        CLI::write("database not yet set up!\n        Please use --dbconfig for setup", CLI::LOG_WARN);
+        CLI::write('Database not yet set up!', CLI::LOG_WARN);
+        CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
         CLI::write();
         return;
     }
diff --git a/setup/tools/clisetup/sql.func.php b/setup/tools/clisetup/sql.func.php
index 052f6c7c..796f1eef 100644
--- a/setup/tools/clisetup/sql.func.php
+++ b/setup/tools/clisetup/sql.func.php
@@ -13,6 +13,14 @@ if (!CLI)
 
 function sql($syncMe = null) : array
 {
+    if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD))
+    {
+        CLI::write('Database not yet set up!', CLI::LOG_WARN);
+        CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
+        CLI::write();
+        return [];
+    }
+
     require_once 'setup/tools/sqlGen.class.php';
 
     if (!SqlGen::init($syncMe !== null ? SqlGen::MODE_UPDATE : SqlGen::MODE_NORMAL, $syncMe ?: []))
diff --git a/setup/tools/clisetup/sync.func.php b/setup/tools/clisetup/sync.func.php
index 388d4c7f..5f1ff8dd 100644
--- a/setup/tools/clisetup/sync.func.php
+++ b/setup/tools/clisetup/sync.func.php
@@ -30,6 +30,14 @@ function sync(array $s = [], array $b = []) : void
         return;
     }
 
+    if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD))
+    {
+        CLI::write('Database not yet set up!', CLI::LOG_WARN);
+        CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
+        CLI::write();
+        return;
+    }
+
     $_s = sql($s);
     if ($s)
     {
diff --git a/setup/tools/clisetup/update.func.php b/setup/tools/clisetup/update.func.php
index d61d72b4..d5c757d4 100644
--- a/setup/tools/clisetup/update.func.php
+++ b/setup/tools/clisetup/update.func.php
@@ -13,6 +13,14 @@ if (!CLI)
 
 function update(?array &$sql = [], ?array &$build = []) : void
 {
+    if (!DB::isConnected(DB_AOWOW))
+    {
+        CLI::write('Database not yet set up!', CLI::LOG_WARN);
+        CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
+        CLI::write();
+        return;
+    }
+
     [$date, $part] = array_values(DB::Aowow()->selectRow('SELECT `date`, `part` FROM ?_dbversion'));
 
     if (CLISetup::getOpt('help'))
diff --git a/setup/tools/dbc.class.php b/setup/tools/dbc.class.php
index f377fdd4..9b302257 100644
--- a/setup/tools/dbc.class.php
+++ b/setup/tools/dbc.class.php
@@ -280,6 +280,14 @@ class DBC
         if (empty($this->_fields[$file]) || empty($this->_formats[$file]))
         {
             CLI::write('no structure known for '.$file.'.dbc, aborting.', CLI::LOG_ERROR);
+            CLI::write();
+            return;
+        }
+
+        if (!DB::isConnected(DB_AOWOW))
+        {
+            CLI::write('not connected to db, aborting.', CLI::LOG_ERROR);
+            CLI::write();
             return;
         }
 
@@ -291,6 +299,7 @@ class DBC
         if (count($this->fields) != strlen(str_ireplace('x', '', $this->format)))
         {
             CLI::write('known field types ['.count($this->fields).'] and names ['.strlen(str_ireplace('x', '', $this->format)).'] do not match for '.$file.'.dbc, aborting.', CLI::LOG_ERROR);
+            CLI::write();
             return;
         }
 
@@ -327,6 +336,7 @@ class DBC
         if (!$this->fileRefs)
         {
             CLI::write('no suitable files found for '.$file.'.dbc, aborting.', CLI::LOG_ERROR);
+            CLI::write();
             return;
         }
 
@@ -336,18 +346,21 @@ class DBC
         if (count($x) != 1)
         {
             CLI::write('some DBCs have differenct record counts ('.implode(', ', $x).' respectively). cannot merge!', CLI::LOG_ERROR);
+            CLI::write();
             return;
         }
         $x = array_unique(array_column($headers, 'fieldCount'));
         if (count($x) != 1)
         {
             CLI::write('some DBCs have differenct field counts ('.implode(', ', $x).' respectively). cannot merge!', CLI::LOG_ERROR);
+            CLI::write();
             return;
         }
         $x = array_unique(array_column($headers, 'recordSize'));
         if (count($x) != 1)
         {
             CLI::write('some DBCs have differenct record sizes ('.implode(', ', $x).' respectively). cannot merge!', CLI::LOG_ERROR);
+            CLI::write();
             return;
         }
 
diff --git a/setup/tools/filegen/realmMenu.func.php b/setup/tools/filegen/realmMenu.func.php
index a25bb5ac..2b13f662 100644
--- a/setup/tools/filegen/realmMenu.func.php
+++ b/setup/tools/filegen/realmMenu.func.php
@@ -62,6 +62,8 @@ if (!CLI)
         if (!$set)
             CLI::write(' - realmMenu: Auth-DB not set up .. realm menu will be empty', CLI::LOG_WARN);
 
+        Lang::load(LOCALE_EN);                              // why is this file not localized!?
+
         foreach (Util::$regions as $idx => $n)
             if ($set & (1 << $idx))
                 $menu[] = [$n, Lang::profiler('regions', $n), null, &$subs[$idx]];
diff --git a/setup/tools/sqlgen/source.func.php b/setup/tools/sqlgen/source.func.php
index ecc60002..d3fa4976 100644
--- a/setup/tools/sqlgen/source.func.php
+++ b/setup/tools/sqlgen/source.func.php
@@ -1161,6 +1161,7 @@ SqlGen::register(new class extends SetupScript
     {
         CLI::write('   * #13 cuStrings', CLI::LOG_BLANK, true, true);
 
+        Lang::load(LOCALE_EN);
         foreach (Lang::game('pvpSources') as $src => $__)
             $this->pushBuffer(Type::TITLE, $src, SRC_CUSTOM_STRING, $src);
     }
diff --git a/template/bricks/footer.tpl.php b/template/bricks/footer.tpl.php
index c1f8bf9d..77d46c58 100644
--- a/template/bricks/footer.tpl.php
+++ b/template/bricks/footer.tpl.php
@@ -36,7 +36,7 @@ endif;
 if (CFG_DEBUG && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN)):
 ?>
 
 
TimeQuery