Skip to content

Commit

Permalink
Enh: Attempt to show better error messages when DB-Connection is invalid
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-rueegg committed Aug 16, 2023
1 parent 28fa6d9 commit 56e9cf4
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ HumHub Changelog

1.15.0-beta.2 (Unreleased)
--------------------------
- Enh #6512: Show error messages when DB connection configuration is invalid
- Enh #6478: Add pseudo test class to allow population of DB with standard test data
- Enh #6480: Convert assert* and db* methods to static, in line with general usage pattern
- Enh #6505: Introduce Application interface; now also fire the `onInit` event when the web application has initialized
Expand Down
8 changes: 7 additions & 1 deletion index.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*/

// comment out the following two lines when deployed to production
use humhub\libs\Helpers;

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

Expand All @@ -22,4 +24,8 @@
require(__DIR__ . '/protected/config/web.php')
);

(new humhub\components\Application($config))->run();
try {
(new humhub\components\Application($config))->run();
} catch (Throwable $ex) {
Helpers::handleConnectionErrors($ex);
}
15 changes: 12 additions & 3 deletions protected/humhub/commands/MigrateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace humhub\commands;

use humhub\components\Module;
use humhub\libs\Helpers;
use Yii;
use yii\console\Exception;
use yii\web\Application;
Expand Down Expand Up @@ -78,9 +79,17 @@ class MigrateController extends \yii\console\controllers\MigrateController
*/
public function beforeAction($action)
{
// Make sure to define default table storage engine
if (in_array(Yii::$app->db->getDriverName(), ['mysql', 'mysqli'], true)) {
Yii::$app->db->pdo->exec('SET default_storage_engine=' . Yii::$app->params['databaseDefaultStorageEngine']);
// Make sure to define a default table storage engine
$db = Yii::$app->db;

try {
$db->open();
} catch (\Throwable $ex) {
Helpers::handleConnectionErrors($ex);
}

if (in_array($db->getDriverName(), ['mysql', 'mysqli'], true)) {
$db->pdo->exec('SET default_storage_engine=' . Yii::$app->params['databaseDefaultStorageEngine']);
}
return parent::beforeAction($action);
}
Expand Down
2 changes: 1 addition & 1 deletion protected/humhub/components/console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function init()
));
}

if (BaseSettingsManager::isDatabaseInstalled()) {
if (BaseSettingsManager::isDatabaseInstalled(Yii::$app->params['databaseInstalled'] ?? false)) {
$baseUrl = Yii::$app->settings->get('baseUrl');
if (!empty($baseUrl)) {
if (Yii::getAlias('@web', false) === false) {
Expand Down
13 changes: 7 additions & 6 deletions protected/humhub/libs/BaseSettingsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -303,19 +303,20 @@ public function deleteAll($prefix = null)
/**
* Checks if settings table exists or application is not installed yet
*
* @return bool
* @since 1.3
*/
public static function isDatabaseInstalled()
public static function isDatabaseInstalled(bool $dieOnError = false): bool
{
try {
if (in_array('setting', Yii::$app->db->schema->getTableNames())) {
return true;
}
$db = Yii::$app->db;
$db->open();
} catch (\Exception $ex) {
if ($dieOnError) {
Helpers::handleConnectionErrors($ex);
}
return false;
}

return false;
return in_array('setting', $db->schema->getTableNames());
}
}
92 changes: 91 additions & 1 deletion protected/humhub/libs/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace humhub\libs;

use humhub\components\Application;
use Throwable;
use Yii;
use yii\base\InvalidArgumentException;
use yii\base\Exception;
Expand All @@ -19,7 +21,6 @@
*/
class Helpers
{

/**
* Shorten a text string
*
Expand Down Expand Up @@ -264,4 +265,93 @@ public static function SqlMode($event)
}
}

public static function handleConnectionErrors(Throwable $ex, bool $print = true, bool $die = true, bool $forcePlainText = false): ?string
{
static $last = false;

if (!$ex instanceof \yii\db\Exception) {
return null;
}

if ($last) {
return null;
}

$last = true;

$trace = debug_backtrace(0);
$trace = end($trace);
if ($trace && $trace['function'] === 'handleException' && $trace['args'][0] instanceof \yii\db\Exception) {
return null;
}

switch ($ex->getCode()) {
case 2002:
$error = 'Hostname not found.';
break;

case 1044:
$error = 'Database not found or not accessible.';
break;

case 1049:
$error = 'Database not found.';
break;

default:
$error = $ex->getMessage();
}

$dsn = Yii::$app instanceof \yii\web\Application ? '******' : Yii::$app->db->dsn;

$htmlMessage = sprintf('
<h1>Invalid database configuration</h1>
<p><strong>%s</strong></p>
', $error);

try {
$additionalInfo = json_encode([get_class($ex), ...$ex->errorInfo], JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
$additionalInfo = 'N/A';
}

while ($ex->getPrevious()) {
$ex = $ex->getPrevious();
}

$txtMessage = sprintf('
Invalid database configuration
==============================
%s
The following connection string was used:
%s
Technical information
---------------------
%s
%s
', $error, $dsn, $additionalInfo, $ex);

if ($print) {
if ($forcePlainText) {
echo $txtMessage;
} elseif (Yii::$app instanceof \yii\console\Application && Yii::$app->controller instanceof \yii\console\Controller) {
Yii::$app->controller->stderr($txtMessage);
} else {
header("HTTP/1.1 500 Internal Server Error");
echo $htmlMessage;
}
}

if (!$die) {
return $txtMessage;
}

die(1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace humhub\modules\installer\commands;

use humhub\libs\Helpers;
use Yii;
use yii\console\Controller;
use yii\console\ExitCode;
Expand Down Expand Up @@ -80,8 +81,8 @@ public function actionInstallDb()
$this->stdout("Install DB:\n\n", Console::FG_YELLOW);

$this->stdout(" * Checking Database Connection\n", Console::FG_YELLOW);
if(!$this->checkDBConnection()){
throw new Exception("Could not connect to DB!");
if (true !== $message = $this->checkDBConnection()) {
throw new Exception($message ?? "Could not connect to DB!");
}

$this->stdout(" * Installing Database\n", Console::FG_YELLOW);
Expand Down Expand Up @@ -179,17 +180,18 @@ private function setDatabaseInstalled()

/**
* Tries to open global db connection and checks result.
*
* @return true|null|string
*/
private function checkDBConnection()
{
try {
// call setActive with true to open connection.
Yii::$app->db->open();
// return the current connection state.
return Yii::$app->db->getIsActive();
return Yii::$app->db->getIsActive() ?: null;
} catch (Exception $e) {
$this->stderr($e->getMessage());
return Helpers::handleConnectionErrors($e, false, false, true);
}
return false;
}
}
8 changes: 7 additions & 1 deletion protected/yii
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* @license http://www.yiiframework.com/license/
*/

use humhub\libs\Helpers;

defined('YII_DEBUG') or define('YII_DEBUG', true);

// fcgi doesn't have STDIN and STDOUT defined by default
Expand All @@ -26,5 +28,9 @@ $config = yii\helpers\ArrayHelper::merge(
);

$application = new humhub\components\console\Application($config);
$exitCode = $application->run();
try {
$exitCode = $application->run();
} catch (\Throwable $ex) {
Helpers::handleConnectionErrors($ex);
}
exit($exitCode);

0 comments on commit 56e9cf4

Please sign in to comment.