TYPO3  7.6
DatabaseConnect.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Install\Controller\Action\Step;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 
27 {
35  public function execute()
36  {
37  $result = array();
38 
40  $configurationManager = $this->objectManager->get(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
41 
42  $postValues = $this->postValues['values'];
43  if (isset($postValues['loadDbal'])) {
44  $result[] = $this->executeLoadDbalExtension();
45  } elseif ($postValues['unloadDbal']) {
46  $result[] = $this->executeUnloadDbalExtension();
47  } elseif ($postValues['setDbalDriver']) {
48  $driver = $postValues['setDbalDriver'];
49  switch ($driver) {
50  case 'mssql':
51  case 'odbc_mssql':
52  $driverConfig = array(
53  'useNameQuote' => true,
54  'quoteClob' => false,
55  );
56  break;
57  case 'oci8':
58  $driverConfig = array(
59  'driverOptions' => array(
60  'connectSID' => '',
61  ),
62  );
63  break;
64  }
65  $config = array(
66  '_DEFAULT' => array(
67  'type' => 'adodb',
68  'config' => array(
69  'driver' => $driver,
70  )
71  )
72  );
73  if (isset($driverConfig)) {
74  $config['_DEFAULT']['config'] = array_merge($config['_DEFAULT']['config'], $driverConfig);
75  }
76  $configurationManager->setLocalConfigurationValueByPath('EXTCONF/dbal/handlerCfg', $config);
77  } else {
78  $localConfigurationPathValuePairs = array();
79 
80  if ($this->isDbalEnabled()) {
81  $config = $configurationManager->getConfigurationValueByPath('EXTCONF/dbal/handlerCfg');
82  $driver = $config['_DEFAULT']['config']['driver'];
83  if ($driver === 'oci8') {
84  $config['_DEFAULT']['config']['driverOptions']['connectSID'] = ($postValues['type'] === 'sid');
85  $localConfigurationPathValuePairs['EXTCONF/dbal/handlerCfg'] = $config;
86  }
87  }
88 
89  if (isset($postValues['username'])) {
90  $value = $postValues['username'];
91  if (strlen($value) <= 50) {
92  $localConfigurationPathValuePairs['DB/username'] = $value;
93  } else {
95  $errorStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
96  $errorStatus->setTitle('Database username not valid');
97  $errorStatus->setMessage('Given username must be shorter than fifty characters.');
98  $result[] = $errorStatus;
99  }
100  }
101 
102  if (isset($postValues['password'])) {
103  $value = $postValues['password'];
104  if (strlen($value) <= 50) {
105  $localConfigurationPathValuePairs['DB/password'] = $value;
106  } else {
108  $errorStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
109  $errorStatus->setTitle('Database password not valid');
110  $errorStatus->setMessage('Given password must be shorter than fifty characters.');
111  $result[] = $errorStatus;
112  }
113  }
114 
115  if (isset($postValues['host'])) {
116  $value = $postValues['host'];
117  if (preg_match('/^[a-zA-Z0-9_\\.-]+(:.+)?$/', $value) && strlen($value) <= 50) {
118  $localConfigurationPathValuePairs['DB/host'] = $value;
119  } else {
121  $errorStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
122  $errorStatus->setTitle('Database host not valid');
123  $errorStatus->setMessage('Given host is not alphanumeric (a-z, A-Z, 0-9 or _-.:) or longer than fifty characters.');
124  $result[] = $errorStatus;
125  }
126  }
127 
128  if (isset($postValues['port']) && $postValues['host'] !== 'localhost') {
129  $value = $postValues['port'];
130  if (preg_match('/^[0-9]+(:.+)?$/', $value) && $value > 0 && $value <= 65535) {
131  $localConfigurationPathValuePairs['DB/port'] = (int)$value;
132  } else {
134  $errorStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
135  $errorStatus->setTitle('Database port not valid');
136  $errorStatus->setMessage('Given port is not numeric or within range 1 to 65535.');
137  $result[] = $errorStatus;
138  }
139  }
140 
141  if (isset($postValues['socket']) && $postValues['socket'] !== '') {
142  if (@file_exists($postValues['socket'])) {
143  $localConfigurationPathValuePairs['DB/socket'] = $postValues['socket'];
144  } else {
146  $errorStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
147  $errorStatus->setTitle('Socket does not exist');
148  $errorStatus->setMessage('Given socket location does not exist on server.');
149  $result[] = $errorStatus;
150  }
151  }
152 
153  if (isset($postValues['database'])) {
154  $value = $postValues['database'];
155  if (strlen($value) <= 50) {
156  $localConfigurationPathValuePairs['DB/database'] = $value;
157  } else {
159  $errorStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
160  $errorStatus->setTitle('Database name not valid');
161  $errorStatus->setMessage('Given database name must be shorter than fifty characters.');
162  $result[] = $errorStatus;
163  }
164  }
165 
166  if (!empty($localConfigurationPathValuePairs)) {
167  $configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs);
168 
169  // After setting new credentials, test again and create an error message if connect is not successful
170  // @TODO: This could be simplified, if isConnectSuccessful could be released from TYPO3_CONF_VARS
171  // and fed with connect values directly in order to obsolete the bootstrap reload.
172  \TYPO3\CMS\Core\Core\Bootstrap::getInstance()
173  ->populateLocalConfiguration()
174  ->disableCoreCache();
175  if ($this->isDbalEnabled()) {
176  require(ExtensionManagementUtility::extPath('dbal') . 'ext_localconf.php');
177  \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
178  }
179  if (!$this->isConnectSuccessful()) {
181  $errorStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\ErrorStatus::class);
182  $errorStatus->setTitle('Database connect not successful');
183  $errorStatus->setMessage('Connecting to the database with given settings failed. Please check.');
184  $result[] = $errorStatus;
185  }
186  }
187  }
188 
189  return $result;
190  }
191 
198  public function needsExecution()
199  {
200  if ($this->isConnectSuccessful() && $this->isConfigurationComplete()) {
201  return false;
202  }
203  if (!$this->isHostConfigured() && !$this->isDbalEnabled()) {
204  $this->useDefaultValuesForNotConfiguredOptions();
205  throw new \TYPO3\CMS\Install\Controller\Exception\RedirectException(
206  'Wrote default settings to LocalConfiguration.php, redirect needed',
207  1377611168
208  );
209  }
210  return true;
211  }
212 
218  protected function executeAction()
219  {
220  $isDbalEnabled = $this->isDbalEnabled();
221  $this->view
222  ->assign('isDbalEnabled', $isDbalEnabled)
223  ->assign('username', $this->getConfiguredUsername())
224  ->assign('password', $this->getConfiguredPassword())
225  ->assign('host', $this->getConfiguredHost())
226  ->assign('port', $this->getConfiguredOrDefaultPort())
227  ->assign('database', $GLOBALS['TYPO3_CONF_VARS']['DB']['database'] ?: '')
228  ->assign('socket', $GLOBALS['TYPO3_CONF_VARS']['DB']['socket'] ?: '');
229 
230  if ($isDbalEnabled) {
231  $this->view->assign('selectedDbalDriver', $this->getSelectedDbalDriver());
232  $this->view->assign('dbalDrivers', $this->getAvailableDbalDrivers());
234  } else {
235  $this->view
236  ->assign('renderConnectDetailsUsername', true)
237  ->assign('renderConnectDetailsPassword', true)
238  ->assign('renderConnectDetailsHost', true)
239  ->assign('renderConnectDetailsPort', true)
240  ->assign('renderConnectDetailsSocket', true);
241  }
242  $this->assignSteps();
243 
244  return $this->view->render();
245  }
246 
252  protected function getConfiguredOrDefaultPort()
253  {
254  $configuredPort = (int)$this->getConfiguredPort();
255  if (!$configuredPort) {
256  if ($this->isDbalEnabled()) {
257  $driver = $this->getSelectedDbalDriver();
258  switch ($driver) {
259  case 'postgres':
260  $port = 5432;
261  break;
262  case 'mssql':
263  case 'odbc_mssql':
264  $port = 1433;
265  break;
266  case 'oci8':
267  $port = 1521;
268  break;
269  default:
270  $port = 3306;
271  }
272  } else {
273  $port = 3306;
274  }
275  } else {
276  $port = $configuredPort;
277  }
278  return $port;
279  }
280 
286  protected function isConnectSuccessful()
287  {
289  $databaseConnection = $this->objectManager->get(\TYPO3\CMS\Core\Database\DatabaseConnection::class);
290 
291  if ($this->isDbalEnabled()) {
292  // Set additional connect information based on dbal driver. postgres for example needs
293  // database name already for connect.
294  if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['database'])) {
295  $databaseConnection->setDatabaseName($GLOBALS['TYPO3_CONF_VARS']['DB']['database']);
296  }
297  }
298 
299  $databaseConnection->setDatabaseUsername($this->getConfiguredUsername());
300  $databaseConnection->setDatabasePassword($this->getConfiguredPassword());
301  $databaseConnection->setDatabaseHost($this->getConfiguredHost());
302  $databaseConnection->setDatabasePort($this->getConfiguredPort());
303  $databaseConnection->setDatabaseSocket($this->getConfiguredSocket());
304 
305  $databaseConnection->initialize();
306 
307  return (bool)@$databaseConnection->sql_pconnect();
308  }
309 
317  protected function isHostConfigured()
318  {
319  $hostConfigured = true;
320  if (empty($GLOBALS['TYPO3_CONF_VARS']['DB']['host'])) {
321  $hostConfigured = false;
322  }
323  if (
324  !isset($GLOBALS['TYPO3_CONF_VARS']['DB']['port'])
325  && !isset($GLOBALS['TYPO3_CONF_VARS']['DB']['socket'])
326  ) {
327  $hostConfigured = false;
328  }
329  return $hostConfigured;
330  }
331 
340  protected function isConfigurationComplete()
341  {
342  $configurationComplete = $this->isHostConfigured();
343  if (!isset($GLOBALS['TYPO3_CONF_VARS']['DB']['username'])) {
344  $configurationComplete = false;
345  }
346  if (!isset($GLOBALS['TYPO3_CONF_VARS']['DB']['password'])) {
347  $configurationComplete = false;
348  }
349  return $configurationComplete;
350  }
351 
368  protected function useDefaultValuesForNotConfiguredOptions()
369  {
370  $localConfigurationPathValuePairs = array();
371 
372  $localConfigurationPathValuePairs['DB/host'] = $this->getConfiguredHost();
373 
374  // If host is "local" either by upgrading or by first install, we try a socket
375  // connection first and use TCP/IP as fallback
376  if ($localConfigurationPathValuePairs['DB/host'] === 'localhost'
377  || \TYPO3\CMS\Core\Utility\GeneralUtility::cmpIP($localConfigurationPathValuePairs['DB/host'], '127.*.*.*')
378  || (string)$localConfigurationPathValuePairs['DB/host'] === ''
379  ) {
381  $localConfigurationPathValuePairs['DB/host'] = 'localhost';
382  $localConfigurationPathValuePairs['DB/socket'] = $this->getConfiguredSocket();
383  } else {
384  if (!\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($localConfigurationPathValuePairs['DB/host'], '127.')) {
385  $localConfigurationPathValuePairs['DB/host'] = '127.0.0.1';
386  }
387  }
388  }
389 
390  if (!isset($localConfigurationPathValuePairs['DB/socket'])) {
391  // Make sure a default port is set if not configured yet
392  // This is independent from any host configuration
393  $port = $this->getConfiguredPort();
394  if ($port > 0) {
395  $localConfigurationPathValuePairs['DB/port'] = $port;
396  } else {
397  $localConfigurationPathValuePairs['DB/port'] = $this->getConfiguredOrDefaultPort();
398  }
399  }
400 
402  $configurationManager = $this->objectManager->get(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
403  $configurationManager->setLocalConfigurationValuesByPathValuePairs($localConfigurationPathValuePairs);
404  }
405 
413  {
414  $result = false;
415  // Use configured socket
416  $socket = (string)$this->getConfiguredSocket();
417  if ($socket === '') {
418  // If no configured socket, use default php socket
419  $defaultSocket = (string)ini_get('mysqli.default_socket');
420  if ($defaultSocket !== '') {
421  $socket = $defaultSocket;
422  }
423  }
424  if ($socket !== '') {
425  $socketOpenResult = @fsockopen('unix://' . $socket);
426  if ($socketOpenResult) {
427  fclose($socketOpenResult);
428  $result = true;
429  }
430  }
431  return $result;
432  }
433 
441  protected function setDbalInputFieldsToRender()
442  {
443  $driver = $this->getSelectedDbalDriver();
444  switch ($driver) {
445  case 'mssql':
446  case 'odbc_mssql':
447  case 'postgres':
448  $this->view
449  ->assign('renderConnectDetailsUsername', true)
450  ->assign('renderConnectDetailsPassword', true)
451  ->assign('renderConnectDetailsHost', true)
452  ->assign('renderConnectDetailsPort', true)
453  ->assign('renderConnectDetailsDatabase', true);
454  break;
455  case 'oci8':
456  $this->view
457  ->assign('renderConnectDetailsUsername', true)
458  ->assign('renderConnectDetailsPassword', true)
459  ->assign('renderConnectDetailsHost', true)
460  ->assign('renderConnectDetailsPort', true)
461  ->assign('renderConnectDetailsDatabase', true)
462  ->assign('renderConnectDetailsOracleSidConnect', true);
463  $type = isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['config']['driverOptions']['connectSID'])
464  ? $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['config']['driverOptions']['connectSID']
465  : '';
466  if ($type === true) {
467  $this->view->assign('oracleSidSelected', true);
468  }
469  break;
470  }
471  }
472 
478  protected function getAvailableDbalDrivers()
479  {
480  $supportedDrivers = $this->getSupportedDbalDrivers();
481  $availableDrivers = array();
482  $selectedDbalDriver = $this->getSelectedDbalDriver();
483  foreach ($supportedDrivers as $abstractionLayer => $drivers) {
484  foreach ($drivers as $driver => $info) {
485  if (isset($info['combine']) && $info['combine'] === 'OR') {
486  $isAvailable = false;
487  } else {
488  $isAvailable = true;
489  }
490  // Loop through each PHP module dependency to ensure it is loaded
491  foreach ($info['extensions'] as $extension) {
492  if (isset($info['combine']) && $info['combine'] === 'OR') {
493  $isAvailable |= extension_loaded($extension);
494  } else {
495  $isAvailable &= extension_loaded($extension);
496  }
497  }
498  if ($isAvailable) {
499  if (!isset($availableDrivers[$abstractionLayer])) {
500  $availableDrivers[$abstractionLayer] = array();
501  }
502  $availableDrivers[$abstractionLayer][$driver] = array();
503  $availableDrivers[$abstractionLayer][$driver]['driver'] = $driver;
504  $availableDrivers[$abstractionLayer][$driver]['label'] = $info['label'];
505  $availableDrivers[$abstractionLayer][$driver]['selected'] = false;
506  if ($selectedDbalDriver === $driver) {
507  $availableDrivers[$abstractionLayer][$driver]['selected'] = true;
508  }
509  }
510  }
511  }
512  return $availableDrivers;
513  }
514 
521  protected function getSupportedDbalDrivers()
522  {
523  $supportedDrivers = array(
524  'Native' => array(
525  'mssql' => array(
526  'label' => 'Microsoft SQL Server',
527  'extensions' => array('mssql')
528  ),
529  'oci8' => array(
530  'label' => 'Oracle OCI8',
531  'extensions' => array('oci8')
532  ),
533  'postgres' => array(
534  'label' => 'PostgreSQL',
535  'extensions' => array('pgsql')
536  )
537  ),
538  'ODBC' => array(
539  'odbc_mssql' => array(
540  'label' => 'Microsoft SQL Server',
541  'extensions' => array('odbc', 'mssql')
542  )
543  )
544  );
545  return $supportedDrivers;
546  }
547 
553  protected function getSelectedDbalDriver()
554  {
555  if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['config']['driver'])) {
556  return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['config']['driver'];
557  }
558  return '';
559  }
560 
566  protected function executeLoadDbalExtension()
567  {
568  if (!ExtensionManagementUtility::isLoaded('adodb')) {
570  }
573  }
575  $warningStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\WarningStatus::class);
576  $warningStatus->setTitle('Loaded database abstraction layer');
577  return $warningStatus;
578  }
579 
585  protected function executeUnloadDbalExtension()
586  {
589  }
592  }
593  // @TODO: Remove configuration from TYPO3_CONF_VARS['EXTCONF']['dbal']
595  $warningStatus = $this->objectManager->get(\TYPO3\CMS\Install\Status\WarningStatus::class);
596  $warningStatus->setTitle('Removed database abstraction layer');
597  return $warningStatus;
598  }
599 
605  protected function getConfiguredUsername()
606  {
607  $username = isset($GLOBALS['TYPO3_CONF_VARS']['DB']['username']) ? $GLOBALS['TYPO3_CONF_VARS']['DB']['username'] : '';
608  return $username;
609  }
610 
616  protected function getConfiguredPassword()
617  {
618  $password = isset($GLOBALS['TYPO3_CONF_VARS']['DB']['password']) ? $GLOBALS['TYPO3_CONF_VARS']['DB']['password'] : '';
619  return $password;
620  }
621 
627  protected function getConfiguredHost()
628  {
629  $host = isset($GLOBALS['TYPO3_CONF_VARS']['DB']['host']) ? $GLOBALS['TYPO3_CONF_VARS']['DB']['host'] : '';
630  $port = isset($GLOBALS['TYPO3_CONF_VARS']['DB']['port']) ? $GLOBALS['TYPO3_CONF_VARS']['DB']['port'] : '';
631  if (strlen($port) < 1 && substr_count($host, ':') === 1) {
632  list($host) = explode(':', $host);
633  }
634  return $host;
635  }
636 
642  protected function getConfiguredPort()
643  {
644  $host = isset($GLOBALS['TYPO3_CONF_VARS']['DB']['host']) ? $GLOBALS['TYPO3_CONF_VARS']['DB']['host'] : '';
645  $port = isset($GLOBALS['TYPO3_CONF_VARS']['DB']['port']) ? $GLOBALS['TYPO3_CONF_VARS']['DB']['port'] : '';
646  if ($port === '' && substr_count($host, ':') === 1) {
647  $hostPortArray = explode(':', $host);
648  $port = $hostPortArray[1];
649  }
650  return (int)$port;
651  }
652 
658  protected function getConfiguredSocket()
659  {
660  $socket = isset($GLOBALS['TYPO3_CONF_VARS']['DB']['socket']) ? $GLOBALS['TYPO3_CONF_VARS']['DB']['socket'] : '';
661  return $socket;
662  }
663 }