[TASK] Correct DBAL ux_* class mapping in migrations file
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_install.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
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 * Class to setup values in localconf.php and verify the TYPO3 DB tables/fields
29 *
30 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
31 */
32 /**
33 * Class to setup values in localconf.php and verify the TYPO3 DB tables/fields
34 *
35 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
36 * @package TYPO3
37 * @subpackage t3lib
38 */
39 class t3lib_install {
40
41 // External, Static
42 // Set to string which identifies the script using this class.
43 /**
44 * @todo Define visibility
45 */
46 public $updateIdentity = '';
47
48 // Prefix for checkbox fields when updating database.
49 /**
50 * @todo Define visibility
51 */
52 public $dbUpdateCheckboxPrefix = 'TYPO3_INSTALL[database_update]';
53
54 // If this is set, modifications to localconf.php is done by adding new lines to the array only. If unset, existing values are recognized and changed.
55 /**
56 * @todo Define visibility
57 */
58 public $localconf_addLinesOnly = 0;
59
60 // If set and addLinesOnly is disabled, lines will be change only if they are after this token (on a single line!) in the file
61 protected $localconf_startEditPointToken = '## INSTALL SCRIPT EDIT POINT TOKEN - all lines after this points may be changed by the install script!';
62
63 protected $localconf_endEditPointToken = '## INSTALL SCRIPT EDIT END POINT TOKEN - all lines before this points may be changed by the install script!';
64
65 // If TRUE, this class will allow the user to update the localconf.php file. Is set TRUE in the init.php file.
66 /**
67 * @todo Define visibility
68 */
69 public $allowUpdateLocalConf = 0;
70
71 // Backpath (used for icons etc.)
72 /**
73 * @todo Define visibility
74 */
75 public $backPath = '../';
76
77 // Internal, dynamic:
78 // Used to indicate that a value is change in the line-array of localconf and that it should be written.
79 /**
80 * @todo Define visibility
81 */
82 public $setLocalconf = 0;
83
84 // Used to set (error)messages from the executing functions like mail-sending, writing Localconf and such
85 /**
86 * @todo Define visibility
87 */
88 public $messages = array();
89
90 // Updated with line in localconf.php file that was changed.
91 /**
92 * @todo Define visibility
93 */
94 public $touchedLine = 0;
95
96 /**
97 * @var \TYPO3\CMS\Install\Sql\SchemaMigrator Instance of SQL handler
98 */
99 protected $sqlHandler = NULL;
100
101 /**
102 * Constructor function
103 */
104 public function __construct() {
105 $this->sqlHandler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Install\\Sql\\SchemaMigrator');
106 }
107
108 /**************************************
109 *
110 * Writing to localconf.php
111 ***************************************/
112 /**
113 * This functions takes an array with lines from localconf.php, finds a variable and inserts the new value.
114 *
115 * @param array $line_array The localconf.php file exploded into an array by linebreaks. (see writeToLocalconf_control())
116 * @param string $variable The variable name to find and substitute. This string must match the first part of a trimmed line in the line-array. Matching is done backwards so the last appearing line will be substituted.
117 * @param string $value Is the value to be insert for the variable
118 * @param boolean $quoteValue Whether the given value should be quoted before being written
119 * @return void
120 * @see writeToLocalconf_control()
121 */
122 public function setValueInLocalconfFile(&$line_array, $variable, $value, $quoteValue = TRUE) {
123 if (!$this->checkForBadString($value)) {
124 return 0;
125 }
126 // Initialize
127 $found = 0;
128 $this->touchedLine = '';
129 $inArray = in_array($this->localconf_startEditPointToken, $line_array);
130 // Flag is set if the token should be set but is not yet.
131 $tokenSet = $this->localconf_startEditPointToken && !$inArray;
132 $stopAtToken = $this->localconf_startEditPointToken && $inArray;
133 $hasEndToken = in_array($this->localconf_endEditPointToken, $line_array);
134 $respectEndToken = $hasEndToken;
135 $comment = (' Modified or inserted by ' . $this->updateIdentity) . '.';
136 $replace = array('["', '"]');
137 $search = array('[\'', '\']');
138 $varDoubleQuotes = str_replace($search, $replace, $variable);
139 // Search for variable name
140 if (!$this->localconf_addLinesOnly && !$tokenSet) {
141 $line_array = array_reverse($line_array);
142 foreach ($line_array as $k => $v) {
143 $v2 = trim($v);
144 if ($respectEndToken) {
145 if (strcmp($v2, $this->localconf_endEditPointToken)) {
146 $respectEndToken = FALSE;
147 } else {
148 continue;
149 }
150 }
151 if ($stopAtToken && !strcmp($v2, $this->localconf_startEditPointToken)) {
152 break;
153 }
154 // If stopAtToken and token found, break out of the loop..
155 if (!strcmp(substr($v2, 0, strlen(($variable . ' '))), ($variable . ' '))) {
156 $mainparts = explode($variable, $v, 2);
157 // Should ALWAYS be.
158 if (count($mainparts) == 2) {
159 $subparts = explode('//', $mainparts[1], 2);
160 if ($quoteValue) {
161 $value = ('\'' . $this->slashValueForSingleDashes($value)) . '\'';
162 }
163 $line_array[$k] = (((($mainparts[0] . $variable) . ' = ') . $value) . '; ') . (('//' . $comment) . str_replace($comment, '', $subparts[1]));
164 $this->touchedLine = (count($line_array) - $k) - 1;
165 $found = 1;
166 break;
167 }
168 } elseif (!strcmp(substr($v2, 0, strlen(($varDoubleQuotes . ' '))), ($varDoubleQuotes . ' '))) {
169 // Due to a bug in the update wizard (fixed in TYPO3 4.1.7) it is possible
170 // that $TYPO3_CONF_VARS['SYS']['compat_version'] was enclosed by "" (double
171 // quotes) instead of the expected '' (single quotes) when is was written to
172 // localconf.php. The following code was added to make sure that values with
173 // double quotes are updated, too.
174 $mainparts = explode($varDoubleQuotes, $v, 2);
175 // Should ALWAYS be.
176 if (count($mainparts) == 2) {
177 $subparts = explode('//', $mainparts[1], 2);
178 if ($quoteValue) {
179 $value = ('\'' . $this->slashValueForSingleDashes($value)) . '\'';
180 }
181 $line_array[$k] = (((($mainparts[0] . $variable) . ' = ') . $value) . '; ') . (('//' . $comment) . str_replace($comment, '', $subparts[1]));
182 $this->touchedLine = (count($line_array) - $k) - 1;
183 $found = 1;
184 break;
185 }
186 }
187 }
188 $line_array = array_reverse($line_array);
189 }
190 if (!$found) {
191 if ($tokenSet) {
192 $line_array[] = $this->localconf_startEditPointToken;
193 $line_array[] = '';
194 }
195 if ($quoteValue) {
196 $value = ('\'' . $this->slashValueForSingleDashes($value)) . '\'';
197 }
198 $line_array[] = ((($variable . ' = ') . $value) . '; // ') . $comment;
199 if (!$hasEndToken) {
200 $line_array[] = '';
201 $line_array[] = $this->localconf_endEditPointToken;
202 }
203 $this->touchedLine = -1;
204 }
205 if ($variable == '$typo_db_password') {
206 $this->messages[] = 'Updated ' . $variable;
207 } else {
208 $this->messages[] = ($variable . ' = ') . htmlspecialchars($value);
209 }
210 $this->setLocalconf = 1;
211 }
212
213 /**
214 * Takes an array with lines from localconf.php, finds a variable and inserts the new array value.
215 *
216 * @param array $lines the localconf.php file exploded into an array by line breaks. {@see writeToLocalconf_control()}
217 * @param string $variable the variable name to find and substitute. This string must match the first part of a trimmed line in the line-array. Matching is done backwards so the last appearing line will be substituted.
218 * @param array $value value to be assigned to the variable
219 * @return void
220 * @see writeToLocalconf_control()
221 */
222 public function setArrayValueInLocalconfFile(array &$lines, $variable, array $value) {
223 $commentKey = '## ';
224 $inArray = in_array($commentKey . $this->localconf_startEditPointToken, $lines);
225 $tokenSet = $this->localconf_startEditPointToken && !$inArray;
226 // Flag is set if the token should be set but is not yet
227 $stopAtToken = $this->localconf_startEditPointToken && $inArray;
228 $comment = ('Modified or inserted by ' . $this->updateIdentity) . '.';
229 $format = '%s = %s; // ' . $comment;
230 $insertPos = count($lines);
231 $startPos = 0;
232 if (!($this->localconf_addLinesOnly || $tokenSet)) {
233 for ($i = count($lines) - 1; $i > 0; $i--) {
234 $line = trim($lines[$i]);
235 if ($stopAtToken && \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($line, $this->localconf_startEditPointToken)) {
236 break;
237 }
238 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($line, '?>')) {
239 $insertPos = $i;
240 }
241 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($line, $variable)) {
242 $startPos = $i;
243 break;
244 }
245 }
246 }
247 if ($startPos) {
248 $this->touchedLine = $startPos;
249 $endPos = $startPos;
250 for ($i = $startPos; $i < count($lines); $i++) {
251 $line = trim($lines[$i]);
252 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($line, ');')) {
253 $endPos = $i;
254 break;
255 }
256 }
257 $startLines = array_slice($lines, 0, $startPos);
258 $endLines = array_slice($lines, $endPos + 1);
259 $lines = $startLines;
260 $definition = $this->array_export($value);
261 $lines[] = sprintf($format, $variable, $definition);
262 foreach ($endLines as $line) {
263 $lines[] = $line;
264 }
265 } else {
266 $lines[$insertPos] = sprintf($format, $variable, $this->array_export($value));
267 $lines[] = '?>';
268 $this->touchedLine = -1;
269 }
270 }
271
272 /**
273 * Returns a parsable string representation of an array variable. This methods enhances
274 * standard method var_export from PHP to take TYPO3's CGL into account.
275 *
276 * @param array $variable
277 * @return string
278 */
279 protected function array_export(array $variable) {
280 $lines = explode('
281 ', var_export($variable, TRUE));
282 $out = 'array(';
283 for ($i = 1; $i < count($lines); $i++) {
284 $out .= '
285 ';
286 // Make the space-indented declaration tab-indented instead
287 while (substr($lines[$i], 0, 2) === ' ') {
288 $out .= ' ';
289 $lines[$i] = substr($lines[$i], 2);
290 }
291 $out .= $lines[$i];
292 // Array declaration should be next to the assignment and no space between
293 // "array" and its opening parenthesis should exist
294 if (preg_match('/\\s=>\\s$/', $lines[$i])) {
295 $out .= preg_replace('/^\\s*array \\(/', 'array(', $lines[$i + 1]);
296 $i++;
297 }
298 }
299 return $out;
300 }
301
302 /**
303 * Writes or returns lines from localconf.php
304 *
305 * @param mixed $inlines Array of lines to write back to localconf.php. Possibly
306 * @param string $absFullPath Absolute path of alternative file to use (Notice: this path is not validated in terms of being inside 'TYPO3 space')
307 * @return mixed If $inlines is not an array it will return an array with the lines from localconf.php. Otherwise it will return a status string, either "continue" (updated) or "nochange" (not updated)
308 * @see setValueInLocalconfFile()
309 * @todo Define visibility
310 */
311 public function writeToLocalconf_control($inlines = '', $absFullPath = '') {
312 $tmpExt = '.TMP.php';
313 $writeToLocalconf_dat = array();
314 $writeToLocalconf_dat['file'] = $absFullPath ? $absFullPath : PATH_typo3conf . 'localconf.php';
315 $writeToLocalconf_dat['tmpfile'] = $writeToLocalconf_dat['file'] . $tmpExt;
316 // Checking write state of localconf.php
317 if (!$this->allowUpdateLocalConf) {
318 throw new RuntimeException('TYPO3 Fatal Error: ->allowUpdateLocalConf flag in the install object is not set and therefore "localconf.php" cannot be altered.', 1270853915);
319 }
320 if (!@is_writable($writeToLocalconf_dat['file'])) {
321 throw new RuntimeException(('TYPO3 Fatal Error: ' . $writeToLocalconf_dat['file']) . ' is not writable!', 1270853916);
322 }
323 // Splitting localconf.php file into lines
324 $lines = explode(LF, str_replace(CR, '', trim(\TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($writeToLocalconf_dat['file']))));
325 $writeToLocalconf_dat['endLine'] = array_pop($lines);
326 // Getting "? >" ending.
327 // Checking if "updated" line was set by this tool - if so remove old line.
328 $updatedLine = array_pop($lines);
329 $writeToLocalconf_dat['updatedText'] = ('// Updated by ' . $this->updateIdentity) . ' ';
330 if (!strstr($updatedLine, $writeToLocalconf_dat['updatedText'])) {
331 array_push($lines, $updatedLine);
332 }
333 // Setting a line and write
334 if (is_array($inlines)) {
335 // Setting configuration
336 $updatedLine = $writeToLocalconf_dat['updatedText'] . date(($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' H:i:s'));
337 array_push($inlines, $updatedLine);
338 array_push($inlines, $writeToLocalconf_dat['endLine']);
339 if ($this->setLocalconf) {
340 $success = $this->writeToLocalconf($inlines, $absFullPath);
341 if ($success) {
342 return 'continue';
343 } else {
344 return 'nochange';
345 }
346 } else {
347 return 'nochange';
348 }
349 } else {
350 // Return lines found in localconf.php
351 return $lines;
352 }
353 }
354
355 /**
356 * Writes lines to localconf.php.
357 *
358 * @param array $lines Array of lines to write back to localconf.php
359 * @param string $absFullPath Absolute path of alternative file to use (Notice: this path is not validated in terms of being inside 'TYPO3 space')
360 * @return boolean TRUE if method succeeded, otherwise FALSE
361 */
362 public function writeToLocalconf(array $lines, $absFullPath = '') {
363 $tmpExt = '.TMP.php';
364 $writeToLocalconf_dat = array();
365 $writeToLocalconf_dat['file'] = $absFullPath ? $absFullPath : PATH_typo3conf . 'localconf.php';
366 $writeToLocalconf_dat['tmpfile'] = $writeToLocalconf_dat['file'] . $tmpExt;
367 // Checking write state of localconf.php:
368 if (!$this->allowUpdateLocalConf) {
369 throw new RuntimeException('TYPO3 Fatal Error: ->allowUpdateLocalConf flag in the install object is not set and therefore "localconf.php" cannot be altered.', 1270853915);
370 }
371 if (!@is_writable($writeToLocalconf_dat['file'])) {
372 throw new RuntimeException(('TYPO3 Fatal Error: ' . $writeToLocalconf_dat['file']) . ' is not writable!', 1270853916);
373 }
374 $writeToLocalconf_dat['endLine'] = array_pop($lines);
375 // Getting "? >" ending.
376 if (!strstr(('?' . '>'), $writeToLocalconf_dat['endLine'])) {
377 $lines[] = $writeToLocalconf_dat['endLine'];
378 $writeToLocalconf_dat['endLine'] = '?' . '>';
379 }
380 // Checking if "updated" line was set by this tool - if so remove old line.
381 $updatedLine = array_pop($lines);
382 $writeToLocalconf_dat['updatedText'] = ('// Updated by ' . $this->updateIdentity) . ' ';
383 if (!strstr($updatedLine, $writeToLocalconf_dat['updatedText'])) {
384 $lines[] = $updatedLine;
385 }
386 $updatedLine = $writeToLocalconf_dat['updatedText'] . date(($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' H:i:s'));
387 $lines[] = $updatedLine;
388 $lines[] = $writeToLocalconf_dat['endLine'];
389 $success = FALSE;
390 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::writeFile($writeToLocalconf_dat['tmpfile'], implode(LF, $lines))) {
391 $msg = ('typo3conf/localconf.php' . $tmpExt) . ' could not be written - maybe a write access problem?';
392 } elseif (strcmp(\TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($writeToLocalconf_dat['tmpfile']), implode(LF, $lines))) {
393 @unlink($writeToLocalconf_dat['tmpfile']);
394 $msg = ('typo3conf/localconf.php' . $tmpExt) . ' was NOT written properly (written content didn\'t match file content) - maybe a disk space problem?';
395 } elseif (!@copy($writeToLocalconf_dat['tmpfile'], $writeToLocalconf_dat['file'])) {
396 $msg = ('typo3conf/localconf.php could not be replaced by typo3conf/localconf.php' . $tmpExt) . ' - maybe a write access problem?';
397 } else {
398 @unlink($writeToLocalconf_dat['tmpfile']);
399 $success = TRUE;
400 $msg = 'Configuration written to typo3conf/localconf.php';
401 }
402 $this->messages[] = $msg;
403 if (!$success) {
404 \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog($msg, 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_ERROR);
405 }
406 return $success;
407 }
408
409 /**
410 * Checking for linebreaks in the string
411 *
412 * @param string $string String to test
413 * @return boolean Returns TRUE if string is OK
414 * @see setValueInLocalconfFile()
415 * @todo Define visibility
416 */
417 public function checkForBadString($string) {
418 return preg_match((('/[' . LF) . CR) . ']/', $string) ? FALSE : TRUE;
419 }
420
421 /**
422 * Replaces ' with \' and \ with \\
423 *
424 * @param string $value Input value
425 * @return string Output value
426 * @see setValueInLocalconfFile()
427 * @todo Define visibility
428 */
429 public function slashValueForSingleDashes($value) {
430 $value = str_replace('\'.LF.\'', '###INSTALL_TOOL_LINEBREAK###', $value);
431 $value = str_replace('\'', '\\\'', str_replace('\\', '\\\\', $value));
432 $value = str_replace('###INSTALL_TOOL_LINEBREAK###', '\'.LF.\'', $value);
433 return $value;
434 }
435
436 /**
437 * Creates a table which checkboxes for updating database.
438 *
439 * @param array $arr Array of statements (key / value pairs where key is used for the checkboxes)
440 * @param string $label Label for the table.
441 * @param boolean $checked If set, then checkboxes are set by default.
442 * @param boolean $iconDis If set, then icons are shown.
443 * @param array $currentValue Array of "current values" for each key/value pair in $arr. Shown if given.
444 * @param boolean $cVfullMsg If set, will show the prefix "Current value" if $currentValue is given.
445 * @return string HTML table with checkboxes for update. Must be wrapped in a form.
446 * @todo Define visibility
447 */
448 public function generateUpdateDatabaseForm_checkboxes($arr, $label, $checked = TRUE, $iconDis = FALSE, $currentValue = array(), $cVfullMsg = FALSE) {
449 $out = array();
450 if (is_array($arr)) {
451 $tableId = uniqid('table');
452 if (count($arr) > 1) {
453 $out[] = ((((((('
454 <tr class="update-db-fields-batch">
455 <td valign="top">
456 <input type="checkbox" id="' . $tableId) . '-checkbox"') . ($checked ? ' checked="checked"' : '')) . '
457 onclick="$(\'') . $tableId) . '\').select(\'input[type=checkbox]\').invoke(\'setValue\', $(this).checked);" />
458 </td>
459 <td nowrap="nowrap"><label for="') . $tableId) . '-checkbox" style="cursor:pointer"><strong>select/deselect all</strong></label></td>
460 </tr>';
461 }
462 foreach ($arr as $key => $string) {
463 $ico = '';
464 $warnings = array();
465 if ($iconDis) {
466 if (preg_match('/^TRUNCATE/i', $string)) {
467 $ico .= ('<img src="' . $this->backPath) . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong> </strong>';
468 $warnings['clear_table_info'] = 'Clearing the table is sometimes neccessary when adding new keys. In case of cache_* tables this should not hurt at all. However, use it with care.';
469 } elseif (stristr($string, ' user_')) {
470 $ico .= ('<img src="' . $this->backPath) . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong>(USER) </strong>';
471 } elseif (stristr($string, ' app_')) {
472 $ico .= ('<img src="' . $this->backPath) . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong>(APP) </strong>';
473 } elseif (stristr($string, ' ttx_') || stristr($string, ' tx_')) {
474 $ico .= ('<img src="' . $this->backPath) . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong>(EXT) </strong>';
475 }
476 }
477 $out[] = ((((((((((('
478 <tr>
479 <td valign="top"><input type="checkbox" id="db-' . $key) . '" name="') . $this->dbUpdateCheckboxPrefix) . '[') . $key) . ']" value="1"') . ($checked ? ' checked="checked"' : '')) . ' /></td>
480 <td nowrap="nowrap"><label for="db-') . $key) . '">') . nl2br(($ico . htmlspecialchars($string)))) . '</label></td>
481 </tr>';
482 if (isset($currentValue[$key])) {
483 $out[] = ('
484 <tr>
485 <td valign="top"></td>
486 <td nowrap="nowrap" style="color:#666666;">' . nl2br(((((!$cVfullMsg ? 'Current value: ' : '') . '<em>') . $currentValue[$key]) . '</em>'))) . '</td>
487 </tr>';
488 }
489 }
490 if (count($warnings)) {
491 $out[] = ('
492 <tr>
493 <td valign="top"></td>
494 <td style="color:#666666;"><em>' . implode('<br />', $warnings)) . '</em></td>
495 </tr>';
496 }
497 // Compile rows:
498 $content = ((((('
499 <!-- Update database fields / tables -->
500 <h3>' . $label) . '</h3>
501 <table border="0" cellpadding="2" cellspacing="2" id="') . $tableId) . '" class="update-db-fields">') . implode('', $out)) . '
502 </table>';
503 }
504 return $content;
505 }
506
507 }
508
509 ?>