f94478249d537b27f5ae03011f21bd4e05dd57ae
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / Classes / Hooks / InstallToolHooks.php
1 <?php
2 namespace TYPO3\CMS\Dbal\Hooks;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2011 Xavier Perseguers <xavier@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Hooks for TYPO3 Install Tool.
31 *
32 * @author Xavier Perseguers <xavier@typo3.org>
33 * @package TYPO3
34 * @subpackage dbal
35 */
36 class InstallToolHooks {
37
38 /**
39 * @var string
40 */
41 protected $templateFilePath = 'res/Templates/';
42
43 /**
44 * @var array
45 */
46 protected $supportedDrivers;
47
48 /**
49 * @var array
50 */
51 protected $availableDrivers;
52
53 /**
54 * @var string
55 */
56 protected $driver;
57
58 /**
59 * Default constructor.
60 */
61 public function __construct() {
62 $this->supportedDrivers = $this->getSupportedDrivers();
63 $this->availableDrivers = $this->getAvailableDrivers();
64 $configDriver =& $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['config']['driver'];
65 $this->driver = \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('driver');
66 if (!$this->driver && $configDriver) {
67 $this->driver = $configDriver;
68 }
69 }
70
71 /**
72 * Hooks into Installer to set required PHP modules.
73 *
74 * @param array $modules
75 * @param tx_install|tx_reports_reports_status_SystemStatus $instObj
76 * @return array modules
77 */
78 public function setRequiredPhpModules(array &$modules, $instObj) {
79 $modifiedModules = array();
80 foreach ($modules as $key => $module) {
81 if ($module === 'mysql') {
82 $dbModules = array();
83 foreach ($this->supportedDrivers as $abstractionLayer => $drivers) {
84 $dbModules = array_merge($dbModules, array_keys($drivers));
85 }
86 $module = $dbModules;
87 }
88 $modifiedModules[] = $module;
89 }
90 return $modifiedModules;
91 }
92
93 /**
94 * Hooks into Installer to let a non-MySQL database to be configured.
95 *
96 * @param array $markers
97 * @param integer $step
98 * @param \TYPO3\CMS\Install\Installer $instObj
99 * @return void
100 */
101 public function executeStepOutput(array &$markers, $step, \TYPO3\CMS\Install\Installer $instObj) {
102 switch ($step) {
103 case 2:
104 $this->createConnectionForm($markers, $instObj);
105 break;
106 case 3:
107 $this->createDatabaseForm($markers, $instObj);
108 break;
109 }
110 }
111
112 /**
113 * Hooks into Installer to modify lines to be written to localconf.php.
114 *
115 * @param array $lines This parameter is obsolet as of TYPO3 6.0
116 * @param integer $step
117 * @param \TYPO3\CMS\Install\Installer $instObj
118 * @return void
119 */
120 public function executeWriteLocalconf(array &$lines, $step, \TYPO3\CMS\Install\Installer $instObj) {
121 switch ($step) {
122 case 3:
123
124 case 4:
125 $driver = $instObj->INSTALL['Database']['typo_db_driver'];
126 if (!$driver && $this->driver) {
127 // Driver was already configured
128 break;
129 }
130 $driverConfig = '';
131 switch ($driver) {
132 case 'oci8':
133 $driverConfig = array(
134 'driverOptions' => array(
135 'connectSID' => $instObj->INSTALL['Database']['typo_db_type'] === 'sid' ? TRUE : FALSE
136 )
137 );
138 break;
139 case 'mssql':
140
141 case 'odbc_mssql':
142 $driverConfig = array(
143 'useNameQuote' => TRUE,
144 'quoteClob' => FALSE
145 );
146 break;
147 case 'mysql':
148 return;
149 }
150 $config = array(
151 '_DEFAULT' => array(
152 'type' => 'adodb',
153 'config' => array(
154 'driver' => $driver,
155 $driverConfig
156 )
157 )
158 );
159 \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager')->setLocalConfigurationValuesByPathValuePairs('EXTCONF/dbal/handlerCfg', $config);
160 break;
161 }
162 }
163
164 /**
165 * Creates a specialized form to configure the DBMS connection.
166 *
167 * @param array $markers
168 * @param \TYPO3\CMS\Install\Installer $instObj
169 * @return void
170 */
171 protected function createConnectionForm(array &$markers, \TYPO3\CMS\Install\Installer $instObj) {
172 // Normalize current driver
173 if (!$this->driver) {
174 $this->driver = $this->getDefaultDriver();
175 }
176 // Get the template file
177 $templateFile = @file_get_contents((\TYPO3\CMS\Core\Extension\ExtensionManager::extPath('dbal') . $this->templateFilePath . 'install.html'));
178 // Get the template part from the file
179 $template = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###TEMPLATE###');
180 // Get the subpart for the connection form
181 $formSubPart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###CONNECTION_FORM###');
182 if ($this->getNumberOfAvailableDrivers() == 1 && $this->getDefaultDriver() === 'mysql') {
183 // Only MySQL is actually available (PDO support may be compiled in
184 // PHP itself and as such DBAL was activated, behaves as if DBAL were
185 // not activated
186 $driverSubPart = '<input type="hidden" name="TYPO3_INSTALL[Database][typo_db_driver]" value="mysql" />';
187 } else {
188 $driverTemplate = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($formSubPart, '###DATABASE_DRIVER###');
189 $driverSubPart = $this->prepareDatabaseDrivers($driverTemplate);
190 }
191 $formSubPart = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($formSubPart, '###DATABASE_DRIVER###', $driverSubPart);
192 // Get the subpart related to selected database driver
193 if ($this->driver === '' || $this->driver === 'mysql') {
194 $driverOptionsSubPart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###DRIVER_MYSQL###');
195 } else {
196 $driverOptionsSubPart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###DRIVER_' . \TYPO3\CMS\Core\Utility\GeneralUtility::strtoupper($this->driver) . '###');
197 if ($driverOptionsSubPart === '') {
198 $driverOptionsSubPart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###DRIVER_DEFAULT###');
199 }
200 }
201 // Define driver-specific markers
202 $driverMarkers = array();
203 switch ($this->driver) {
204 case 'mssql':
205 $driverMarkers = array(
206 'labelUsername' => 'Username',
207 'username' => TYPO3_db_username,
208 'labelPassword' => 'Password',
209 'password' => TYPO3_db_password,
210 'labelHost' => 'Host',
211 'host' => TYPO3_db_host ? TYPO3_db_host : 'windows',
212 'labelDatabase' => 'Database',
213 'database' => TYPO3_db
214 );
215 $nextStep = $instObj->step + 2;
216 break;
217 case 'odbc_mssql':
218 $driverMarkers = array(
219 'labelUsername' => 'Username',
220 'username' => TYPO3_db_username,
221 'labelPassword' => 'Password',
222 'password' => TYPO3_db_password,
223 'labelHost' => 'Host',
224 'host' => TYPO3_db_host ? TYPO3_db_host : 'windows',
225 'database' => 'dummy_string'
226 );
227 $nextStep = $instObj->step + 2;
228 break;
229 case 'oci8':
230 $driverMarkers = array(
231 'labelUsername' => 'Username',
232 'username' => TYPO3_db_username,
233 'labelPassword' => 'Password',
234 'password' => TYPO3_db_password,
235 'labelHost' => 'Host',
236 'host' => TYPO3_db_host ? TYPO3_db_host : 'localhost',
237 'labelType' => 'Type',
238 'labelSID' => 'SID',
239 'labelServiceName' => 'Service Name',
240 'labelDatabase' => 'Name',
241 'database' => TYPO3_db
242 );
243 $nextStep = $instObj->step + 2;
244 break;
245 case 'postgres':
246 $driverMarkers = array(
247 'labelUsername' => 'Username',
248 'username' => TYPO3_db_username,
249 'labelPassword' => 'Password',
250 'password' => TYPO3_db_password,
251 'labelHost' => 'Host',
252 'host' => TYPO3_db_host ? TYPO3_db_host : 'localhost',
253 'labelDatabase' => 'Database',
254 'database' => TYPO3_db
255 );
256 $nextStep = $instObj->step + 2;
257 break;
258 default:
259 $driverMarkers = array(
260 'labelUsername' => 'Username',
261 'username' => TYPO3_db_username,
262 'labelPassword' => 'Password',
263 'password' => TYPO3_db_password,
264 'labelHost' => 'Host',
265 'host' => TYPO3_db_host ? TYPO3_db_host : 'localhost',
266 'labelDatabase' => 'Database',
267 'database' => TYPO3_db
268 );
269 $nextStep = $instObj->step + 1;
270 break;
271 }
272 // Add header marker for main template
273 $markers['header'] = 'Connect to your database host';
274 // Define the markers content for the subpart
275 $subPartMarkers = array(
276 'step' => $nextStep,
277 'action' => htmlspecialchars($instObj->action),
278 'encryptionKey' => $instObj->createEncryptionKey(),
279 'branch' => TYPO3_branch,
280 'driver_options' => $driverOptionsSubPart,
281 'continue' => 'Continue',
282 'llDescription' => 'If you have not already created a username and password to access the database, please do so now. This can be done using tools provided by your host.'
283 );
284 $subPartMarkers = array_merge($subPartMarkers, $driverMarkers);
285 // Add step marker for main template
286 $markers['step'] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($formSubPart, $subPartMarkers, '###|###', 1, 1);
287 }
288
289 /**
290 * Prepares the list of database drivers for step 2.
291 *
292 * @param string $template
293 * @return string
294 */
295 protected function prepareDatabaseDrivers($template) {
296 $subParts = array(
297 'abstractionLayer' => \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###ABSTRACTION_LAYER###'),
298 'vendor' => \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###VENDOR###')
299 );
300 // Create the drop-down list of available drivers
301 $dropdown = '';
302 foreach ($this->availableDrivers as $abstractionLayer => $drivers) {
303 $options = array();
304 foreach ($drivers as $driver => $label) {
305 $markers = array(
306 'driver' => $driver,
307 'labelvendor' => $label,
308 'onclick' => 'document.location=\'index.php?TYPO3_INSTALL[type]=config&mode=123&step=2&driver=' . $driver . '\';',
309 'selected' => ''
310 );
311 if ($driver === $this->driver) {
312 $markers['selected'] .= ' selected="selected"';
313 }
314 $options[] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($subParts['vendor'], $markers, '###|###', 1);
315 }
316 $subPart = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($subParts['abstractionLayer'], '###VENDOR###', implode('
317 ', $options));
318 $dropdown .= \TYPO3\CMS\Core\Html\HtmlParser::substituteMarker($subPart, '###LABELABSTRACTIONLAYER###', $abstractionLayer);
319 }
320 $form = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($template, '###ABSTRACTION_LAYER###', $dropdown);
321 $form = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarker($form, '###LABELDRIVER###', 'Driver');
322 return $form;
323 }
324
325 /**
326 * Returns a list of DBAL supported database drivers, with a user-friendly name
327 * and any PHP module dependency.
328 *
329 * @return array
330 */
331 protected function getSupportedDrivers() {
332 $supportedDrivers = array(
333 'Native' => array(
334 'mysql' => array(
335 'label' => 'MySQL/MySQLi (recommended)',
336 'combine' => 'OR',
337 'extensions' => array('mysql', 'mysqli')
338 ),
339 'mssql' => array(
340 'label' => 'Microsoft SQL Server',
341 'extensions' => array('mssql')
342 ),
343 'oci8' => array(
344 'label' => 'Oracle OCI8',
345 'extensions' => array('oci8')
346 ),
347 'postgres' => array(
348 'label' => 'PostgreSQL',
349 'extensions' => array('pgsql')
350 )
351 ),
352 'ODBC' => array(
353 'odbc_mssql' => array(
354 'label' => 'Microsoft SQL Server',
355 'extensions' => array('odbc', 'mssql')
356 )
357 )
358 );
359 return $supportedDrivers;
360 }
361
362 /**
363 * Returns a list of database drivers that are available on current server.
364 *
365 * @return array
366 */
367 protected function getAvailableDrivers() {
368 $availableDrivers = array();
369 foreach ($this->supportedDrivers as $abstractionLayer => $drivers) {
370 foreach ($drivers as $driver => $info) {
371 if (isset($info['combine']) && $info['combine'] === 'OR') {
372 $isAvailable = FALSE;
373 } else {
374 $isAvailable = TRUE;
375 }
376 // Loop through each PHP module dependency to ensure it is loaded
377 foreach ($info['extensions'] as $extension) {
378 if (isset($info['combine']) && $info['combine'] === 'OR') {
379 $isAvailable |= extension_loaded($extension);
380 } else {
381 $isAvailable &= extension_loaded($extension);
382 }
383 }
384 if ($isAvailable) {
385 if (!isset($availableDrivers[$abstractionLayer])) {
386 $availableDrivers[$abstractionLayer] = array();
387 }
388 $availableDrivers[$abstractionLayer][$driver] = $info['label'];
389 }
390 }
391 }
392 return $availableDrivers;
393 }
394
395 /**
396 * Returns the number of available drivers.
397 *
398 * @return boolean
399 */
400 protected function getNumberOfAvailableDrivers() {
401 $count = 0;
402 foreach ($this->availableDrivers as $drivers) {
403 $count += count($drivers);
404 }
405 return $count;
406 }
407
408 /**
409 * Returns the driver that is selected by default in the
410 * Install Tool dropdown list.
411 *
412 * @return string
413 */
414 protected function getDefaultDriver() {
415 $defaultDriver = '';
416 if (count($this->availableDrivers)) {
417 $abstractionLayers = array_keys($this->availableDrivers);
418 $drivers = array_keys($this->availableDrivers[$abstractionLayers[0]]);
419 $defaultDriver = $drivers[0];
420 }
421 return $defaultDriver;
422 }
423
424 /**
425 * Creates a specialized form to configure the database.
426 *
427 * @param array $markers
428 * @param \TYPO3\CMS\Install\Installer $instObj
429 */
430 protected function createDatabaseForm(array &$markers, \TYPO3\CMS\Install\Installer $instObj) {
431 $error_missingConnect = '
432 <p class="typo3-message message-error">
433 <strong>
434 There is no connection to the database!
435 </strong>
436 <br />
437 (Username: <em>' . TYPO3_db_username . '</em>,
438 Host: <em>' . TYPO3_db_host . '</em>,
439 Using Password: YES)
440 <br />
441 Go to Step 1 and enter a valid username and password!
442 </p>
443 ';
444 // Add header marker for main template
445 $markers['header'] = 'Select database';
446 // There should be a database host connection at this point
447 if ($result = $GLOBALS['TYPO3_DB']->sql_pconnect(TYPO3_db_host, TYPO3_db_username, TYPO3_db_password)) {
448 // Get the template file
449 $templateFile = @file_get_contents((\TYPO3\CMS\Core\Extension\ExtensionManager::extPath('dbal') . $this->templateFilePath . 'install.html'));
450 // Get the template part from the file
451 $template = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($templateFile, '###TEMPLATE###');
452 // Get the subpart for the database choice step
453 $formSubPart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($template, '###DATABASE_FORM###');
454 // Get the subpart for the database options
455 $step3DatabaseOptionsSubPart = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($formSubPart, '###DATABASEOPTIONS###');
456 $dbArr = $instObj->getDatabaseList();
457 $dbIncluded = FALSE;
458 foreach ($dbArr as $dbname) {
459 // Define the markers content for database options
460 $step3DatabaseOptionMarkers = array(
461 'databaseValue' => htmlspecialchars($dbname),
462 'databaseSelected' => $dbname === TYPO3_db ? 'selected="selected"' : '',
463 'databaseName' => htmlspecialchars($dbname)
464 );
465 // Add the option HTML to an array
466 $step3DatabaseOptions[] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($step3DatabaseOptionsSubPart, $step3DatabaseOptionMarkers, '###|###', 1, 1);
467 if ($dbname === TYPO3_db) {
468 $dbIncluded = TRUE;
469 }
470 }
471 if (!$dbIncluded && TYPO3_db) {
472 // // Define the markers content when no access
473 $step3DatabaseOptionMarkers = array(
474 'databaseValue' => htmlspecialchars(TYPO3_db),
475 'databaseSelected' => 'selected="selected"',
476 'databaseName' => htmlspecialchars(TYPO3_db) . ' (NO ACCESS!)'
477 );
478 // Add the option HTML to an array
479 $step3DatabaseOptions[] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($step3DatabaseOptionsSubPart, $step3DatabaseOptionMarkers, '###|###', 1, 1);
480 }
481 // Substitute the subpart for the database options
482 $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($formSubPart, '###DATABASEOPTIONS###', implode(chr(10), $step3DatabaseOptions));
483 // Define the markers content
484 $step3SubPartMarkers = array(
485 'step' => $instObj->step + 1,
486 'action' => htmlspecialchars($instObj->action),
487 'llOption2' => 'Select an EMPTY existing database:',
488 'llRemark2' => 'Any tables used by TYPO3 will be overwritten.',
489 'continue' => 'Continue'
490 );
491 // Add step marker for main template
492 $markers['step'] = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($content, $step3SubPartMarkers, '###|###', 1, 1);
493 } else {
494 // Add step marker for main template when no connection
495 $markers['step'] = $error_missingConnect;
496 }
497 }
498
499 }
500
501
502 ?>