[TASK] Remove function index
[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
34 /**
35 * Class to setup values in localconf.php and verify the TYPO3 DB tables/fields
36 *
37 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
38 * @package TYPO3
39 * @subpackage t3lib
40 */
41 class t3lib_install {
42
43
44 // External, Static
45 var $updateIdentity = ''; // Set to string which identifies the script using this class.
46 var $deletedPrefixKey = 'zzz_deleted_'; // Prefix used for tables/fields when deleted/renamed.
47
48 /**
49 * @var array Tables starting with this name are ignored during compare
50 */
51 var $ignoreTablePrefixes = array(
52 'cachingframework_',
53 );
54
55 var $dbUpdateCheckboxPrefix = 'TYPO3_INSTALL[database_update]'; // Prefix for checkbox fields when updating database.
56 var $localconf_addLinesOnly = 0; // 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.
57 var $localconf_editPointToken = 'INSTALL SCRIPT EDIT POINT TOKEN - all lines after this points may be changed by the install script!'; // If set and addLinesOnly is disabled, lines will be change only if they are after this token (on a single line!) in the file
58 var $allowUpdateLocalConf = 0; // If TRUE, this class will allow the user to update the localconf.php file. Is set TRUE in the init.php file.
59 var $backPath = '../'; // Backpath (used for icons etc.)
60
61 var $multiplySize = 1; // Multiplier of SQL field size (for char, varchar and text fields)
62 var $character_sets = array(); // Caching output of $GLOBALS['TYPO3_DB']->admin_get_charsets()
63
64 // Internal, dynamic:
65 var $setLocalconf = 0; // Used to indicate that a value is change in the line-array of localconf and that it should be written.
66 var $messages = array(); // Used to set (error)messages from the executing functions like mail-sending, writing Localconf and such
67 var $touchedLine = 0; // updated with line in localconf.php file that was changed.
68
69
70 /**
71 * Constructor function
72 *
73 * @return void
74 */
75 function __construct() {
76 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['multiplyDBfieldSize'] >= 1 && $GLOBALS['TYPO3_CONF_VARS']['SYS']['multiplyDBfieldSize'] <= 5) {
77 $this->multiplySize = (double) $GLOBALS['TYPO3_CONF_VARS']['SYS']['multiplyDBfieldSize'];
78 }
79 }
80
81
82 /**************************************
83 *
84 * Writing to localconf.php
85 *
86
87 **************************************/
88
89 /**
90 * This functions takes an array with lines from localconf.php, finds a variable and inserts the new value.
91 *
92 * @param array $line_array the localconf.php file exploded into an array by linebreaks. (see writeToLocalconf_control())
93 * @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.
94 * @param string $value Is the value to be insert for the variable
95 * @param boolean $quoteValue Whether the given value should be quoted before being written
96 * @return void
97 * @see writeToLocalconf_control()
98 */
99 public function setValueInLocalconfFile(&$line_array, $variable, $value, $quoteValue = TRUE) {
100 if (!$this->checkForBadString($value)) {
101 return 0;
102 }
103
104 // Initialize:
105 $found = 0;
106 $this->touchedLine = '';
107 $commentKey = '## ';
108 $inArray = in_array($commentKey . $this->localconf_editPointToken, $line_array);
109 $tokenSet = ($this->localconf_editPointToken && !$inArray); // Flag is set if the token should be set but is not yet...
110 $stopAtToken = ($this->localconf_editPointToken && $inArray);
111 $comment = ' Modified or inserted by ' . $this->updateIdentity . '.';
112 $replace = array('["', '"]');
113 $search = array('[\'', '\']');
114 $varDoubleQuotes = str_replace($search, $replace, $variable);
115
116 // Search for variable name:
117 if (!$this->localconf_addLinesOnly && !$tokenSet) {
118 $line_array = array_reverse($line_array);
119 foreach ($line_array as $k => $v) {
120 $v2 = trim($v);
121 if ($stopAtToken && !strcmp($v2, $commentKey . $this->localconf_editPointToken)) {
122 break;
123 } // If stopAtToken and token found, break out of the loop..
124 if (!strcmp(substr($v2, 0, strlen($variable . ' ')), $variable . ' ')) {
125 $mainparts = explode($variable, $v, 2);
126 if (count($mainparts) == 2) { // should ALWAYS be....
127 $subparts = explode('//', $mainparts[1], 2);
128 if ($quoteValue) {
129 $value = '\'' . $this->slashValueForSingleDashes($value) . '\'';
130 }
131 $line_array[$k] = $mainparts[0] . $variable . " = " . $value . "; " . ('//' . $comment . str_replace($comment, '', $subparts[1]));
132 $this->touchedLine = count($line_array) - $k - 1;
133 $found = 1;
134 break;
135 }
136 } elseif (!strcmp(substr($v2, 0, strlen($varDoubleQuotes . ' ')), $varDoubleQuotes . ' ')) {
137 // Due to a bug in the update wizard (fixed in TYPO3 4.1.7) it is possible
138 // that $TYPO3_CONF_VARS['SYS']['compat_version'] was enclosed by "" (double
139 // quotes) instead of the expected '' (single quotes) when is was written to
140 // localconf.php. The following code was added to make sure that values with
141 // double quotes are updated, too.
142 $mainparts = explode($varDoubleQuotes, $v, 2);
143 if (count($mainparts) == 2) { // should ALWAYS be....
144 $subparts = explode('//', $mainparts[1], 2);
145 if ($quoteValue) {
146 $value = '\'' . $this->slashValueForSingleDashes($value) . '\'';
147 }
148 $line_array[$k] = $mainparts[0] . $variable . " = " . $value . "; " . ('//' . $comment . str_replace($comment, '', $subparts[1]));
149 $this->touchedLine = count($line_array) - $k - 1;
150 $found = 1;
151 break;
152 }
153 }
154 }
155 $line_array = array_reverse($line_array);
156 }
157 if (!$found) {
158 if ($tokenSet) {
159 $line_array[] = $commentKey . $this->localconf_editPointToken;
160 $line_array[] = '';
161 }
162 if ($quoteValue) {
163 $value = '\'' . $this->slashValueForSingleDashes($value) . '\'';
164 }
165 $line_array[] = $variable . " = " . $value . "; // " . $comment;
166 $this->touchedLine = -1;
167 }
168 if ($variable == '$typo_db_password') {
169 $this->messages[] = 'Updated ' . $variable;
170 } else {
171 $this->messages[] = $variable . " = " . htmlspecialchars($value);
172 }
173 $this->setLocalconf = 1;
174 }
175
176 /**
177 * Takes an array with lines from localconf.php, finds a variable and inserts the new array value.
178 *
179 * @param array $lines the localconf.php file exploded into an array by line breaks. {@see writeToLocalconf_control()}
180 * @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.
181 * @param array $value value to be assigned to the variable
182 * @return void
183 * @see writeToLocalconf_control()
184 */
185 public function setArrayValueInLocalconfFile(array &$lines, $variable, array $value) {
186 $commentKey = '## ';
187 $inArray = in_array($commentKey . $this->localconf_editPointToken, $lines);
188 $tokenSet = $this->localconf_editPointToken && !$inArray; // Flag is set if the token should be set but is not yet
189 $stopAtToken = $this->localconf_editPointToken && $inArray;
190 $comment = 'Modified or inserted by ' . $this->updateIdentity . '.';
191 $format = "%s = %s;\t// " . $comment;
192
193 $insertPos = count($lines);
194 $startPos = 0;
195 if (!($this->localconf_addLinesOnly || $tokenSet)) {
196 for ($i = count($lines) - 1; $i > 0; $i--) {
197 $line = trim($lines[$i]);
198 if ($stopAtToken && t3lib_div::isFirstPartOfStr($line, $this->localconf_editPointToken)) {
199 break;
200 }
201 if (t3lib_div::isFirstPartOfStr($line, '?>')) {
202 $insertPos = $i;
203 }
204 if (t3lib_div::isFirstPartOfStr($line, $variable)) {
205 $startPos = $i;
206 break;
207 }
208 }
209 }
210 if ($startPos) {
211 $this->touchedLine = $startPos;
212 $endPos = $startPos;
213 for ($i = $startPos; $i < count($lines); $i++) {
214 $line = trim($lines[$i]);
215 if (t3lib_div::isFirstPartOfStr($line, ');')) {
216 $endPos = $i;
217 break;
218 }
219 }
220
221 $startLines = array_slice($lines, 0, $startPos);
222 $endLines = array_slice($lines, $endPos + 1);
223
224 $lines = $startLines;
225 $definition = $this->array_export($value);
226 $lines[] = sprintf($format, $variable, $definition);
227 foreach ($endLines as $line) {
228 $lines[] = $line;
229 }
230 } else {
231 $lines[$insertPos] = sprintf($format, $variable, $this->array_export($value));
232 $lines[] = '?>';
233 $this->touchedLine = -1;
234 }
235 }
236
237 /**
238 * Returns a parsable string representation of an array variable. This methods enhances
239 * standard method var_export from PHP to take TYPO3's CGL into account.
240 *
241 * @param array $variable
242 * @return string
243 */
244 protected function array_export(array $variable) {
245 $lines = explode("\n", var_export($variable, TRUE));
246 $out = 'array(';
247
248 for ($i = 1; $i < count($lines); $i++) {
249 $out .= "\n";
250 // Make the space-indented declaration tab-indented instead
251 while (substr($lines[$i], 0, 2) === ' ') {
252 $out .= "\t";
253 $lines[$i] = substr($lines[$i], 2);
254 }
255 $out .= $lines[$i];
256 // Array declaration should be next to the assignment and no space between
257 // "array" and its opening parenthesis should exist
258 if (preg_match('/\s=>\s$/', $lines[$i])) {
259 $out .= preg_replace('/^\s*array \(/', 'array(', $lines[$i + 1]);
260 $i++;
261 }
262 }
263
264 return $out;
265 }
266
267 /**
268 * Writes or returns lines from localconf.php
269 *
270 * @param array Array of lines to write back to localconf.php. Possibly
271 * @param string Absolute path of alternative file to use (Notice: this path is not validated in terms of being inside 'TYPO3 space')
272 * @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)
273 * @see setValueInLocalconfFile()
274 */
275 function writeToLocalconf_control($inlines = '', $absFullPath = '') {
276 $tmpExt = '.TMP.php';
277 $writeToLocalconf_dat = array();
278 $writeToLocalconf_dat['file'] = $absFullPath ? $absFullPath : PATH_typo3conf . 'localconf.php';
279 $writeToLocalconf_dat['tmpfile'] = $writeToLocalconf_dat['file'] . $tmpExt;
280
281 // Checking write state of localconf.php:
282 if (!$this->allowUpdateLocalConf) {
283 throw new RuntimeException(
284 'TYPO3 Fatal Error: ->allowUpdateLocalConf flag in the install object is not set and therefore "localconf.php" cannot be altered.',
285 1270853915
286 );
287 }
288 if (!@is_writable($writeToLocalconf_dat['file'])) {
289 throw new RuntimeException(
290 'TYPO3 Fatal Error: ' . $writeToLocalconf_dat['file'] . ' is not writable!',
291 1270853916
292 );
293 }
294
295 // Splitting localconf.php file into lines:
296 $lines = explode(LF, str_replace(CR, '', trim(t3lib_div::getUrl($writeToLocalconf_dat['file']))));
297 $writeToLocalconf_dat['endLine'] = array_pop($lines); // Getting "? >" ending.
298
299 // Checking if "updated" line was set by this tool - if so remove old line.
300 $updatedLine = array_pop($lines);
301 $writeToLocalconf_dat['updatedText'] = '// Updated by ' . $this->updateIdentity . ' ';
302
303 if (!strstr($updatedLine, $writeToLocalconf_dat['updatedText'])) {
304 array_push($lines, $updatedLine);
305 }
306
307 if (is_array($inlines)) { // Setting a line and write:
308 // Setting configuration
309 $updatedLine = $writeToLocalconf_dat['updatedText'] . date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' H:i:s');
310 array_push($inlines, $updatedLine);
311 array_push($inlines, $writeToLocalconf_dat['endLine']);
312
313 if ($this->setLocalconf) {
314 $success = $this->writeToLocalconf($inlines, $absFullPath);
315
316 if ($success) {
317 return 'continue';
318 } else {
319 return 'nochange';
320 }
321 } else {
322 return 'nochange';
323 }
324 } else { // Return lines found in localconf.php
325 return $lines;
326 }
327 }
328
329 /**
330 * Writes lines to localconf.php.
331 *
332 * @param array Array of lines to write back to localconf.php
333 * @param string Absolute path of alternative file to use (Notice: this path is not validated in terms of being inside 'TYPO3 space')
334 * @return boolean TRUE if method succeeded, otherwise FALSE
335 */
336 public function writeToLocalconf(array $lines, $absFullPath = '') {
337 $tmpExt = '.TMP.php';
338 $writeToLocalconf_dat = array();
339 $writeToLocalconf_dat['file'] = $absFullPath ? $absFullPath : PATH_typo3conf . 'localconf.php';
340 $writeToLocalconf_dat['tmpfile'] = $writeToLocalconf_dat['file'] . $tmpExt;
341
342 // Checking write state of localconf.php:
343 if (!$this->allowUpdateLocalConf) {
344 throw new RuntimeException(
345 'TYPO3 Fatal Error: ->allowUpdateLocalConf flag in the install object is not set and therefore "localconf.php" cannot be altered.',
346 1270853915
347 );
348 }
349 if (!@is_writable($writeToLocalconf_dat['file'])) {
350 throw new RuntimeException(
351 'TYPO3 Fatal Error: ' . $writeToLocalconf_dat['file'] . ' is not writable!',
352 1270853916
353 );
354 }
355
356 $writeToLocalconf_dat['endLine'] = array_pop($lines); // Getting "? >" ending.
357 if (!strstr('?' . '>', $writeToLocalconf_dat['endLine'])) {
358 $lines[] = $writeToLocalconf_dat['endLine'];
359 $writeToLocalconf_dat['endLine'] = '?' . '>';
360 }
361 // Checking if "updated" line was set by this tool - if so remove old line.
362 $updatedLine = array_pop($lines);
363 $writeToLocalconf_dat['updatedText'] = '// Updated by ' . $this->updateIdentity . ' ';
364
365 if (!strstr($updatedLine, $writeToLocalconf_dat['updatedText'])) {
366 $lines[] = $updatedLine;
367 }
368
369 $updatedLine = $writeToLocalconf_dat['updatedText'] . date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' H:i:s');
370 $lines[] = $updatedLine;
371 $lines[] = $writeToLocalconf_dat['endLine'];
372
373 $success = FALSE;
374 if (!t3lib_div::writeFile($writeToLocalconf_dat['tmpfile'], implode(LF, $lines))) {
375 $msg = 'typo3conf/localconf.php' . $tmpExt . ' could not be written - maybe a write access problem?';
376 }
377 elseif (strcmp(t3lib_div::getUrl($writeToLocalconf_dat['tmpfile']), implode(LF, $lines))) {
378 @unlink($writeToLocalconf_dat['tmpfile']);
379 $msg = 'typo3conf/localconf.php' . $tmpExt . ' was NOT written properly (written content didn\'t match file content) - maybe a disk space problem?';
380 }
381 elseif (!@copy($writeToLocalconf_dat['tmpfile'], $writeToLocalconf_dat['file'])) {
382 $msg = 'typo3conf/localconf.php could not be replaced by typo3conf/localconf.php' . $tmpExt . ' - maybe a write access problem?';
383 }
384 else {
385 @unlink($writeToLocalconf_dat['tmpfile']);
386 $success = TRUE;
387 $msg = 'Configuration written to typo3conf/localconf.php';
388 }
389 $this->messages[] = $msg;
390
391 if (!$success) {
392 t3lib_div::sysLog($msg, 'Core', 3);
393 }
394
395 return $success;
396 }
397
398 /**
399 * Checking for linebreaks in the string
400 *
401 * @param string String to test
402 * @return boolean Returns TRUE if string is OK
403 * @see setValueInLocalconfFile()
404 */
405 function checkForBadString($string) {
406 return preg_match('/[' . LF . CR . ']/', $string) ? FALSE : TRUE;
407 }
408
409 /**
410 * Replaces ' with \' and \ with \\
411 *
412 * @param string Input value
413 * @return string Output value
414 * @see setValueInLocalconfFile()
415 */
416 function slashValueForSingleDashes($value) {
417 $value = str_replace("'.LF.'", '###INSTALL_TOOL_LINEBREAK###', $value);
418 $value = str_replace("'", "\'", str_replace('\\', '\\\\', $value));
419 $value = str_replace('###INSTALL_TOOL_LINEBREAK###', "'.LF.'", $value);
420
421 return $value;
422 }
423
424
425 /*************************************
426 *
427 * SQL
428 *
429 *************************************/
430
431 /**
432 * Reads the field definitions for the input SQL-file string
433 *
434 * @param string Should be a string read from an SQL-file made with 'mysqldump [database_name] -d'
435 * @return array Array with information about table.
436 */
437 function getFieldDefinitions_fileContent($fileContent) {
438 $lines = t3lib_div::trimExplode(LF, $fileContent, 1);
439 $table = '';
440 $total = array();
441
442 foreach ($lines as $value) {
443 if (substr($value, 0, 1) == '#') {
444 continue; // Ignore comments
445 }
446
447 if (!strlen($table)) {
448 $parts = t3lib_div::trimExplode(' ', $value, TRUE);
449 if (strtoupper($parts[0]) === 'CREATE' && strtoupper($parts[1]) === 'TABLE') {
450 $table = str_replace('`', '', $parts[2]);
451 if (TYPO3_OS == 'WIN') { // tablenames are always lowercase on windows!
452 $table = strtolower($table);
453 }
454 }
455 } else {
456 if (substr($value, 0, 1) == ')' && substr($value, -1) == ';') {
457 $ttype = array();
458 if (preg_match('/(ENGINE|TYPE)[ ]*=[ ]*([a-zA-Z]*)/', $value, $ttype)) {
459 $total[$table]['extra']['ENGINE'] = $ttype[2];
460 } // Otherwise, just do nothing: If table engine is not defined, just accept the system default.
461
462 // Set the collation, if specified
463 if (preg_match('/(COLLATE)[ ]*=[ ]*([a-zA-z0-9_-]+)/', $value, $tcollation)) {
464 $total[$table]['extra']['COLLATE'] = $tcollation[2];
465 } else {
466 // Otherwise, get the CHARACTER SET and try to find the default collation for it as returned by "SHOW CHARACTER SET" query (for details, see http://dev.mysql.com/doc/refman/5.1/en/charset-table.html)
467 if (preg_match('/(CHARSET|CHARACTER SET)[ ]*=[ ]*([a-zA-z0-9_-]+)/', $value, $tcharset)) { // Note: Keywords "DEFAULT CHARSET" and "CHARSET" are the same, so "DEFAULT" can just be ignored
468 $charset = $tcharset[2];
469 } else {
470 $charset = $GLOBALS['TYPO3_DB']->default_charset; // Fallback to default charset
471 }
472 $total[$table]['extra']['COLLATE'] = $this->getCollationForCharset($charset);
473 }
474
475 $table = ''; // Remove table marker and start looking for the next "CREATE TABLE" statement
476 } else {
477 $lineV = preg_replace('/,$/', '', $value); // Strip trailing commas
478 $lineV = str_replace('`', '', $lineV);
479 $lineV = str_replace(' ', ' ', $lineV); // Remove double blanks
480
481 $parts = explode(' ', $lineV, 2);
482 if (!preg_match('/(PRIMARY|UNIQUE|FULLTEXT|INDEX|KEY)/', $parts[0])) { // Field definition
483
484 // Make sure there is no default value when auto_increment is set
485 if (stristr($parts[1], 'auto_increment')) {
486 $parts[1] = preg_replace('/ default \'0\'/i', '', $parts[1]);
487 }
488 // "default" is always lower-case
489 if (stristr($parts[1], ' DEFAULT ')) {
490 $parts[1] = str_ireplace(' DEFAULT ', ' default ', $parts[1]);
491 }
492
493 // Change order of "default" and "NULL" statements
494 $parts[1] = preg_replace('/(.*) (default .*) (NOT NULL)/', '$1 $3 $2', $parts[1]);
495 $parts[1] = preg_replace('/(.*) (default .*) (NULL)/', '$1 $3 $2', $parts[1]);
496
497 $key = $parts[0];
498 $total[$table]['fields'][$key] = $parts[1];
499
500 } else { // Key definition
501 $search = array('/UNIQUE (INDEX|KEY)/', '/FULLTEXT (INDEX|KEY)/', '/INDEX/');
502 $replace = array('UNIQUE', 'FULLTEXT', 'KEY');
503 $lineV = preg_replace($search, $replace, $lineV);
504
505 if (preg_match('/PRIMARY|UNIQUE|FULLTEXT/', $parts[0])) {
506 $parts[1] = preg_replace('/^(KEY|INDEX) /', '', $parts[1]);
507 }
508
509 $newParts = explode(' ', $parts[1], 2);
510 $key = $parts[0] == 'PRIMARY' ? $parts[0] : $newParts[0];
511
512 $total[$table]['keys'][$key] = $lineV;
513
514 // This is a protection against doing something stupid: Only allow clearing of cache_* and index_* tables.
515 if (preg_match('/^(cache|index)_/', $table)) {
516 // Suggest to truncate (clear) this table
517 $total[$table]['extra']['CLEAR'] = 1;
518 }
519 }
520 }
521 }
522 }
523
524 $this->getFieldDefinitions_sqlContent_parseTypes($total);
525 return $total;
526 }
527
528 /**
529 * Multiplies varchars/tinytext fields in size according to $this->multiplySize
530 * Useful if you want to use UTF-8 in the database and needs to extend the field sizes in the database so UTF-8 chars are not discarded. For most charsets available as single byte sets, multiplication with 2 should be enough. For chinese, use 3.
531 *
532 * @param array Total array (from getFieldDefinitions_fileContent())
533 * @return void
534 * @access private
535 * @see getFieldDefinitions_fileContent()
536 */
537 function getFieldDefinitions_sqlContent_parseTypes(&$total) {
538
539 $mSize = (double) $this->multiplySize;
540 if ($mSize > 1) {
541
542 // Init SQL parser:
543 $sqlParser = t3lib_div::makeInstance('t3lib_sqlparser');
544 foreach ($total as $table => $cfg) {
545 if (is_array($cfg['fields'])) {
546 foreach ($cfg['fields'] as $fN => $fType) {
547 $orig_fType = $fType;
548 $fInfo = $sqlParser->parseFieldDef($fType);
549
550 switch ($fInfo['fieldType']) {
551 case 'char':
552 case 'varchar':
553 $newSize = round($fInfo['value'] * $mSize);
554
555 if ($newSize <= 255) {
556 $fInfo['value'] = $newSize;
557 } else {
558 $fInfo = array(
559 'fieldType' => 'text',
560 'featureIndex' => array(
561 'NOTNULL' => array(
562 'keyword' => 'NOT NULL'
563 )
564 )
565 );
566 // Change key definition if necessary (must use "prefix" on TEXT columns)
567 if (is_array($cfg['keys'])) {
568 foreach ($cfg['keys'] as $kN => $kType) {
569 $match = array();
570 preg_match('/^([^(]*)\(([^)]+)\)(.*)/', $kType, $match);
571 $keys = array();
572 foreach (t3lib_div::trimExplode(',', $match[2]) as $kfN) {
573 if ($fN == $kfN) {
574 $kfN .= '(' . $newSize . ')';
575 }
576 $keys[] = $kfN;
577 }
578 $total[$table]['keys'][$kN] = $match[1] . '(' . implode(',', $keys) . ')' . $match[3];
579 }
580 }
581 }
582 break;
583 case 'tinytext':
584 $fInfo['fieldType'] = 'text';
585 break;
586 }
587
588 $total[$table]['fields'][$fN] = $sqlParser->compileFieldCfg($fInfo);
589 if ($sqlParser->parse_error) {
590 throw new RuntimeException(
591 'TYPO3 Fatal Error: ' . $sqlParser->parse_error,
592 1270853961
593 );
594 }
595 }
596 }
597 }
598 }
599 }
600
601 /**
602 * Look up the default collation for specified character set based on "SHOW CHARACTER SET" output
603 *
604 * @param string Character set
605 * @return string Corresponding default collation
606 */
607 function getCollationForCharset($charset) {
608 // Load character sets, if not cached already
609 if (!count($this->character_sets)) {
610 if (method_exists($GLOBALS['TYPO3_DB'], 'admin_get_charsets')) {
611 $this->character_sets = $GLOBALS['TYPO3_DB']->admin_get_charsets();
612 } else {
613 $this->character_sets[$charset] = array(); // Add empty element to avoid that the check will be repeated
614 }
615 }
616
617 $collation = '';
618 if (isset($this->character_sets[$charset]['Default collation'])) {
619 $collation = $this->character_sets[$charset]['Default collation'];
620 }
621
622 return $collation;
623 }
624
625 /**
626 * Reads the field definitions for the current database
627 *
628 * @return array Array with information about table.
629 */
630 function getFieldDefinitions_database() {
631 $total = array();
632 $tempKeys = array();
633 $tempKeysPrefix = array();
634
635 $GLOBALS['TYPO3_DB']->sql_select_db(TYPO3_db);
636 echo $GLOBALS['TYPO3_DB']->sql_error();
637
638 $tables = $GLOBALS['TYPO3_DB']->admin_get_tables(TYPO3_db);
639 foreach ($tables as $tableName => $tableStatus) {
640
641 // Fields:
642 $fieldInformation = $GLOBALS['TYPO3_DB']->admin_get_fields($tableName);
643 foreach ($fieldInformation as $fN => $fieldRow) {
644 $total[$tableName]['fields'][$fN] = $this->assembleFieldDefinition($fieldRow);
645 }
646
647 // Keys:
648 $keyInformation = $GLOBALS['TYPO3_DB']->admin_get_keys($tableName);
649
650 foreach ($keyInformation as $keyRow) {
651 $keyName = $keyRow['Key_name'];
652 $colName = $keyRow['Column_name'];
653 if ($keyRow['Sub_part']) {
654 $colName .= '(' . $keyRow['Sub_part'] . ')';
655 }
656 $tempKeys[$tableName][$keyName][$keyRow['Seq_in_index']] = $colName;
657 if ($keyName == 'PRIMARY') {
658 $prefix = 'PRIMARY KEY';
659 } else {
660 if ($keyRow['Index_type'] == 'FULLTEXT') {
661 $prefix = 'FULLTEXT';
662 } elseif ($keyRow['Non_unique']) {
663 $prefix = 'KEY';
664 } else {
665 $prefix = 'UNIQUE';
666 }
667 $prefix .= ' ' . $keyName;
668 }
669 $tempKeysPrefix[$tableName][$keyName] = $prefix;
670 }
671
672 // Table status (storage engine, collaction, etc.)
673 if (is_array($tableStatus)) {
674 $tableExtraFields = array(
675 'Engine' => 'ENGINE',
676 'Collation' => 'COLLATE',
677 );
678
679 foreach ($tableExtraFields as $mysqlKey => $internalKey) {
680 if (isset($tableStatus[$mysqlKey])) {
681 $total[$tableName]['extra'][$internalKey] = $tableStatus[$mysqlKey];
682 }
683 }
684 }
685 }
686
687 // Compile key information:
688 if (count($tempKeys)) {
689 foreach ($tempKeys as $table => $keyInf) {
690 foreach ($keyInf as $kName => $index) {
691 ksort($index);
692 $total[$table]['keys'][$kName] = $tempKeysPrefix[$table][$kName] . ' (' . implode(',', $index) . ')';
693 }
694 }
695 }
696
697 return $total;
698 }
699
700 /**
701 * Compares two arrays with field information and returns information about fields that are MISSING and fields that have CHANGED.
702 * FDsrc and FDcomp can be switched if you want the list of stuff to remove rather than update.
703 *
704 * @param array Field definitions, source (from getFieldDefinitions_fileContent())
705 * @param array Field definitions, comparison. (from getFieldDefinitions_database())
706 * @param string Table names (in list) which is the ONLY one observed.
707 * @param boolean If set, this function ignores NOT NULL statements of the SQL file field definition when comparing current field definition from database with field definition from SQL file. This way, NOT NULL statements will be executed when the field is initially created, but the SQL parser will never complain about missing NOT NULL statements afterwards.
708 * @return array Returns an array with 1) all elements from $FDsrc that is not in $FDcomp (in key 'extra') and 2) all elements from $FDsrc that is different from the ones in $FDcomp
709 */
710 function getDatabaseExtra($FDsrc, $FDcomp, $onlyTableList = '', $ignoreNotNullWhenComparing = TRUE) {
711 $extraArr = array();
712 $diffArr = array();
713
714 if (is_array($FDsrc)) {
715 foreach ($FDsrc as $table => $info) {
716 if (!strlen($onlyTableList) || t3lib_div::inList($onlyTableList, $table)) {
717 if (!isset($FDcomp[$table])) {
718 $extraArr[$table] = $info; // If the table was not in the FDcomp-array, the result array is loaded with that table.
719 $extraArr[$table]['whole_table'] = 1;
720 } else {
721 $keyTypes = explode(',', 'extra,fields,keys');
722 foreach ($keyTypes as $theKey) {
723 if (is_array($info[$theKey])) {
724 foreach ($info[$theKey] as $fieldN => $fieldC) {
725 $fieldN = str_replace('`', '', $fieldN);
726 if ($fieldN == 'COLLATE') {
727 continue; // TODO: collation support is currently disabled (needs more testing)
728 }
729
730 if (!isset($FDcomp[$table][$theKey][$fieldN])) {
731 $extraArr[$table][$theKey][$fieldN] = $fieldC;
732 } else {
733 $fieldC = trim($fieldC);
734 if ($ignoreNotNullWhenComparing) {
735 $fieldC = str_replace(' NOT NULL', '', $fieldC);
736 $FDcomp[$table][$theKey][$fieldN] = str_replace(' NOT NULL', '', $FDcomp[$table][$theKey][$fieldN]);
737 }
738 if ($fieldC !== $FDcomp[$table][$theKey][$fieldN]) {
739 $diffArr[$table][$theKey][$fieldN] = $fieldC;
740 $diffArr_cur[$table][$theKey][$fieldN] = $FDcomp[$table][$theKey][$fieldN];
741 }
742 }
743 }
744 }
745 }
746 }
747 }
748 }
749 }
750
751 $output = array(
752 'extra' => $extraArr,
753 'diff' => $diffArr,
754 'diff_currentValues' => $diffArr_cur
755 );
756
757 return $output;
758 }
759
760 /**
761 * Returns an array with SQL-statements that is needed to update according to the diff-array
762 *
763 * @param array Array with differences of current and needed DB settings. (from getDatabaseExtra())
764 * @param string List of fields in diff array to take notice of.
765 * @return array Array of SQL statements (organized in keys depending on type)
766 */
767 function getUpdateSuggestions($diffArr, $keyList = 'extra,diff') {
768 $statements = array();
769 $deletedPrefixKey = $this->deletedPrefixKey;
770 $remove = 0;
771 if ($keyList == 'remove') {
772 $remove = 1;
773 $keyList = 'extra';
774 }
775 $keyList = explode(',', $keyList);
776 foreach ($keyList as $theKey) {
777 if (is_array($diffArr[$theKey])) {
778 foreach ($diffArr[$theKey] as $table => $info) {
779 $whole_table = array();
780 if (is_array($info['fields'])) {
781 foreach ($info['fields'] as $fN => $fV) {
782 if ($info['whole_table']) {
783 $whole_table[] = $fN . ' ' . $fV;
784 } else {
785 // Special case to work around MySQL problems when adding auto_increment fields:
786 if (stristr($fV, 'auto_increment')) {
787 // The field can only be set "auto_increment" if there exists a PRIMARY key of that field already.
788 // The check does not look up which field is primary but just assumes it must be the field with the auto_increment value...
789 if (isset($diffArr['extra'][$table]['keys']['PRIMARY'])) {
790 // Remove "auto_increment" from the statement - it will be suggested in a 2nd step after the primary key was created
791 $fV = str_replace(' auto_increment', '', $fV);
792 } else {
793 // In the next step, attempt to clear the table once again (2 = force)
794 $info['extra']['CLEAR'] = 2;
795 }
796 }
797 if ($theKey == 'extra') {
798 if ($remove) {
799 if (substr($fN, 0, strlen($deletedPrefixKey)) != $deletedPrefixKey) {
800 $statement = 'ALTER TABLE ' . $table . ' CHANGE ' . $fN . ' ' . $deletedPrefixKey . $fN . ' ' . $fV . ';';
801 $statements['change'][md5($statement)] = $statement;
802 } else {
803 $statement = 'ALTER TABLE ' . $table . ' DROP ' . $fN . ';';
804 $statements['drop'][md5($statement)] = $statement;
805 }
806 } else {
807 $statement = 'ALTER TABLE ' . $table . ' ADD ' . $fN . ' ' . $fV . ';';
808 $statements['add'][md5($statement)] = $statement;
809 }
810 } elseif ($theKey == 'diff') {
811 $statement = 'ALTER TABLE ' . $table . ' CHANGE ' . $fN . ' ' . $fN . ' ' . $fV . ';';
812 $statements['change'][md5($statement)] = $statement;
813 $statements['change_currentValue'][md5($statement)] = $diffArr['diff_currentValues'][$table]['fields'][$fN];
814 }
815 }
816 }
817 }
818 if (is_array($info['keys'])) {
819 foreach ($info['keys'] as $fN => $fV) {
820 if ($info['whole_table']) {
821 $whole_table[] = $fV;
822 } else {
823 if ($theKey == 'extra') {
824 if ($remove) {
825 $statement = 'ALTER TABLE ' . $table . ($fN == 'PRIMARY' ? ' DROP PRIMARY KEY' : ' DROP KEY ' . $fN) . ';';
826 $statements['drop'][md5($statement)] = $statement;
827 } else {
828 $statement = 'ALTER TABLE ' . $table . ' ADD ' . $fV . ';';
829 $statements['add'][md5($statement)] = $statement;
830 }
831 } elseif ($theKey == 'diff') {
832 $statement = 'ALTER TABLE ' . $table . ($fN == 'PRIMARY' ? ' DROP PRIMARY KEY' : ' DROP KEY ' . $fN) . ';';
833 $statements['change'][md5($statement)] = $statement;
834 $statement = 'ALTER TABLE ' . $table . ' ADD ' . $fV . ';';
835 $statements['change'][md5($statement)] = $statement;
836 }
837 }
838 }
839 }
840 if (is_array($info['extra'])) {
841 $extras = array();
842 $extras_currentValue = array();
843 $clear_table = FALSE;
844
845 foreach ($info['extra'] as $fN => $fV) {
846
847 // Only consider statements which are missing in the database but don't remove existing properties
848 if (!$remove) {
849 if (!$info['whole_table']) { // If the whole table is created at once, we take care of this later by imploding all elements of $info['extra']
850 if ($fN == 'CLEAR') {
851 // Truncate table must happen later, not now
852 // Valid values for CLEAR: 1=only clear if keys are missing, 2=clear anyway (force)
853 if (count($info['keys']) || $fV == 2) {
854 $clear_table = TRUE;
855 }
856 continue;
857 } else {
858 $extras[] = $fN . '=' . $fV;
859 $extras_currentValue[] = $fN . '=' . $diffArr['diff_currentValues'][$table]['extra'][$fN];
860 }
861 }
862 }
863 }
864 if ($clear_table) {
865 $statement = 'TRUNCATE TABLE ' . $table . ';';
866 $statements['clear_table'][md5($statement)] = $statement;
867 }
868 if (count($extras)) {
869 $statement = 'ALTER TABLE ' . $table . ' ' . implode(' ', $extras) . ';';
870 $statements['change'][md5($statement)] = $statement;
871 $statements['change_currentValue'][md5($statement)] = implode(' ', $extras_currentValue);
872 }
873 }
874 if ($info['whole_table']) {
875 if ($remove) {
876 if (substr($table, 0, strlen($deletedPrefixKey)) != $deletedPrefixKey) {
877 // Ignore table operation if the table name starts with a
878 // prefix that should be ignored
879 $ignoreTable = FALSE;
880 foreach ($this->ignoreTablePrefixes as $ignorePrefix) {
881 if (substr($table, 0, strlen($ignorePrefix)) === $ignorePrefix) {
882 $ignoreTable = TRUE;
883 break;
884 }
885 }
886 if (!$ignoreTable) {
887 $statement = 'ALTER TABLE ' . $table . ' RENAME ' . $deletedPrefixKey . $table . ';';
888 $statements['change_table'][md5($statement)] = $statement;
889 }
890 } else {
891 $statement = 'DROP TABLE ' . $table . ';';
892 $statements['drop_table'][md5($statement)] = $statement;
893 }
894 // count:
895 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $table);
896 $statements['tables_count'][md5($statement)] = $count ? 'Records in table: ' . $count : '';
897 } else {
898 $statement = 'CREATE TABLE ' . $table . " (\n" . implode(",\n", $whole_table) . "\n)";
899 if ($info['extra']) {
900 foreach ($info['extra'] as $k => $v) {
901 if ($k == 'COLLATE' || $k == 'CLEAR') {
902 continue; // Skip these special statements. TODO: collation support is currently disabled (needs more testing)
903 }
904 $statement .= ' ' . $k . '=' . $v; // Add extra attributes like ENGINE, CHARSET, etc.
905 }
906 }
907 $statement .= ';';
908 $statements['create_table'][md5($statement)] = $statement;
909 }
910 }
911 }
912 }
913 }
914
915 return $statements;
916 }
917
918 /**
919 * Converts a result row with field information into the SQL field definition string
920 *
921 * @param array MySQL result row
922 * @return string Field definition
923 */
924 function assembleFieldDefinition($row) {
925 $field = array($row['Type']);
926
927 if ($row['Null'] == 'NO') {
928 $field[] = 'NOT NULL';
929 }
930 if (!strstr($row['Type'], 'blob') && !strstr($row['Type'], 'text')) {
931 // Add a default value if the field is not auto-incremented (these fields never have a default definition)
932 if (!stristr($row['Extra'], 'auto_increment')) {
933 $field[] = 'default \'' . addslashes($row['Default']) . '\'';
934 }
935 }
936 if ($row['Extra']) {
937 $field[] = $row['Extra'];
938 }
939
940 return implode(' ', $field);
941 }
942
943 /**
944 * Returns an array where every entry is a single SQL-statement. Input must be formatted like an ordinary MySQL-dump files.
945 *
946 * @param string The SQL-file content. Provided that 1) every query in the input is ended with ';' and that a line in the file contains only one query or a part of a query.
947 * @param boolean If set, non-SQL content (like comments and blank lines) is not included in the final output
948 * @param string Regex to filter SQL lines to include
949 * @return array Array of SQL statements
950 */
951 function getStatementArray($sqlcode, $removeNonSQL = 0, $query_regex = '') {
952 $sqlcodeArr = explode(LF, $sqlcode);
953
954 // Based on the assumption that the sql-dump has
955 $statementArray = array();
956 $statementArrayPointer = 0;
957
958 foreach ($sqlcodeArr as $line => $lineContent) {
959 $is_set = 0;
960
961 // auto_increment fields cannot have a default value!
962 if (stristr($lineContent, 'auto_increment')) {
963 $lineContent = preg_replace('/ default \'0\'/i', '', $lineContent);
964 }
965
966 if (!$removeNonSQL || (strcmp(trim($lineContent), '') && substr(trim($lineContent), 0, 1) != '#' && substr(trim($lineContent), 0, 2) != '--')) { // '--' is seen as mysqldump comments from server version 3.23.49
967 $statementArray[$statementArrayPointer] .= $lineContent;
968 $is_set = 1;
969 }
970 if (substr(trim($lineContent), -1) == ';') {
971 if (isset($statementArray[$statementArrayPointer])) {
972 if (!trim($statementArray[$statementArrayPointer]) || ($query_regex && !preg_match('/' . $query_regex . '/i', trim($statementArray[$statementArrayPointer])))) {
973 unset($statementArray[$statementArrayPointer]);
974 }
975 }
976 $statementArrayPointer++;
977
978 } elseif ($is_set) {
979 $statementArray[$statementArrayPointer] .= LF;
980 }
981 }
982
983 return $statementArray;
984 }
985
986 /**
987 * Returns tables to create and how many records in each
988 *
989 * @param array Array of SQL statements to analyse.
990 * @param boolean If set, will count number of INSERT INTO statements following that table definition
991 * @return array Array with table definitions in index 0 and count in index 1
992 */
993 function getCreateTables($statements, $insertCountFlag = 0) {
994 $crTables = array();
995 $insertCount = array();
996 foreach ($statements as $line => $lineContent) {
997 $reg = array();
998 if (preg_match('/^create[[:space:]]*table[[:space:]]*[`]?([[:alnum:]_]*)[`]?/i', substr($lineContent, 0, 100), $reg)) {
999 $table = trim($reg[1]);
1000 if ($table) {
1001 // table names are always lowercase on Windows!
1002 if (TYPO3_OS == 'WIN') {
1003 $table = strtolower($table);
1004 }
1005 $sqlLines = explode(LF, $lineContent);
1006 foreach ($sqlLines as $k => $v) {
1007 if (stristr($v, 'auto_increment')) {
1008 $sqlLines[$k] = preg_replace('/ default \'0\'/i', '', $v);
1009 }
1010 }
1011 $lineContent = implode(LF, $sqlLines);
1012 $crTables[$table] = $lineContent;
1013 }
1014 } elseif ($insertCountFlag && preg_match('/^insert[[:space:]]*into[[:space:]]*[`]?([[:alnum:]_]*)[`]?/i', substr($lineContent, 0, 100), $reg)) {
1015 $nTable = trim($reg[1]);
1016 $insertCount[$nTable]++;
1017 }
1018 }
1019
1020 return array($crTables, $insertCount);
1021 }
1022
1023 /**
1024 * Extracts all insert statements from $statement array where content is inserted into $table
1025 *
1026 * @param array Array of SQL statements
1027 * @param string Table name
1028 * @return array Array of INSERT INTO statements where table match $table
1029 */
1030 function getTableInsertStatements($statements, $table) {
1031 $outStatements = array();
1032 foreach ($statements as $line => $lineContent) {
1033 $reg = array();
1034 if (preg_match('/^insert[[:space:]]*into[[:space:]]*[`]?([[:alnum:]_]*)[`]?/i', substr($lineContent, 0, 100), $reg)) {
1035 $nTable = trim($reg[1]);
1036 if ($nTable && !strcmp($table, $nTable)) {
1037 $outStatements[] = $lineContent;
1038 }
1039 }
1040 }
1041 return $outStatements;
1042 }
1043
1044 /**
1045 * Performs the queries passed from the input array.
1046 *
1047 * @param array Array of SQL queries to execute.
1048 * @param array Array with keys that must match keys in $arr. Only where a key in this array is set and TRUE will the query be executed (meant to be passed from a form checkbox)
1049 * @return mixed Array with error message from database if any occured. Otherwise TRUE if everything was executed successfully.
1050 */
1051 function performUpdateQueries($arr, $keyArr) {
1052 $result = array();
1053 if (is_array($arr)) {
1054 foreach ($arr as $key => $string) {
1055 if (isset($keyArr[$key]) && $keyArr[$key]) {
1056 $res = $GLOBALS['TYPO3_DB']->admin_query($string);
1057 if ($res === FALSE) {
1058 $result[$key] = $GLOBALS['TYPO3_DB']->sql_error();
1059 } elseif (is_resource($res)) {
1060 $GLOBALS['TYPO3_DB']->sql_free_result($res);
1061 }
1062 }
1063 }
1064 }
1065 if (count($result) > 0) {
1066 return $result;
1067 } else {
1068 return TRUE;
1069 }
1070 }
1071
1072 /**
1073 * Returns list of tables in the database
1074 *
1075 * @return array List of tables.
1076 * @see t3lib_db::admin_get_tables()
1077 */
1078 function getListOfTables() {
1079 $whichTables = $GLOBALS['TYPO3_DB']->admin_get_tables(TYPO3_db);
1080 foreach ($whichTables as $key => &$value) {
1081 $value = $key;
1082 }
1083 unset($value);
1084 return $whichTables;
1085 }
1086
1087 /**
1088 * Creates a table which checkboxes for updating database.
1089 *
1090 * @param array Array of statements (key / value pairs where key is used for the checkboxes)
1091 * @param string Label for the table.
1092 * @param boolean If set, then checkboxes are set by default.
1093 * @param boolean If set, then icons are shown.
1094 * @param array Array of "current values" for each key/value pair in $arr. Shown if given.
1095 * @param boolean If set, will show the prefix "Current value" if $currentValue is given.
1096 * @return string HTML table with checkboxes for update. Must be wrapped in a form.
1097 */
1098 function generateUpdateDatabaseForm_checkboxes($arr, $label, $checked = 1, $iconDis = 0, $currentValue = array(), $cVfullMsg = 0) {
1099 $out = array();
1100 if (is_array($arr)) {
1101 $tableId = uniqid('table');
1102 if (count($arr) > 1) {
1103 $out[] = '
1104 <tr class="update-db-fields-batch">
1105 <td valign="top">
1106 <input type="checkbox" id="' . $tableId . '-checkbox"' . ($checked ? ' checked="checked"' : '') . '
1107 onclick="$(\'' . $tableId . '\').select(\'input[type=checkbox]\').invoke(\'setValue\', $(this).checked);" />
1108 </td>
1109 <td nowrap="nowrap"><label for="' . $tableId . '-checkbox" style="cursor:pointer"><strong>select/deselect all</strong></label></td>
1110 </tr>';
1111 }
1112 foreach ($arr as $key => $string) {
1113 $ico = '';
1114 $warnings = array();
1115
1116 if ($iconDis) {
1117 if (preg_match('/^TRUNCATE/i', $string)) {
1118 $ico .= '<img src="' . $this->backPath . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong> </strong>';
1119 $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.';
1120 } elseif (stristr($string, ' user_')) {
1121 $ico .= '<img src="' . $this->backPath . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong>(USER) </strong>';
1122 } elseif (stristr($string, ' app_')) {
1123 $ico .= '<img src="' . $this->backPath . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong>(APP) </strong>';
1124 } elseif (stristr($string, ' ttx_') || stristr($string, ' tx_')) {
1125 $ico .= '<img src="' . $this->backPath . 'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" /><strong>(EXT) </strong>';
1126 }
1127 }
1128 $out[] = '
1129 <tr>
1130 <td valign="top"><input type="checkbox" id="db-' . $key . '" name="' . $this->dbUpdateCheckboxPrefix . '[' . $key . ']" value="1"' . ($checked ? ' checked="checked"' : '') . ' /></td>
1131 <td nowrap="nowrap"><label for="db-' . $key . '">' . nl2br($ico . htmlspecialchars($string)) . '</label></td>
1132 </tr>';
1133 if (isset($currentValue[$key])) {
1134 $out[] = '
1135 <tr>
1136 <td valign="top"></td>
1137 <td nowrap="nowrap" style="color:#666666;">' . nl2br((!$cVfullMsg ? "Current value: " : "") . '<em>' . $currentValue[$key] . '</em>') . '</td>
1138 </tr>';
1139 }
1140 }
1141 if (count($warnings)) {
1142 $out[] = '
1143 <tr>
1144 <td valign="top"></td>
1145 <td style="color:#666666;"><em>' . implode('<br />', $warnings) . '</em></td>
1146 </tr>';
1147 }
1148
1149 // Compile rows:
1150 $content = '
1151 <!-- Update database fields / tables -->
1152 <h3>' . $label . '</h3>
1153 <table border="0" cellpadding="2" cellspacing="2" id="' . $tableId . '" class="update-db-fields">' . implode('', $out) . '
1154 </table>';
1155 }
1156
1157 return $content;
1158 }
1159 }
1160
1161 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_install.php'])) {
1162 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_install.php']);
1163 }
1164
1165 ?>