Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions installation/src/Helper/DatabaseHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,33 @@
*/
abstract class DatabaseHelper
{
/**
* The minimum database server version for MariaDB databases as required by the CMS.
* This is not necessarily equal to what the database driver requires.
*
* @var string
* @since 4.0.0
*/
protected static $dbMinimumMariaDb = '10.1';

/**
* The minimum database server version for MySQL databases as required by the CMS.
* This is not necessarily equal to what the database driver requires.
*
* @var string
* @since 4.0.0
*/
protected static $dbMinimumMySql = '5.6';

/**
* The minimum database server version for PostgreSQL databases as required by the CMS.
* This is not necessarily equal to what the database driver requires.
*
* @var string
* @since 4.0.0
*/
protected static $dbMinimumPostgreSql = '11.0';

/**
* Method to get a database driver.
*
Expand Down Expand Up @@ -109,4 +136,45 @@ public static function getEncryptionSettings($options)
'dbsslcipher' => $options->db_sslcipher,
];
}

/**
* Get the minimum required databse server version.
*
* @param DatabaseDriver $db Database object
* @param \stdClass $options The session options
*
* @return string The minimum required database server version.
*
* @since __DEPLOY_VERSION__
*/
public static function getMinimumServerVersion($db, $options)
{
// Get minimum database version required by the database driver
$minDbVersionRequired = $db->getMinimum();

// Get minimum database version required by the CMS
if (in_array($options->db_type, ['mysql', 'mysqli']))
{
if ($db->isMariaDb())
{
$minDbVersionCms = self::$dbMinimumMariaDb;
}
else
{
$minDbVersionCms = self::$dbMinimumMySql;
}
}
else
{
$minDbVersionCms = self::$dbMinimumPostgreSql;
}

// Use most restrictive, i.e. largest minimum database version requirement
if (version_compare($minDbVersionCms, $minDbVersionRequired) > 0)
{
$minDbVersionRequired = $minDbVersionCms;
}

return $minDbVersionRequired;
}
}
76 changes: 64 additions & 12 deletions installation/src/Model/DatabaseModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,6 @@ public function initialise()
* @return boolean
*
* @since 3.1
* @throws \RuntimeException
*/
public function createDatabase($options)
{
Expand Down Expand Up @@ -415,7 +414,9 @@ public function createDatabase($options)
catch (\RuntimeException $e)
{
// We did everything we could
throw new \RuntimeException(Text::_('INSTL_DATABASE_COULD_NOT_CREATE_DATABASE'), 500, $e);
Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_COULD_NOT_CREATE_DATABASE'), 'error');

return false;
}

// If we got here, the database should have been successfully created, now try one more time to get the version
Expand All @@ -426,44 +427,91 @@ public function createDatabase($options)
catch (\RuntimeException $e)
{
// We did everything we could
throw new \RuntimeException(Text::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 500, $e);
Factory::getApplication()->enqueueMessage(Text::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 'error');

return false;
}
}
elseif ($type === 'postgresql' && strpos($e->getMessage(), 'Error connecting to PGSQL database') === 42)
{
throw new \RuntimeException(Text::_('INSTL_DATABASE_COULD_NOT_CREATE_DATABASE'), 500, $e);
Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_COULD_NOT_CREATE_DATABASE'), 'error');

return false;
}
// Anything getting into this part of the conditional either doesn't support manually creating the database or isn't that type of error
else
{
throw new \RuntimeException(Text::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 500, $e);
Factory::getApplication()->enqueueMessage(Text::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 'error');

return false;
}
}

if (!$db->isMinimumVersion())
// Get required database version
$minDbVersionRequired = DatabaseHelper::getMinimumServerVersion($db, $options);

// Check minimum database version
if (version_compare($db_version, $minDbVersionRequired) < 0)
{
if (in_array($type, ['mysql', 'mysqli']) && $db->isMariaDb())
{
throw new \RuntimeException(Text::sprintf('INSTL_DATABASE_INVALID_MARIADB_VERSION', $db->getMinimum(), $db_version));
$errorMessage = Text::sprintf(
'INSTL_DATABASE_INVALID_MARIADB_VERSION',
$minDbVersionRequired,
$db_version
);
}
else
{
throw new \RuntimeException(
Text::sprintf('INSTL_DATABASE_INVALID_' . strtoupper($type) . '_VERSION', $db->getMinimum(), $db_version)
$errorMessage = Text::sprintf(
'INSTL_DATABASE_INVALID_' . strtoupper($options->db_type) . '_VERSION',
$minDbVersionRequired,
$db_version
);
}

Factory::getApplication()->enqueueMessage($errorMessage, 'error');

$db->disconnect();

return false;
}

// Check database connection encryption
if ($options->db_encryption !== 0 && empty($db->getConnectionEncryption()))
{
if ($db->isConnectionEncryptionSupported())
{
Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_ENCRYPTION_MSG_CONN_NOT_ENCRYPT'), 'error');
}
else
{
Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_ENCRYPTION_MSG_SRV_NOT_SUPPORTS'), 'error');
}

$db->disconnect();

return false;
}

// @internal Check for spaces in beginning or end of name.
if (strlen(trim($options->db_name)) <> strlen($options->db_name))
{
throw new \RuntimeException(Text::_('INSTL_DATABASE_NAME_INVALID_SPACES'));
Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_INVALID_SPACES'), 'error');

$db->disconnect();

return false;
}

// @internal Check for asc(00) Null in name.
if (strpos($options->db_name, chr(00)) !== false)
{
throw new \RuntimeException(Text::_('INSTL_DATABASE_NAME_INVALID_CHAR'));
Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_INVALID_CHAR'), 'error');

$db->disconnect();

return false;
}

// Get database's UTF support.
Expand All @@ -479,7 +527,11 @@ public function createDatabase($options)
// If the database could not be selected, attempt to create it and then select it.
if (!$this->createDb($db, $options, $utfSupport))
{
throw new \RuntimeException(Text::sprintf('INSTL_DATABASE_ERROR_CREATE', $options->db_name), 500, $e);
Factory::getApplication()->enqueueMessage(Text::sprintf('INSTL_DATABASE_ERROR_CREATE', $options->db_name), 'error');

$db->disconnect();

return false;
}

$db->select($options->db_name);
Expand Down
87 changes: 21 additions & 66 deletions installation/src/Model/SetupModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,6 @@
*/
class SetupModel extends BaseInstallationModel
{
/**
* The minimum database server version for MariaDB databases as required by the CMS.
* This is not necessarily equal to what the database driver requires.
*
* @var string
* @since 4.0.0
*/
protected static $dbMinimumMariaDb = '10.1';

/**
* The minimum database server version for MySQL databases as required by the CMS.
* This is not necessarily equal to what the database driver requires.
*
* @var string
* @since 4.0.0
*/
protected static $dbMinimumMySql = '5.6';

/**
* The minimum database server version for PostgreSQL databases as required by the CMS.
* This is not necessarily equal to what the database driver requires.
*
* @var string
* @since 4.0.0
*/
protected static $dbMinimumPostgreSql = '11.0';

/**
* Get the current setup options from the session.
*
Expand Down Expand Up @@ -549,65 +522,47 @@ public function validateDbConnection()
}
catch (\RuntimeException $e)
{
Factory::getApplication()->enqueueMessage(Text::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 'error');

return false;
}

$dbVersion = $db->getVersion();

// Get minimum database version required by the database driver
$minDbVersionRequired = $db->getMinimum();

// Get minimum database version required by the CMS
if (in_array($options->db_type, ['mysql', 'mysqli']))
{
if ($db->isMariaDb())
if ($options->db_type === 'pgsql' && strpos($e->getMessage(), 'database "' . $options->db_name . '" does not exist')
|| $options->db_type === 'mysql' && strpos($e->getMessage(), 'Unknown database \'' . $options->db_name . '\''))
{
$minDbVersionCms = self::$dbMinimumMariaDb;
// Database doesn't exist: Further checks will be done in the database installation step.
return true;
}
else
{
$minDbVersionCms = self::$dbMinimumMySql;
Factory::getApplication()->enqueueMessage(Text::sprintf('INSTL_DATABASE_COULD_NOT_CONNECT', $e->getMessage()), 'error');

return false;
}
}
else
{
$minDbVersionCms = self::$dbMinimumPostgreSql;
}

// Use most restrictive minimum database version requirement
if (version_compare($minDbVersionCms, $minDbVersionRequired) > 0)
{
$minDbVersionRequired = $minDbVersionCms;
}
$dbVersion = $db->getVersion();

// Get required database version
$minDbVersionRequired = DatabaseHelper::getMinimumServerVersion($db, $options);

// Check minimum database version
if (version_compare($dbVersion, $minDbVersionRequired) < 0)
{
if (in_array($options->db_type, ['mysql', 'mysqli']) && $db->isMariaDb())
{
Factory::getApplication()->enqueueMessage(
Text::sprintf(
'INSTL_DATABASE_INVALID_MARIADB_VERSION',
$minDbVersionRequired,
$dbVersion
),
'error'
$errorMessage = Text::sprintf(
'INSTL_DATABASE_INVALID_MARIADB_VERSION',
$minDbVersionRequired,
$dbVersion
);
}
else
{
Factory::getApplication()->enqueueMessage(
Text::sprintf(
'INSTL_DATABASE_INVALID_' . strtoupper($options->db_type) . '_VERSION',
$minDbVersionRequired,
$dbVersion
),
'error'
$errorMessage = Text::sprintf(
'INSTL_DATABASE_INVALID_' . strtoupper($options->db_type) . '_VERSION',
$minDbVersionRequired,
$dbVersion
);
}

Factory::getApplication()->enqueueMessage($errorMessage, 'error');

$db->disconnect();

return false;
Expand Down