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