diff -wruN typo3_src-8.6.0_orig/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseConnect.php typo3_src-8.6.0/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseConnect.php --- typo3_src-8.6.0_orig/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseConnect.php 2017-02-14 09:33:27.000000000 -0500 +++ typo3_src-8.6.0/typo3/sysext/install/Classes/Controller/Action/Step/DatabaseConnect.php 2017-02-18 23:50:10.698081700 -0500 @@ -40,9 +40,29 @@ $configurationManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class); $postValues = $this->postValues['values']; - $localConfigurationPathValuePairs = []; + if (isset($postValues['driver'])) { + $value = $postValues['driver']; + + $isSupported = false; + foreach($this->getSupportedDrivers() as $supportedDriver) { + if ($supportedDriver['extension'] === $value) { + $isSupported = true; + break; + } + } + if ($isSupported) { + $localConfigurationPathValuePairs['DB/Connections/Default/driver'] = $value; + } else { + /** @var $errorStatus \TYPO3\CMS\Install\Status\ErrorStatus */ + $errorStatus = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\ErrorStatus::class); + $errorStatus->setTitle('Database driver not valid'); + $errorStatus->setMessage('The driver should be supported by TYPO3 and it\'s extension enabled.'); + $result[] = $errorStatus; + } + } + if (isset($postValues['username'])) { $value = $postValues['username']; if (strlen($value) <= 50) { @@ -56,7 +76,7 @@ } } - if (isset($postValues['password'])) { + if (isset($postValues['password']) && $postValues['password'] !== '') { $value = $postValues['password']; if (strlen($value) <= 50) { $localConfigurationPathValuePairs['DB/Connections/Default/password'] = $value; @@ -67,9 +87,11 @@ $errorStatus->setMessage('Given password must be shorter than fifty characters.'); $result[] = $errorStatus; } + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/password']); } - if (isset($postValues['host'])) { + if (isset($postValues['host']) && $postValues['host'] !== '') { $value = $postValues['host']; if (preg_match('/^[a-zA-Z0-9_\\.-]+(:.+)?$/', $value) && strlen($value) <= 255) { $localConfigurationPathValuePairs['DB/Connections/Default/host'] = $value; @@ -80,9 +102,11 @@ $errorStatus->setMessage('Given host is not alphanumeric (a-z, A-Z, 0-9 or _-.:) or longer than 255 characters.'); $result[] = $errorStatus; } + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/host']); } - if (isset($postValues['port']) && $postValues['host'] !== 'localhost') { + if (isset($postValues['port']) && $postValues['port'] !== '') { $value = $postValues['port']; if (preg_match('/^[0-9]+(:.+)?$/', $value) && $value > 0 && $value <= 65535) { $localConfigurationPathValuePairs['DB/Connections/Default/port'] = (int)$value; @@ -93,6 +117,8 @@ $errorStatus->setMessage('Given port is not numeric or within range 1 to 65535.'); $result[] = $errorStatus; } + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/port']); } if (isset($postValues['socket']) && $postValues['socket'] !== '') { @@ -105,6 +131,8 @@ $errorStatus->setMessage('Given socket location does not exist on server.'); $result[] = $errorStatus; } + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/socket']); } if (isset($postValues['database'])) { @@ -120,6 +148,58 @@ } } + // Oracle : pool support + if (isset($postValues['pooled'])) { + if ($postValues['pooled'] === 'on') { + $localConfigurationPathValuePairs['DB/Connections/Default/pooled'] = true; + } else { + $localConfigurationPathValuePairs['DB/Connections/Default/pooled'] = false; + } + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/pooled']); + } + + // Oracle : check if we must set Doctrine service configuration + if (isset($postValues['oracletype']) && $postValues['oracletype'] !== '') { + $value = $postValues['oracletype']; + if ($value == "servicename") { + $localConfigurationPathValuePairs['DB/Connections/Default/service'] = true; + } else { + $localConfigurationPathValuePairs['DB/Connections/Default/service'] = false; + } + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/service']); + } + + // Oracle : SID or Service Name + // https://docs.oracle.com/database/121/NETAG/concepts.htm#NETAG253 + if (isset($postValues['servicename']) && $postValues['servicename'] !== '') { + $value = $postValues['servicename']; + // https://docs.oracle.com/cd/E11882_01/network.112/e10835/syntax.htm#NETRF175 + // @todo: [a...z] [A...Z] [0...9] _ + // The first character must be an alphanumeric character. + if (strlen($value) <= 50) { + $localConfigurationPathValuePairs['DB/Connections/Default/servicename'] = $value; + } else { + /** @var $errorStatus \TYPO3\CMS\Install\Status\ErrorStatus */ + $errorStatus = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\ErrorStatus::class); + $errorStatus->setTitle('SID or Service name not valid'); + $errorStatus->setMessage('Given SID or service name must match correct syntax.'); + $result[] = $errorStatus; + } + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/servicename']); + } + + // Oracle : Easy Connect + // https://docs.oracle.com/database/121/NETAG/naming.htm#NETAG255 + if (isset($postValues['connectstring']) && $postValues['connectstring'] !== '') { + $value = $postValues['connectstring']; + $localConfigurationPathValuePairs['DB/Connections/Default/connectstring'] = $value; + } else { + $configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/connectstring']); + } + if (!empty($localConfigurationPathValuePairs)) { $configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs); @@ -169,18 +249,58 @@ */ protected function executeAction() { + $driver = $this->getConfiguredDriver(); + $this->view + ->assign('driver', $driver) + ->assign('drivers', $this->getSupportedDrivers()) ->assign('username', $this->getConfiguredUsername()) ->assign('password', $this->getConfiguredPassword()) ->assign('host', $this->getConfiguredHost()) ->assign('port', $this->getConfiguredOrDefaultPort()) - ->assign('database', $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['dbname'] ?: '') - ->assign('socket', $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['unix_socket'] ?: '') + ->assign('database', $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['dbname'] ?: ''); + + $this->view + ->assign('renderConnectDetailsDriver', true); + + foreach ($this->getSupportedDrivers() as $driverName => $driverInfo) { + if ($driverName == 'mysql') { + $this->view + ->assign('renderConnectDetailsUsername', true) + ->assign('renderConnectDetailsPassword', true) + ->assign('renderConnectDetailsSelectMySQLType', true) + ->assign('renderConnectDetailsHost', true) + ->assign('renderConnectDetailsPort', true) + ->assign('renderConnectDetailsSocket', true) + ->assign('socket', $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['unix_socket'] ?: ''); + } else if ($driverName == 'oracle') { + $connectString = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['connectstring'] ?: ''; + $this->view ->assign('renderConnectDetailsUsername', true) ->assign('renderConnectDetailsPassword', true) + ->assign('renderConnectDetailsPooled', true) + ->assign('renderConnectDetailsSelectOracleType', true) ->assign('renderConnectDetailsHost', true) ->assign('renderConnectDetailsPort', true) - ->assign('renderConnectDetailsSocket', true); + ->assign('renderConnectDetailsServiceName', true) + ->assign('renderConnectDetailsEasyConnectString', true) + ->assign('pooled', $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['pooled'] ?: false) + ->assign('servicename', $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['servicename'] ?: '') + ->assign('connectstring', $connectString); + + $service = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['oracletype'] ?: false; + if ($service) { + $this->view->assign('oracletype', 'servicename'); + } else if ($connectString != '') { + $this->view->assign('oracletype', 'easyconnect'); + } else { + $this->view->assign('oracletype', 'sid'); + } + + + // @todo: instancename (string): Optional parameter, complete whether to add the INSTANCE_NAME parameter in the connection. It is generally used to connect to an Oracle RAC server to select the name of a particular instance. + } + } $this->assignSteps(); @@ -188,6 +308,50 @@ } /** + * Returns a list of supported database drivers, with a + * user-friendly name and any PHP module dependency. + * + * @return array + */ + protected function getSupportedDrivers() + { + $supportedDrivers = [ + 'mysql' => [ + 'label' => 'MySQL/MariaDB (mysqli)', + 'extension' => 'mysqli' + ], + 'oracle' => [ + 'label' => 'Oracle (oci8)', + 'extension' => 'oci8' + ], + ]; + + if (!extension_loaded('mysqli')) { + unset($supportedDrivers['mysql']); + } + if (!extension_loaded('oci8')) { + unset($supportedDrivers['oracle']); + } + return $supportedDrivers; + } + + /** + * Render driver + * + * @return string + */ + protected function getConfiguredOrDefaultDriver() + { + $configuredDriver = $this->getConfiguredDriver(); + if (!$configuredDriver) { + $driver = 'mysqli'; + } else { + $driver = $configuredDriver; + } + return $driver; + } + + /** * Render connect port and label * * @return int Configured or default port @@ -220,14 +386,31 @@ /** * Check LocalConfiguration.php for required database settings: + * + * For MySQL: * - 'host' is mandatory and must not be empty - * - 'port' OR 'socket' is mandatory, but may be empty + * - 'port' OR 'socket' is mandatory, but may be empty (Doctrine defaults to 3306) + * + * For Oracle, nothing is really mandatory (Doctrine will defaut to dbname as SID), but + * since the database name is not configured before testing the connection, we must either + * have: + * - SID (servicename) is mandatory if using SID (service is false) + * - 'host', 'port' and 'servicename' is mandatory if using Service Name (service is true) + * OR + * - 'connectstring' is used to configure everything with an Easy Connect syntax * * @return bool TRUE if host is set */ protected function isHostConfigured() { + if (!isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driver'])) { + return false; + } + $hostConfigured = true; + + $driver = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driver']; + if ($driver == 'mysqli') { if (empty($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['host'])) { $hostConfigured = false; } @@ -236,15 +419,41 @@ ) { $hostConfigured = false; } + } else if ($driver == 'oci8') { + // Service name + if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['service']) + && $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['service'] === true + ) { + if (empty($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['host']) + || empty($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['port']) + || empty($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['servicename']) + ) { + $hostConfigured = false; + } + // Easy Connect + } else if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['connectstring'])) { + if ($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['connectstring'] == '') { + $hostConfigured = false; + } + // SID + } else if (!isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['servicename'])) { + $hostConfigured = false; + } + } return $hostConfigured; } /** - * Check LocalConfiguration.php for required database settings: - * - 'host' is mandatory and must not be empty - * - 'port' OR 'socket' is mandatory, but may be empty + * Check LocalConfiguration.php for required database settings. + * + * For MySQL: + * - Connection must be configured * - 'username' and 'password' are mandatory, but may be empty * + * For Oracle: + * - Connection must be configured + * - 'username' is mandatory. 'password' must not be present if 'username' is '/' (host authentication) + * * @return bool TRUE if required settings are present */ protected function isConfigurationComplete() @@ -253,9 +462,17 @@ if (!isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['user'])) { $configurationComplete = false; } + + $driver = $this->getConfiguredOrDefaultDriver(); + $user = $this->getConfiguredUsername(); + if ($driver === 'mysqli' + || ($driver === 'oci8' && $user !== '/') + ) { if (!isset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['password'])) { $configurationComplete = false; } + } + return $configurationComplete; } @@ -300,11 +517,9 @@ if (!isset($localConfigurationPathValuePairs['DB/Connections/Default/unix_socket'])) { // Make sure a default port is set if not configured yet // This is independent from any host configuration - $port = $this->getConfiguredPort(); + $port = $this->getConfiguredOrDefaultPort(); if ($port > 0) { $localConfigurationPathValuePairs['DB/Connections/Default/port'] = $port; - } else { - $localConfigurationPathValuePairs['DB/Connections/Default/port'] = $this->getConfiguredOrDefaultPort(); } } @@ -379,6 +594,17 @@ } /** + * Returns configured driver. + * + * @return string + */ + protected function getConfiguredDriver() + { + $driver = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driver'] ?? ''; + return $driver; + } + + /** * Returns configured port. Gets port from host value if port is not yet set. * * @return int diff -wruN typo3_src-8.6.0_orig/typo3/sysext/install/Resources/Private/Partials/Action/Step/DatabaseConnect/ConnectDetails.html typo3_src-8.6.0/typo3/sysext/install/Resources/Private/Partials/Action/Step/DatabaseConnect/ConnectDetails.html --- typo3_src-8.6.0_orig/typo3/sysext/install/Resources/Private/Partials/Action/Step/DatabaseConnect/ConnectDetails.html 2017-02-14 09:33:27.000000000 -0500 +++ typo3_src-8.6.0/typo3/sysext/install/Resources/Private/Partials/Action/Step/DatabaseConnect/ConnectDetails.html 2017-02-18 23:49:21.817194100 -0500 @@ -5,6 +5,18 @@ + +
+ +
+ +
+
+
@@ -21,7 +33,7 @@
- +
@@ -31,6 +43,28 @@
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
@@ -54,6 +88,24 @@
+ +
+ + +
+ + +
+
+
+ +
+ +
+ +
+
+