diff --git a/installation/src/Helper/DatabaseHelper.php b/installation/src/Helper/DatabaseHelper.php index ee82efd3ca0f4..049ff96ee02b4 100644 --- a/installation/src/Helper/DatabaseHelper.php +++ b/installation/src/Helper/DatabaseHelper.php @@ -10,6 +10,12 @@ defined('_JEXEC') or die; +use Joomla\CMS\Factory; +use Joomla\CMS\Filesystem\File; +use Joomla\CMS\Filesystem\Folder; +use Joomla\CMS\Filesystem\Path; +use Joomla\CMS\Language\Text; +use Joomla\CMS\User\UserHelper; use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseInterface; @@ -177,4 +183,379 @@ public static function getMinimumServerVersion($db, $options) return $minDbVersionRequired; } + + /** + * Validate and clean up database connection parameters. + * + * @param \stdClass $options The session options + * + * @return string|boolean A string with the translated error message if + * validation error, otherwise false. + * + * @since 4.0.0 + */ + public static function validateConnectionParameters($options) + { + // Ensure a database type was selected. + if (empty($options->db_type)) + { + return Text::_('INSTL_DATABASE_INVALID_TYPE'); + } + + // Ensure that a hostname and user name were input. + if (empty($options->db_host) || empty($options->db_user)) + { + return Text::_('INSTL_DATABASE_INVALID_DB_DETAILS'); + } + + // Ensure that a database name is given. + if (empty($options->db_name)) + { + return Text::_('INSTL_DATABASE_EMPTY_NAME'); + } + + // Validate length of database name. + if (strlen($options->db_name) > 64) + { + return Text::_('INSTL_DATABASE_NAME_TOO_LONG'); + } + + // Validate database table prefix. + if (empty($options->db_prefix) || !preg_match('#^[a-zA-Z]+[a-zA-Z0-9_]*$#', $options->db_prefix)) + { + return Text::_('INSTL_DATABASE_PREFIX_MSG'); + } + + // Validate length of database table prefix. + if (strlen($options->db_prefix) > 15) + { + return Text::_('INSTL_DATABASE_FIX_TOO_LONG'); + } + + // Validate database name. + if (in_array($options->db_type, ['pgsql', 'postgresql']) && !preg_match('#^[a-zA-Z_][0-9a-zA-Z_$]*$#', $options->db_name)) + { + return Text::_('INSTL_DATABASE_NAME_MSG_POSTGRESQL'); + } + + if (in_array($options->db_type, ['mysql', 'mysqli']) && preg_match('#[\\\\\/\.]#', $options->db_name)) + { + return Text::_('INSTL_DATABASE_NAME_MSG_MYSQL'); + } + + // Workaround for UPPERCASE table prefix for postgresql + if (in_array($options->db_type, ['pgsql', 'postgresql'])) + { + if (strtolower($options->db_prefix) != $options->db_prefix) + { + return Text::_('INSTL_DATABASE_FIX_LOWERCASE'); + } + } + + // Validate and clean up database connection encryption options + $optionsChanged = false; + + if ($options->db_encryption === 0) + { + // Reset unused options + if (!empty($options->db_sslkey)) + { + $options->db_sslkey = ''; + $optionsChanged = true; + } + + if (!empty($options->db_sslcert)) + { + $options->db_sslcert = ''; + $optionsChanged = true; + } + + if ($options->db_sslverifyservercert) + { + $options->db_sslverifyservercert = false; + $optionsChanged = true; + } + + if (!empty($options->db_sslca)) + { + $options->db_sslca = ''; + $optionsChanged = true; + } + + if (!empty($options->db_sslcipher)) + { + $options->db_sslcipher = ''; + $optionsChanged = true; + } + } + else + { + // Check localhost + if (strtolower($options->db_host) === 'localhost') + { + return Text::_('INSTL_DATABASE_ENCRYPTION_MSG_LOCALHOST'); + } + + // Check CA file and folder depending on database type if server certificate verification + if ($options->db_sslverifyservercert) + { + if (empty($options->db_sslca)) + { + return Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_EMPTY', Text::_('INSTL_DATABASE_ENCRYPTION_CA_LABEL')); + } + + if (!File::exists(Path::clean($options->db_sslca))) + { + return Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_BAD', Text::_('INSTL_DATABASE_ENCRYPTION_CA_LABEL')); + } + } + else + { + // Reset unused option + if (!empty($options->db_sslca)) + { + $options->db_sslca = ''; + $optionsChanged = true; + } + } + + // Check key and certificate if two-way encryption + if ($options->db_encryption === 2) + { + if (empty($options->db_sslkey)) + { + return Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_EMPTY', Text::_('INSTL_DATABASE_ENCRYPTION_KEY_LABEL')); + } + + if (!File::exists(Path::clean($options->db_sslkey))) + { + return Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_BAD', Text::_('INSTL_DATABASE_ENCRYPTION_KEY_LABEL')); + } + + if (empty($options->db_sslcert)) + { + return Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_EMPTY', Text::_('INSTL_DATABASE_ENCRYPTION_CERT_LABEL')); + } + + if (!File::exists(Path::clean($options->db_sslcert))) + { + return Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_BAD', Text::_('INSTL_DATABASE_ENCRYPTION_CERT_LABEL')); + } + } + else + { + // Reset unused options + if (!empty($options->db_sslkey)) + { + $options->db_sslkey = ''; + $optionsChanged = true; + } + + if (!empty($options->db_sslcert)) + { + $options->db_sslcert = ''; + $optionsChanged = true; + } + } + } + + // Save options to session data if changed + if ($optionsChanged) + { + $optsArr = ArrayHelper::fromObject($options); + Factory::getSession()->set('setup.options', $optsArr); + } + + return false; + } + + /** + * Security check for remote db hosts + * + * @param \stdClass $options The session options + * + * @return boolean True if passed, otherwise false. + * + * @since 4.0.0 + */ + public static function checkRemoteDbHost($options) + { + // Security check for remote db hosts: Check env var if disabled + $shouldCheckLocalhost = getenv('JOOMLA_INSTALLATION_DISABLE_LOCALHOST_CHECK') !== '1'; + + // Per Default allowed DB Hosts + $localhost = array( + 'localhost', + '127.0.0.1', + '::1', + ); + + // Check the security file if the db_host is not localhost / 127.0.0.1 / ::1 + if ($shouldCheckLocalhost && !in_array($options->db_host, $localhost)) + { + $remoteDbFileTestsPassed = Factory::getSession()->get('remoteDbFileTestsPassed', false); + + // When all checks have been passed we don't need to do this here again. + if ($remoteDbFileTestsPassed === false) + { + $generalRemoteDatabaseMessage = Text::sprintf( + 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_GENERAL_MESSAGE', + 'https://docs.joomla.org/Special:MyLanguage/J3.x:Secured_procedure_for_installing_Joomla_with_a_remote_database' + ); + + $remoteDbFile = Factory::getSession()->get('remoteDbFile', false); + + if ($remoteDbFile === false) + { + // Add the general message + Factory::getApplication()->enqueueMessage($generalRemoteDatabaseMessage, 'warning'); + + // This is the file you need to remove if you want to use a remote database + $remoteDbFile = '_Joomla' . UserHelper::genRandomPassword(21) . '.txt'; + Factory::getSession()->set('remoteDbFile', $remoteDbFile); + + // Get the path + $remoteDbPath = JPATH_INSTALLATION . '/' . $remoteDbFile; + + // When the path is not writable the user needs to create the file manually + if (!File::write($remoteDbPath, '')) + { + // Request to create the file manually + Factory::getApplication()->enqueueMessage( + Text::sprintf( + 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_CREATE_FILE', + $remoteDbFile, + 'installation', + Text::_('INSTL_INSTALL_JOOMLA') + ), + 'notice' + ); + + Factory::getSession()->set('remoteDbFileUnwritable', true); + + return false; + } + + // Save the file name to the session + Factory::getSession()->set('remoteDbFileWrittenByJoomla', true); + + // Request to delete that file + Factory::getApplication()->enqueueMessage( + Text::sprintf( + 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_DELETE_FILE', + $remoteDbFile, + 'installation', + Text::_('INSTL_INSTALL_JOOMLA') + ), + 'notice' + ); + + return false; + } + + if (Factory::getSession()->get('remoteDbFileWrittenByJoomla', false) === true + && File::exists(JPATH_INSTALLATION . '/' . $remoteDbFile)) + { + // Add the general message + Factory::getApplication()->enqueueMessage($generalRemoteDatabaseMessage, 'warning'); + + // Request to delete the file + Factory::getApplication()->enqueueMessage( + Text::sprintf( + 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_DELETE_FILE', + $remoteDbFile, + 'installation', + Text::_('INSTL_INSTALL_JOOMLA') + ), + 'notice' + ); + + return false; + } + + if (Factory::getSession()->get('remoteDbFileUnwritable', false) === true && !File::exists(JPATH_INSTALLATION . '/' . $remoteDbFile)) + { + // Add the general message + Factory::getApplication()->enqueueMessage($generalRemoteDatabaseMessage, 'warning'); + + // Request to create the file manually + Factory::getApplication()->enqueueMessage( + Text::sprintf( + 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_CREATE_FILE', + $remoteDbFile, + 'installation', + Text::_('INSTL_INSTALL_JOOMLA') + ), + 'notice' + ); + + return false; + } + + // All tests for this session passed set it to the session + Factory::getSession()->set('remoteDbFileTestsPassed', true); + } + } + + return true; + } + + /** + * Check database server parameters after connection + * + * @param DatabaseDriver $db Database object + * @param \stdClass $options The session options + * + * @return string|boolean A string with the translated error message if + * some server parameter is not ok, otherwise false. + * + * @since 4.0.0 + */ + public static function checkDbServerParameters($db, $options) + { + $dbVersion = $db->getVersion(); + + // Get required database version + $minDbVersionRequired = self::getMinimumServerVersion($db, $options); + + // Check minimum database version + if (version_compare($dbVersion, $minDbVersionRequired) < 0) + { + if (in_array($options->db_type, ['mysql', 'mysqli']) && $db->isMariaDb()) + { + $errorMessage = Text::sprintf( + 'INSTL_DATABASE_INVALID_MARIADB_VERSION', + $minDbVersionRequired, + $dbVersion + ); + } + else + { + $errorMessage = Text::sprintf( + 'INSTL_DATABASE_INVALID_' . strtoupper($options->db_type) . '_VERSION', + $minDbVersionRequired, + $dbVersion + ); + } + + return $errorMessage; + } + + // Check database connection encryption + if ($options->db_encryption !== 0 && empty($db->getConnectionEncryption())) + { + if ($db->isConnectionEncryptionSupported()) + { + $errorMessage = Text::_('INSTL_DATABASE_ENCRYPTION_MSG_CONN_NOT_ENCRYPT'); + } + else + { + $errorMessage = Text::_('INSTL_DATABASE_ENCRYPTION_MSG_SRV_NOT_SUPPORTS'); + } + + return $errorMessage; + } + + return false; + } } diff --git a/installation/src/Model/DatabaseModel.php b/installation/src/Model/DatabaseModel.php index 4a1b9f285b1ce..93d2c282d23b2 100644 --- a/installation/src/Model/DatabaseModel.php +++ b/installation/src/Model/DatabaseModel.php @@ -12,14 +12,11 @@ defined('_JEXEC') or die; use Joomla\CMS\Factory; -use Joomla\CMS\Filesystem\File; -use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Installation\Helper\DatabaseHelper; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Language\LanguageHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Object\CMSObject; -use Joomla\CMS\User\UserHelper; use Joomla\CMS\Version; use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseInterface; @@ -75,189 +72,23 @@ public function initialise($select = true) $lang->load('joomla', JPATH_ADMINISTRATOR, 'en-GB', true); } - // Ensure a database type was selected. - if (empty($options->db_type)) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_INVALID_TYPE'), 'warning'); - - return false; - } - - // Ensure that a hostname and user name were input. - if (empty($options->db_host) || empty($options->db_user)) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_INVALID_DB_DETAILS'), 'warning'); - - return false; - } - - // Validate database table prefix. - if (isset($options->db_prefix) && !preg_match('#^[a-zA-Z]+[a-zA-Z0-9_]*$#', $options->db_prefix)) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_PREFIX_MSG'), 'warning'); - - return false; - } - - // Validate length of database table prefix. - if (isset($options->db_prefix) && strlen($options->db_prefix) > 15) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_FIX_TOO_LONG'), 'warning'); - - return false; - } - - // Validate length of database name. - if (strlen($options->db_name) > 64) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_TOO_LONG'), 'warning'); + // Validate and clean up connection parameters + $paramsCheck = DatabaseHelper::validateConnectionParameters($options); - return false; - } - - // Validate database name. - if (in_array($options->db_type, ['pgsql', 'postgresql'], true) && !preg_match('#^[a-zA-Z_][0-9a-zA-Z_$]*$#', $options->db_name)) + if ($paramsCheck) { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_MSG_POSTGRESQL'), 'warning'); + Factory::getApplication()->enqueueMessage($paramsCheck, 'warning'); return false; } - if (in_array($options->db_type, ['mysql', 'mysqli']) && preg_match('#[\\\\\/\.]#', $options->db_name)) + // Security check for remote db hosts + if (!DatabaseHelper::checkRemoteDbHost($options)) { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_MSG_MYSQL'), 'warning'); - + // Messages have been enqueued in the called function. return false; } - // Workaround for UPPERCASE table prefix for PostgreSQL - if (in_array($options->db_type, ['pgsql', 'postgresql'])) - { - if (isset($options->db_prefix) && strtolower($options->db_prefix) !== $options->db_prefix) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_FIX_LOWERCASE'), 'warning'); - - return false; - } - } - - // Security check for remote db hosts: Check env var if disabled - $shouldCheckLocalhost = getenv('JOOMLA_INSTALLATION_DISABLE_LOCALHOST_CHECK') !== '1'; - - // Per Default allowed DB Hosts - $localhost = array( - 'localhost', - '127.0.0.1', - '::1', - ); - - // Check the security file if the db_host is not localhost / 127.0.0.1 / ::1 - if ($shouldCheckLocalhost && !in_array($options->db_host, $localhost)) - { - $remoteDbFileTestsPassed = Factory::getSession()->get('remoteDbFileTestsPassed', false); - - // When all checks have been passed we don't need to do this here again. - if ($remoteDbFileTestsPassed === false) - { - $generalRemoteDatabaseMessage = Text::sprintf( - 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_GENERAL_MESSAGE', - 'https://docs.joomla.org/Special:MyLanguage/J3.x:Secured_procedure_for_installing_Joomla_with_a_remote_database' - ); - - $remoteDbFile = Factory::getSession()->get('remoteDbFile', false); - - if ($remoteDbFile === false) - { - // Add the general message - Factory::getApplication()->enqueueMessage($generalRemoteDatabaseMessage, 'warning'); - - // This is the file you need to remove if you want to use a remote database - $remoteDbFile = '_Joomla' . UserHelper::genRandomPassword(21) . '.txt'; - Factory::getSession()->set('remoteDbFile', $remoteDbFile); - - // Get the path - $remoteDbPath = JPATH_INSTALLATION . '/' . $remoteDbFile; - - // When the path is not writable the user needs to create the file manually - if (!File::write($remoteDbPath, '')) - { - // Request to create the file manually - Factory::getApplication()->enqueueMessage( - Text::sprintf( - 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_CREATE_FILE', - $remoteDbFile, - 'installation', - Text::_('INSTL_INSTALL_JOOMLA') - ), - 'notice' - ); - - Factory::getSession()->set('remoteDbFileUnwritable', true); - - return false; - } - - // Save the file name to the session - Factory::getSession()->set('remoteDbFileWrittenByJoomla', true); - - // Request to delete that file - Factory::getApplication()->enqueueMessage( - Text::sprintf( - 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_DELETE_FILE', - $remoteDbFile, - 'installation', - Text::_('INSTL_INSTALL_JOOMLA') - ), - 'notice' - ); - - return false; - } - - if (Factory::getSession()->get('remoteDbFileWrittenByJoomla', false) === true - && File::exists(JPATH_INSTALLATION . '/' . $remoteDbFile)) - { - // Add the general message - Factory::getApplication()->enqueueMessage($generalRemoteDatabaseMessage, 'warning'); - - // Request to delete the file - Factory::getApplication()->enqueueMessage( - Text::sprintf( - 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_DELETE_FILE', - $remoteDbFile, - 'installation', - Text::_('INSTL_INSTALL_JOOMLA') - ), - 'notice' - ); - - return false; - } - - if (Factory::getSession()->get('remoteDbFileUnwritable', false) === true && !File::exists(JPATH_INSTALLATION . '/' . $remoteDbFile)) - { - // Add the general message - Factory::getApplication()->enqueueMessage($generalRemoteDatabaseMessage, 'warning'); - - // Request to create the file manually - Factory::getApplication()->enqueueMessage( - Text::sprintf( - 'INSTL_DATABASE_HOST_IS_NOT_LOCALHOST_CREATE_FILE', - $remoteDbFile, - 'installation', - Text::_('INSTL_INSTALL_JOOMLA') - ), - 'notice' - ); - - return false; - } - - // All tests for this session passed set it to the session - Factory::getSession()->set('remoteDbFileTestsPassed', true); - } - } - // Get a database object. try { @@ -354,6 +185,15 @@ public function createDatabase() $altDB = DatabaseDriver::getInstance($altDBoptions); + // Check database server parameters + $dbServerCheck = DatabaseHelper::checkDbServerParameters($altDB, $options); + + if ($dbServerCheck) + { + // Some server parameter is not ok + throw new \RuntimeException($dbServerCheck, 500, $e); + } + // Try to create the database now using the alternate driver try { @@ -383,45 +223,13 @@ public function createDatabase() } } - // Get required database version - $minDbVersionRequired = DatabaseHelper::getMinimumServerVersion($db, $options); + // Check database server parameters + $dbServerCheck = DatabaseHelper::checkDbServerParameters($db, $options); - // Check minimum database version - if (version_compare($db_version, $minDbVersionRequired) < 0) + if ($dbServerCheck) { - if (in_array($type, ['mysql', 'mysqli']) && $db->isMariaDb()) - { - throw new \RuntimeException( - Text::sprintf( - 'INSTL_DATABASE_INVALID_MARIADB_VERSION', - $minDbVersionRequired, - $db_version - ) - ); - } - else - { - throw new \RuntimeException( - Text::sprintf( - 'INSTL_DATABASE_INVALID_' . strtoupper($type) . '_VERSION', - $minDbVersionRequired, - $db_version - ) - ); - } - } - - // Check database connection encryption - if ($options->db_encryption !== 0 && empty($db->getConnectionEncryption())) - { - if ($db->isConnectionEncryptionSupported()) - { - throw new \RuntimeException(Text::_('INSTL_DATABASE_ENCRYPTION_MSG_CONN_NOT_ENCRYPT')); - } - else - { - throw new \RuntimeException(Text::_('INSTL_DATABASE_ENCRYPTION_MSG_SRV_NOT_SUPPORTS')); - } + // Some server parameter is not ok + throw new \RuntimeException($dbServerCheck, 500, $e); } // @internal Check for spaces in beginning or end of name. diff --git a/installation/src/Model/SetupModel.php b/installation/src/Model/SetupModel.php index b67cdeeadd0a1..7d2b237c9e5f8 100644 --- a/installation/src/Model/SetupModel.php +++ b/installation/src/Model/SetupModel.php @@ -12,9 +12,6 @@ defined('_JEXEC') or die; use Joomla\CMS\Factory; -use Joomla\CMS\Filesystem\File; -use Joomla\CMS\Filesystem\Folder; -use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\Form; use Joomla\CMS\Installation\Helper\DatabaseHelper; use Joomla\CMS\Language\LanguageHelper; @@ -272,8 +269,6 @@ public function validateDbConnection() $lang = Factory::getLanguage(); $currentLang = $lang->getTag(); - $optionsChanged = false; - // Load the selected language if (LanguageHelper::exists($currentLang, JPATH_ADMINISTRATOR)) { @@ -285,225 +280,24 @@ public function validateDbConnection() $lang->load('joomla', JPATH_ADMINISTRATOR, 'en-GB', true); } - // Ensure a database type was selected. - if (empty($options->db_type)) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_INVALID_TYPE'), 'error'); - - return false; - } - - // Ensure that a hostname and user name were input. - if (empty($options->db_host) || empty($options->db_user)) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_INVALID_DB_DETAILS'), 'error'); - - return false; - } - - // Ensure that a database name was input. - if (empty($options->db_name)) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_EMPTY_NAME'), 'error'); - - return false; - } - - // Validate database table prefix. - if (!preg_match('#^[a-zA-Z]+[a-zA-Z0-9_]*$#', $options->db_prefix)) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_PREFIX_MSG'), 'error'); - - return false; - } - - // Validate length of database table prefix. - if (strlen($options->db_prefix) > 15) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_FIX_TOO_LONG'), 'error'); - - return false; - } - - // Validate length of database name. - if (strlen($options->db_name) > 64) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_TOO_LONG'), 'error'); - - return false; - } + // Validate and clean up connection parameters + $paramsCheck = DatabaseHelper::validateConnectionParameters($options); - // Validate database name. - if (in_array($options->db_type, ['pgsql', 'postgresql']) && !preg_match('#^[a-zA-Z_][0-9a-zA-Z_$]*$#', $options->db_name)) + if ($paramsCheck) { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_MSG_POSTGRESQL'), 'error'); + // Validation error: Enqueue the error message + Factory::getApplication()->enqueueMessage($paramsCheck, 'error'); return false; } - if (in_array($options->db_type, ['mysql', 'mysqli']) && preg_match('#[\\\\\/\.]#', $options->db_name)) + // Security check for remote db hosts + if (!DatabaseHelper::checkRemoteDbHost($options)) { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_NAME_MSG_MYSQL'), 'error'); - + // Messages have been enqueued in the called function. return false; } - // Workaround for UPPERCASE table prefix for postgresql - if (in_array($options->db_type, ['pgsql', 'postgresql'])) - { - if (strtolower($options->db_prefix) != $options->db_prefix) - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_FIX_LOWERCASE'), 'error'); - - return false; - } - } - - // Validate database connection encryption options - if ($options->db_encryption === 0) - { - // Reset unused options - if (!empty($options->db_sslkey)) - { - $options->db_sslkey = ''; - $optionsChanged = true; - } - - if (!empty($options->db_sslcert)) - { - $options->db_sslcert = ''; - $optionsChanged = true; - } - - if ($options->db_sslverifyservercert) - { - $options->db_sslverifyservercert = false; - $optionsChanged = true; - } - - if (!empty($options->db_sslca)) - { - $options->db_sslca = ''; - $optionsChanged = true; - } - - if (!empty($options->db_sslcipher)) - { - $options->db_sslcipher = ''; - $optionsChanged = true; - } - } - else - { - // Check localhost - if (strtolower($options->db_host) === 'localhost') - { - Factory::getApplication()->enqueueMessage(Text::_('INSTL_DATABASE_ENCRYPTION_MSG_LOCALHOST'), 'error'); - - return false; - } - - // Check CA file and folder depending on database type if server certificate verification - if ($options->db_sslverifyservercert) - { - if (empty($options->db_sslca)) - { - Factory::getApplication()->enqueueMessage( - Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_EMPTY', Text::_('INSTL_DATABASE_ENCRYPTION_CA_LABEL')), - 'error' - ); - - return false; - } - - if (!File::exists(Path::clean($options->db_sslca))) - { - Factory::getApplication()->enqueueMessage( - Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_BAD', Text::_('INSTL_DATABASE_ENCRYPTION_CA_LABEL')), - 'error' - ); - - return false; - } - } - else - { - // Reset unused option - if (!empty($options->db_sslca)) - { - $options->db_sslca = ''; - $optionsChanged = true; - } - } - - // Check key and certificate if two-way encryption - if ($options->db_encryption === 2) - { - if (empty($options->db_sslkey)) - { - Factory::getApplication()->enqueueMessage( - Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_EMPTY', Text::_('INSTL_DATABASE_ENCRYPTION_KEY_LABEL')), - 'error' - ); - - return false; - } - - if (!File::exists(Path::clean($options->db_sslkey))) - { - Factory::getApplication()->enqueueMessage( - Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_BAD', Text::_('INSTL_DATABASE_ENCRYPTION_KEY_LABEL')), - 'error' - ); - - return false; - } - - if (empty($options->db_sslcert)) - { - Factory::getApplication()->enqueueMessage( - Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_EMPTY', Text::_('INSTL_DATABASE_ENCRYPTION_CERT_LABEL')), - 'error' - ); - - return false; - } - - if (!File::exists(Path::clean($options->db_sslcert))) - { - Factory::getApplication()->enqueueMessage( - Text::sprintf('INSTL_DATABASE_ENCRYPTION_MSG_FILE_FIELD_BAD', Text::_('INSTL_DATABASE_ENCRYPTION_CERT_LABEL')), - 'error' - ); - - return false; - } - } - else - { - // Reset unused options - if (!empty($options->db_sslkey)) - { - $options->db_sslkey = ''; - $optionsChanged = true; - } - - if (!empty($options->db_sslcert)) - { - $options->db_sslcert = ''; - $optionsChanged = true; - } - } - } - - // Save options to session data if changed - if ($optionsChanged) - { - $session = Factory::getSession(); - $optsArr = ArrayHelper::fromObject($options); - $session->set('setup.options', $optsArr); - } - // Get a database object. try { @@ -534,51 +328,13 @@ public function validateDbConnection() return false; } - $dbVersion = $db->getVersion(); + // Check database server parameters + $dbServerCheck = DatabaseHelper::checkDbServerParameters($db, $options); - // Get required database version - $minDbVersionRequired = DatabaseHelper::getMinimumServerVersion($db, $options); - - // Check minimum database version - if (version_compare($dbVersion, $minDbVersionRequired) < 0) + if ($dbServerCheck) { - if (in_array($options->db_type, ['mysql', 'mysqli']) && $db->isMariaDb()) - { - $errorMessage = Text::sprintf( - 'INSTL_DATABASE_INVALID_MARIADB_VERSION', - $minDbVersionRequired, - $dbVersion - ); - } - else - { - $errorMessage = Text::sprintf( - 'INSTL_DATABASE_INVALID_' . strtoupper($options->db_type) . '_VERSION', - $minDbVersionRequired, - $dbVersion - ); - } - - 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(); + // Some server parameter is not ok: Enqueue the error message + Factory::getApplication()->enqueueMessage($dbServerCheck, 'error'); return false; }