i think david just forgot these. ;)
[phpbb.git] / phpBB / install / database_update.php
blob5cc8bd114fc80de9eedb6f53071a5bdd3ee6794a
1 <?php
2 /**
4 * @package install
5 * @version $Id$
6 * @copyright (c) 2006 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 $updates_to_version = '3.0.RC6';
13 // Return if we "just include it" to find out for which version the database update is responsuble for
14 if (defined('IN_PHPBB') && defined('IN_INSTALL'))
16 return;
19 /**
21 define('IN_PHPBB', true);
22 define('IN_INSTALL', true);
24 $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../';
25 $phpEx = substr(strrchr(__FILE__, '.'), 1);
27 // Report all errors, except notices
28 //error_reporting(E_ALL ^ E_NOTICE);
29 error_reporting(E_ALL);
31 @set_time_limit(0);
33 // Include essential scripts
34 include($phpbb_root_path . 'config.' . $phpEx);
36 if (!isset($dbms))
38 die("Please read: <a href='../docs/INSTALL.html'>INSTALL.html</a> before attempting to update.");
41 // Load Extensions
42 if (!empty($load_extensions))
44 $load_extensions = explode(',', $load_extensions);
46 foreach ($load_extensions as $extension)
48 @dl(trim($extension));
52 // Include files
53 require($phpbb_root_path . 'includes/acm/acm_' . $acm_type . '.' . $phpEx);
54 require($phpbb_root_path . 'includes/cache.' . $phpEx);
55 require($phpbb_root_path . 'includes/template.' . $phpEx);
56 require($phpbb_root_path . 'includes/session.' . $phpEx);
57 require($phpbb_root_path . 'includes/auth.' . $phpEx);
59 require($phpbb_root_path . 'includes/functions.' . $phpEx);
61 if (file_exists($phpbb_root_path . 'includes/functions_content.' . $phpEx))
63 require($phpbb_root_path . 'includes/functions_content.' . $phpEx);
66 require($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
67 require($phpbb_root_path . 'includes/constants.' . $phpEx);
68 require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
69 require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
71 // If we are on PHP >= 6.0.0 we do not need some code
72 if (version_compare(PHP_VERSION, '6.0.0-dev', '>='))
74 /**
75 * @ignore
77 define('STRIP', false);
79 else
81 set_magic_quotes_runtime(0);
82 define('STRIP', (get_magic_quotes_gpc()) ? true : false);
85 $user = new user();
86 $cache = new cache();
87 $db = new $sql_db();
89 // Add own hook handler, if present. :o
90 if (file_exists($phpbb_root_path . 'includes/hooks/index.' . $phpEx))
92 require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
93 $phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));
95 foreach ($cache->obtain_hooks() as $hook)
97 @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx);
100 else
102 $phpbb_hook = false;
105 // Connect to DB
106 $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);
108 // We do not need this any longer, unset for safety purposes
109 unset($dbpasswd);
111 $user->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '';
113 $sql = "SELECT config_value
114 FROM " . CONFIG_TABLE . "
115 WHERE config_name = 'default_lang'";
116 $result = $db->sql_query($sql);
117 $row = $db->sql_fetchrow($result);
118 $db->sql_freeresult($result);
120 $language = basename(request_var('language', ''));
122 if (!$language)
124 $language = $row['config_value'];
127 if (!file_exists($phpbb_root_path . 'language/' . $language))
129 die('No language found!');
132 // And finally, load the relevant language files
133 include($phpbb_root_path . 'language/' . $language . '/common.' . $phpEx);
134 include($phpbb_root_path . 'language/' . $language . '/acp/common.' . $phpEx);
135 include($phpbb_root_path . 'language/' . $language . '/install.' . $phpEx);
137 // Set PHP error handler to ours
138 //set_error_handler('msg_handler');
140 // Define some variables for the database update
141 $inline_update = (request_var('type', 0)) ? true : false;
143 // Database column types mapping
144 $dbms_type_map = array(
145 'mysql_41' => array(
146 'INT:' => 'int(%d)',
147 'BINT' => 'bigint(20)',
148 'UINT' => 'mediumint(8) UNSIGNED',
149 'UINT:' => 'int(%d) UNSIGNED',
150 'TINT:' => 'tinyint(%d)',
151 'USINT' => 'smallint(4) UNSIGNED',
152 'BOOL' => 'tinyint(1) UNSIGNED',
153 'VCHAR' => 'varchar(255)',
154 'VCHAR:' => 'varchar(%d)',
155 'CHAR:' => 'char(%d)',
156 'XSTEXT' => 'text',
157 'XSTEXT_UNI'=> 'varchar(100)',
158 'STEXT' => 'text',
159 'STEXT_UNI' => 'varchar(255)',
160 'TEXT' => 'text',
161 'TEXT_UNI' => 'text',
162 'MTEXT' => 'mediumtext',
163 'MTEXT_UNI' => 'mediumtext',
164 'TIMESTAMP' => 'int(11) UNSIGNED',
165 'DECIMAL' => 'decimal(5,2)',
166 'VCHAR_UNI' => 'varchar(255)',
167 'VCHAR_UNI:'=> 'varchar(%d)',
168 'VCHAR_CI' => 'varchar(255)',
169 'VARBINARY' => 'varbinary(255)',
172 'mysql_40' => array(
173 'INT:' => 'int(%d)',
174 'BINT' => 'bigint(20)',
175 'UINT' => 'mediumint(8) UNSIGNED',
176 'UINT:' => 'int(%d) UNSIGNED',
177 'TINT:' => 'tinyint(%d)',
178 'USINT' => 'smallint(4) UNSIGNED',
179 'BOOL' => 'tinyint(1) UNSIGNED',
180 'VCHAR' => 'varbinary(255)',
181 'VCHAR:' => 'varbinary(%d)',
182 'CHAR:' => 'binary(%d)',
183 'XSTEXT' => 'blob',
184 'XSTEXT_UNI'=> 'blob',
185 'STEXT' => 'blob',
186 'STEXT_UNI' => 'blob',
187 'TEXT' => 'blob',
188 'TEXT_UNI' => 'blob',
189 'MTEXT' => 'mediumblob',
190 'MTEXT_UNI' => 'mediumblob',
191 'TIMESTAMP' => 'int(11) UNSIGNED',
192 'DECIMAL' => 'decimal(5,2)',
193 'VCHAR_UNI' => 'blob',
194 'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')),
195 'VCHAR_CI' => 'blob',
196 'VARBINARY' => 'varbinary(255)',
199 'firebird' => array(
200 'INT:' => 'INTEGER',
201 'BINT' => 'DOUBLE PRECISION',
202 'UINT' => 'INTEGER',
203 'UINT:' => 'INTEGER',
204 'TINT:' => 'INTEGER',
205 'USINT' => 'INTEGER',
206 'BOOL' => 'INTEGER',
207 'VCHAR' => 'VARCHAR(255) CHARACTER SET NONE',
208 'VCHAR:' => 'VARCHAR(%d) CHARACTER SET NONE',
209 'CHAR:' => 'CHAR(%d) CHARACTER SET NONE',
210 'XSTEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
211 'STEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
212 'TEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
213 'MTEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
214 'XSTEXT_UNI'=> 'VARCHAR(100) CHARACTER SET UTF8',
215 'STEXT_UNI' => 'VARCHAR(255) CHARACTER SET UTF8',
216 'TEXT_UNI' => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8',
217 'MTEXT_UNI' => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8',
218 'TIMESTAMP' => 'INTEGER',
219 'DECIMAL' => 'DOUBLE PRECISION',
220 'VCHAR_UNI' => 'VARCHAR(255) CHARACTER SET UTF8',
221 'VCHAR_UNI:'=> 'VARCHAR(%d) CHARACTER SET UTF8',
222 'VCHAR_CI' => 'VARCHAR(255) CHARACTER SET UTF8',
223 'VARBINARY' => 'CHAR(255) CHARACTER SET NONE',
226 'mssql' => array(
227 'INT:' => '[int]',
228 'BINT' => '[float]',
229 'UINT' => '[int]',
230 'UINT:' => '[int]',
231 'TINT:' => '[int]',
232 'USINT' => '[int]',
233 'BOOL' => '[int]',
234 'VCHAR' => '[varchar] (255)',
235 'VCHAR:' => '[varchar] (%d)',
236 'CHAR:' => '[char] (%d)',
237 'XSTEXT' => '[varchar] (1000)',
238 'STEXT' => '[varchar] (3000)',
239 'TEXT' => '[varchar] (8000)',
240 'MTEXT' => '[text]',
241 'XSTEXT_UNI'=> '[varchar] (100)',
242 'STEXT_UNI' => '[varchar] (255)',
243 'TEXT_UNI' => '[varchar] (4000)',
244 'MTEXT_UNI' => '[text]',
245 'TIMESTAMP' => '[int]',
246 'DECIMAL' => '[float]',
247 'VCHAR_UNI' => '[varchar] (255)',
248 'VCHAR_UNI:'=> '[varchar] (%d)',
249 'VCHAR_CI' => '[varchar] (255)',
250 'VARBINARY' => '[varchar] (255)',
253 'oracle' => array(
254 'INT:' => 'number(%d)',
255 'BINT' => 'number(20)',
256 'UINT' => 'number(8)',
257 'UINT:' => 'number(%d)',
258 'TINT:' => 'number(%d)',
259 'USINT' => 'number(4)',
260 'BOOL' => 'number(1)',
261 'VCHAR' => 'varchar2(255)',
262 'VCHAR:' => 'varchar2(%d)',
263 'CHAR:' => 'char(%d)',
264 'XSTEXT' => 'varchar2(1000)',
265 'STEXT' => 'varchar2(3000)',
266 'TEXT' => 'clob',
267 'MTEXT' => 'clob',
268 'XSTEXT_UNI'=> 'varchar2(300)',
269 'STEXT_UNI' => 'varchar2(765)',
270 'TEXT_UNI' => 'clob',
271 'MTEXT_UNI' => 'clob',
272 'TIMESTAMP' => 'number(11)',
273 'DECIMAL' => 'number(5, 2)',
274 'VCHAR_UNI' => 'varchar2(765)',
275 'VCHAR_UNI:'=> array('varchar2(%d)', 'limit' => array('mult', 3, 765, 'clob')),
276 'VCHAR_CI' => 'varchar2(255)',
277 'VARBINARY' => 'raw(255)',
280 'sqlite' => array(
281 'INT:' => 'int(%d)',
282 'BINT' => 'bigint(20)',
283 'UINT' => 'INTEGER UNSIGNED', //'mediumint(8) UNSIGNED',
284 'UINT:' => 'INTEGER UNSIGNED', // 'int(%d) UNSIGNED',
285 'TINT:' => 'tinyint(%d)',
286 'USINT' => 'INTEGER UNSIGNED', //'mediumint(4) UNSIGNED',
287 'BOOL' => 'INTEGER UNSIGNED', //'tinyint(1) UNSIGNED',
288 'VCHAR' => 'varchar(255)',
289 'VCHAR:' => 'varchar(%d)',
290 'CHAR:' => 'char(%d)',
291 'XSTEXT' => 'text(65535)',
292 'STEXT' => 'text(65535)',
293 'TEXT' => 'text(65535)',
294 'MTEXT' => 'mediumtext(16777215)',
295 'XSTEXT_UNI'=> 'text(65535)',
296 'STEXT_UNI' => 'text(65535)',
297 'TEXT_UNI' => 'text(65535)',
298 'MTEXT_UNI' => 'mediumtext(16777215)',
299 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED',
300 'DECIMAL' => 'decimal(5,2)',
301 'VCHAR_UNI' => 'varchar(255)',
302 'VCHAR_UNI:'=> 'varchar(%d)',
303 'VCHAR_CI' => 'varchar(255)',
304 'VARBINARY' => 'blob',
307 'postgres' => array(
308 'INT:' => 'INT4',
309 'BINT' => 'INT8',
310 'UINT' => 'INT4', // unsigned
311 'UINT:' => 'INT4', // unsigned
312 'USINT' => 'INT2', // unsigned
313 'BOOL' => 'INT2', // unsigned
314 'TINT:' => 'INT2',
315 'VCHAR' => 'varchar(255)',
316 'VCHAR:' => 'varchar(%d)',
317 'CHAR:' => 'char(%d)',
318 'XSTEXT' => 'varchar(1000)',
319 'STEXT' => 'varchar(3000)',
320 'TEXT' => 'varchar(8000)',
321 'MTEXT' => 'TEXT',
322 'XSTEXT_UNI'=> 'varchar(100)',
323 'STEXT_UNI' => 'varchar(255)',
324 'TEXT_UNI' => 'varchar(4000)',
325 'MTEXT_UNI' => 'TEXT',
326 'TIMESTAMP' => 'INT4', // unsigned
327 'DECIMAL' => 'decimal(5,2)',
328 'VCHAR_UNI' => 'varchar(255)',
329 'VCHAR_UNI:'=> 'varchar(%d)',
330 'VCHAR_CI' => 'varchar_ci',
331 'VARBINARY' => 'bytea',
335 // A list of types being unsigned for better reference in some db's
336 $unsigned_types = array('UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP');
338 // Only an example, but also commented out
339 $database_update_info = array(
340 // Changes from 3.0.RC2 to the next version
341 '3.0.RC2' => array(
342 // Change the following columns
343 'change_columns' => array(
344 BANLIST_TABLE => array(
345 'ban_reason' => array('VCHAR_UNI', ''),
346 'ban_give_reason' => array('VCHAR_UNI', ''),
350 // Changes from 3.0.RC3 to the next version
351 '3.0.RC3' => array(
352 // Change the following columns
353 'change_columns' => array(
354 BANLIST_TABLE => array(
355 'ban_reason' => array('VCHAR_UNI', ''),
356 'ban_give_reason' => array('VCHAR_UNI', ''),
358 STYLES_TABLE => array(
359 'style_id' => array('USINT', 0),
360 'template_id' => array('USINT', 0),
361 'theme_id' => array('USINT', 0),
362 'imageset_id' => array('USINT', 0),
364 STYLES_TEMPLATE_TABLE => array(
365 'template_id' => array('USINT', 0),
367 STYLES_TEMPLATE_DATA_TABLE => array(
368 'template_id' => array('USINT', 0),
370 STYLES_THEME_TABLE => array(
371 'theme_id' => array('USINT', 0),
373 STYLES_IMAGESET_TABLE => array(
374 'imageset_id' => array('USINT', 0),
376 STYLES_IMAGESET_DATA_TABLE => array(
377 'imageset_id' => array('USINT', 0),
379 USERS_TABLE => array(
380 'user_style' => array('USINT', 0),
382 FORUMS_TABLE => array(
383 'forum_style' => array('USINT', 0),
385 GROUPS_TABLE => array(
386 'group_avatar_type' => array('TINT:2', 0),
387 'group_avatar_width' => array('USINT', 0),
388 'group_avatar_height' => array('USINT', 0),
392 // Changes from 3.0.RC4 to the next version
393 '3.0.RC4' => array(
394 // Change the following columns
395 'change_columns' => array(
396 STYLES_TABLE => array(
397 'style_id' => array('USINT', NULL, 'auto_increment'),
398 'template_id' => array('USINT', 0),
399 'theme_id' => array('USINT', 0),
400 'imageset_id' => array('USINT', 0),
402 STYLES_TEMPLATE_TABLE => array(
403 'template_id' => array('USINT', NULL, 'auto_increment'),
405 STYLES_TEMPLATE_DATA_TABLE => array(
406 'template_id' => array('USINT', 0),
408 STYLES_THEME_TABLE => array(
409 'theme_id' => array('USINT', NULL, 'auto_increment'),
411 STYLES_IMAGESET_TABLE => array(
412 'imageset_id' => array('USINT', NULL, 'auto_increment'),
414 STYLES_IMAGESET_DATA_TABLE => array(
415 'imageset_id' => array('USINT', 0),
417 USERS_TABLE => array(
418 'user_style' => array('USINT', 0),
420 FORUMS_TABLE => array(
421 'forum_style' => array('USINT', 0),
423 GROUPS_TABLE => array(
424 'group_avatar_width' => array('USINT', 0),
425 'group_avatar_height' => array('USINT', 0),
429 // Changes from 3.0.RC5 to the next version
430 '3.0.RC5' => array(
431 // Add the following columns
432 'add_columns' => array(
433 USERS_TABLE => array(
434 'user_form_salt' => array('VCHAR_UNI:32', ''),
437 // Change the following columns
438 'change_columns' => array(
439 POSTS_TABLE => array(
440 'bbcode_uid' => array('VCHAR:8', ''),
442 PRIVMSGS_TABLE => array(
443 'bbcode_uid' => array('VCHAR:8', ''),
445 USERS_TABLE => array(
446 'user_sig_bbcode_uid' => array('VCHAR:8', ''),
452 // Determine mapping database type
453 switch ($db->sql_layer)
455 case 'mysql':
456 $map_dbms = 'mysql_40';
457 break;
459 case 'mysql4':
460 if (version_compare($db->mysql_version, '4.1.3', '>='))
462 $map_dbms = 'mysql_41';
464 else
466 $map_dbms = 'mysql_40';
468 break;
470 case 'mysqli':
471 $map_dbms = 'mysql_41';
472 break;
474 case 'mssql':
475 case 'mssql_odbc':
476 $map_dbms = 'mssql';
477 break;
479 default:
480 $map_dbms = $db->sql_layer;
481 break;
484 $error_ary = array();
485 $errored = false;
487 header('Content-type: text/html; charset=UTF-8');
490 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
491 <html xmlns="http://www.w3.org/1999/xhtml" dir="<?php echo $lang['DIRECTION']; ?>" lang="<?php echo $lang['USER_LANG']; ?>" xml:lang="<?php echo $lang['USER_LANG']; ?>">
492 <head>
494 <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
495 <meta http-equiv="content-language" content="<?php echo $lang['USER_LANG']; ?>" />
496 <meta http-equiv="content-style-type" content="text/css" />
497 <meta http-equiv="imagetoolbar" content="no" />
499 <title><?php echo $lang['UPDATING_TO_LATEST_STABLE']; ?></title>
501 <link href="../adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" />
503 </head>
505 <body>
506 <div id="wrap">
507 <div id="page-header">&nbsp;</div>
509 <div id="page-body">
510 <div id="acp">
511 <div class="panel">
512 <span class="corners-top"><span></span></span>
513 <div id="content">
514 <div id="main">
516 <h1><?php echo $lang['UPDATING_TO_LATEST_STABLE']; ?></h1>
518 <br />
520 <p><?php echo $lang['DATABASE_TYPE']; ?> :: <strong><?php echo $db->sql_layer; ?></strong><br />
521 <?php
523 // To let set_config() calls succeed, we need to make the config array available globally
524 $config = array();
525 $sql = 'SELECT *
526 FROM ' . CONFIG_TABLE;
527 $result = $db->sql_query($sql);
529 while ($row = $db->sql_fetchrow($result))
531 $config[$row['config_name']] = $row['config_value'];
533 $db->sql_freeresult($result);
535 echo $lang['PREVIOUS_VERSION'] . ' :: <strong>' . $config['version'] . '</strong><br />';
536 echo $lang['UPDATED_VERSION'] . ' :: <strong>' . $updates_to_version . '</strong></p>';
538 $current_version = str_replace('rc', 'RC', strtolower($config['version']));
539 $latest_version = str_replace('rc', 'RC', strtolower($updates_to_version));
540 $orig_version = $config['version'];
542 // If the latest version and the current version are 'unequal', we will update the version_update_from, else we do not update anything.
543 if ($inline_update)
545 if ($current_version !== $latest_version)
547 set_config('version_update_from', $orig_version);
550 else
552 // If not called from the update script, we will actually remove the traces
553 $db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'version_update_from'");
556 // Checks/Operations that have to be completed prior to starting the update itself
557 $exit = false;
558 if (version_compare($current_version, '3.0.RC4', '<='))
560 // Define missing language entries...
561 if (!isset($lang['CLEANING_USERNAMES']))
563 $lang = array_merge($lang, array(
564 'CLEANING_USERNAMES' => 'Cleaning usernames',
565 'LONG_SCRIPT_EXECUTION' => 'Please note that this can take a while... Please do not stop the script.',
566 'CHANGE_CLEAN_NAMES' => 'The method used to make sure a username is not used by multiple users has been changed. There are some users which have the same name when compared with the new method. You have to delete or rename these users to make sure that each name is only used by one user before you can proceed.',
567 'USER_ACTIVE' => 'Active user',
568 'USER_INACTIVE' => 'Inactive user',
569 'BOT' => 'Spider/Robot',
570 'UPDATE_REQUIRES_FILE' => 'The updater requires that the following file is present: %s',
572 'DELETE_USER_REMOVE' => 'Delete user and remove posts',
573 'DELETE_USER_RETAIN' => 'Delete user but keep posts',
574 'EDIT_USERNAME' => 'Edit username',
575 'KEEP_OLD_NAME' => 'Keep username',
576 'NEW_USERNAME' => 'New username',
580 <br /><br />
582 <h1><?php echo $lang['CLEANING_USERNAMES']; ?></h1>
584 <br />
586 <?php
587 flush();
589 $submit = (isset($_POST['resolve_conflicts'])) ? true : false;
590 $modify_users = request_var('modify_users', array(0 => ''));
591 $new_usernames = request_var('new_usernames', array(0 => ''), true);
593 if (!class_exists('utf_new_normalizer'))
595 if (!file_exists($phpbb_root_path . 'install/data/new_normalizer.' . $phpEx))
597 global $lang;
598 trigger_error(sprintf($lang['UPDATE_REQUIRES_FILE'], $phpbb_root_path . 'install/data/new_normalizer.' . $phpEx), E_USER_ERROR);
600 include($phpbb_root_path . 'install/data/new_normalizer.' . $phpEx);
603 // the admin decided to change some usernames
604 if (sizeof($modify_users) && $submit)
606 $sql = 'SELECT user_id, username, user_type
607 FROM ' . USERS_TABLE . '
608 WHERE ' . $db->sql_in_set('user_id', array_keys($modify_users));
609 $result = $db->sql_query($sql);
611 $users = 0;
612 while ($row = $db->sql_fetchrow($result))
614 $users++;
615 $user_id = (int) $row['user_id'];
617 if (isset($modify_users[$user_id]))
619 $row['action'] = $modify_users[$user_id];
620 $modify_users[$user_id] = $row;
623 $db->sql_freeresult($result);
625 // only if all ids really existed
626 if (sizeof($modify_users) == $users)
628 $user->data['user_id'] = ANONYMOUS;
629 include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
630 foreach ($modify_users as $user_id => $row)
632 switch ($row['action'])
634 case 'edit':
635 if (isset($new_usernames[$user_id]))
637 $data = array('username' => utf8_new_normalize_nfc($new_usernames[$user_id]));
638 // Need to update config, forum, topic, posting, messages, etc.
639 if ($data['username'] != $row['username'])
641 $check_ary = array('username' => array(
642 array('string', false, $config['min_name_chars'], $config['max_name_chars']),
643 array('username'),
645 // need a little trick for this to work properly
646 $user->data['username_clean'] = utf8_clean_string($data['username']) . 'a';
647 $errors = validate_data($data, $check_ary);
649 if ($errors)
651 include($phpbb_root_path . 'language/' . $language . '/ucp.' . $phpEx);
652 echo '<div class="errorbox">';
653 foreach ($errors as $error)
655 echo '<p>' . $lang[$error] . '</p>';
657 echo '</div>';
660 if (!$errors)
662 $sql = 'UPDATE ' . USERS_TABLE . '
663 SET ' . $db->sql_build_array('UPDATE', array(
664 'username' => $data['username'],
665 'username_clean' => utf8_clean_string($data['username'])
666 )) . '
667 WHERE user_id = ' . $user_id;
668 $db->sql_query($sql);
670 add_log('user', $user_id, 'LOG_USER_UPDATE_NAME', $row['username'], $data['username']);
671 user_update_name($row['username'], $data['username']);
675 break;
677 case 'delete_retain':
678 case 'delete_remove':
679 if ($user_id != ANONYMOUS && $row['user_type'] != USER_FOUNDER)
681 user_delete(substr($row['action'], 7), $user_id, $row['username']);
682 add_log('admin', 'LOG_USER_DELETED', $row['username']);
684 break;
691 <p><?php echo $lang['LONG_SCRIPT_EXECUTION']; ?></p>
692 <p><?php echo $lang['PROGRESS']; ?> :: <strong>
694 <?php
695 flush();
697 // after RC3 a different utf8_clean_string function is used, this requires that
698 // the unique column username_clean is recalculated, during this recalculation
699 // duplicates might be created. Since the column has to be unique such usernames
700 // must not exist. We need identify them and let the admin decide what to do
701 // about them.
702 $sql = 'SELECT user_id, username, username_clean
703 FROM ' . USERS_TABLE . '
704 ORDER BY user_id ASC';
705 $result = $db->sql_query($sql);
707 $colliding_users = $found_names = array();
708 $echos = 0;
710 while ($row = $db->sql_fetchrow($result))
712 // Calculate the new clean name. If it differs from the old one we need
713 // to make sure there is no collision
714 $clean_name = utf8_new_clean_string($row['username']);
716 if ($clean_name != $row['username_clean'])
718 // Check if there would be a collission, if not put it up for changing
719 $user_id = (int) $row['user_id'];
721 // If this clean name was not the result of another user already ...
722 if (!isset($found_names[$clean_name]))
724 // then we need to figure out whether there are any other users
725 // who already had this clean name with the old version
726 $sql = 'SELECT user_id, username
727 FROM ' . USERS_TABLE . '
728 WHERE username_clean = \'' . $db->sql_escape($clean_name) . '\'';
729 $result2 = $db->sql_query($sql);
731 $user_ids = array($user_id);
732 while ($row = $db->sql_fetchrow($result2))
734 // For not trimmed entries this could happen, yes. ;)
735 if ($row['user_id'] == $user_id)
737 continue;
740 // Make sure this clean name will still be the same with the
741 // new function. If it is, then we have to add it to the list
742 // of user ids for this clean name
743 if (utf8_new_clean_string($row['username']) == $clean_name)
745 $user_ids[] = (int) $row['user_id'];
748 $db->sql_freeresult($result2);
750 // if we already found a collision save it
751 if (sizeof($user_ids) > 1)
753 $colliding_users[$clean_name] = $user_ids;
754 $found_names[$clean_name] = true;
756 else
758 // otherwise just mark this name as found
759 $found_names[$clean_name] = $user_id;
762 // Else, if we already found the username
763 else
765 // If the value in the found_names lookup table is only true ...
766 if ($found_names[$clean_name] === true)
768 // then the actual data was already added to $colliding_users
769 // and we only need to append the user_id
770 $colliding_users[$clean_name][] = $user_id;
772 else
774 // otherwise it still keeps the first user_id for this name
775 // and we need to move the data to $colliding_users, and set
776 // the value in the found_names lookup table to true, so
777 // following users will directly be appended to $colliding_users
778 $colliding_users[$clean_name] = array($found_names[$clean_name], $user_id);
779 $found_names[$clean_name] = true;
784 if (($echos % 1000) == 0)
786 echo '.';
787 flush();
789 $echos++;
791 $db->sql_freeresult($result);
793 _write_result(false, $errored, $error_ary);
795 // now retrieve all information about the users and let the admin decide what to do
796 if (sizeof($colliding_users))
798 $exit = true;
799 include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
800 include($phpbb_root_path . 'language/' . $language . '/memberlist.' . $phpEx);
801 include($phpbb_root_path . 'language/' . $language . '/acp/users.' . $phpEx);
803 // link a few things to the correct place so we don't get any problems
804 $user->lang = &$lang;
805 $user->data['user_id'] = ANONYMOUS;
806 $user->date_format = $config['default_dateformat'];
808 // a little trick to get all user_ids
809 $user_ids = call_user_func_array('array_merge', array_values($colliding_users));
811 $sql = 'SELECT session_user_id, MAX(session_time) AS session_time
812 FROM ' . SESSIONS_TABLE . '
813 WHERE session_time >= ' . (time() - $config['session_length']) . '
814 AND ' . $db->sql_in_set('session_user_id', $user_ids) . '
815 GROUP BY session_user_id';
816 $result = $db->sql_query($sql);
818 $session_times = array();
819 while ($row = $db->sql_fetchrow($result))
821 $session_times[$row['session_user_id']] = $row['session_time'];
823 $db->sql_freeresult($result);
825 $sql = 'SELECT *
826 FROM ' . USERS_TABLE . '
827 WHERE ' . $db->sql_in_set('user_id', $user_ids);
828 $result = $db->sql_query($sql);
830 $users = array();
831 while ($row = $db->sql_fetchrow($result))
833 if (isset($session_times[$row['user_id']]))
835 $row['session_time'] = $session_times[$row['user_id']];
837 else
839 $row['session_time'] = 0;
841 $users[(int) $row['user_id']] = $row;
843 $db->sql_freeresult($result);
844 unset($session_times);
846 // now display a table with all users, some information about them and options
847 // for the admin: keep name, change name (with text input) or delete user
848 $u_action = "database_update.$phpEx?language=$language&amp;type=$inline_update";
850 <br /><br />
852 <p><?php echo $lang['CHANGE_CLEAN_NAMES']; ?></p>
853 <form id="change_clean_names" method="post" action="<?php echo $u_action; ?>">
856 <?php
857 foreach ($colliding_users as $clean_name => $user_ids)
860 <fieldset class="tabulated">
861 <table>
862 <caption><?php echo sprintf($lang['COLLIDING_CLEAN_USERNAME'], $clean_name); ?></caption>
863 <thead>
864 <tr>
865 <th><?php echo $lang['RANK']; ?> <?php echo $lang['USERNAME']; ?></th>
866 <th><?php echo $lang['POSTS']; ?></th>
867 <th><?php echo $lang['INFORMATION']; ?></th>
868 <th><?php echo $lang['JOINED']; ?></th>
869 <th><?php echo $lang['LAST_ACTIVE']; ?></th>
870 <th><?php echo $lang['ACTION']; ?></th>
871 <th><?php echo $lang['NEW_USERNAME']; ?></th>
872 </tr>
873 </thead>
874 <tbody>
875 <?php
876 foreach ($user_ids as $i => $user_id)
878 $row = $users[$user_id];
880 $rank_title = $rank_img = '';
881 get_user_rank($row['user_rank'], $row['user_posts'], $rank_title, $rank_img, $rank_img_src);
883 $last_visit = (!empty($row['session_time'])) ? $row['session_time'] : $row['user_lastvisit'];
885 $info = '';
886 switch ($row['user_type'])
888 case USER_INACTIVE:
889 $info .= $lang['USER_INACTIVE'];
890 break;
892 case USER_IGNORE:
893 $info .= $lang['BOT'];
894 break;
896 case USER_FOUNDER:
897 $info .= $lang['FOUNDER'];
898 break;
900 default:
901 $info .= $lang['USER_ACTIVE'];
904 if ($user_id == ANONYMOUS)
906 $info = $lang['GUEST'];
909 <tr class="bg<?php echo ($i % 2) + 1; ?>">
910 <td>
911 <span class="rank-img"><?php echo ($rank_img) ? $rank_img : $rank_title; ?></span><br />
912 <?php echo get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); ?>
913 </td>
914 <td class="posts"><?php echo $row['user_posts']; ?></td>
915 <td class="info"><?php echo $info; ?></td>
916 <td><?php echo $user->format_date($row['user_regdate']) ?></td>
917 <td><?php echo (empty($last_visit)) ? ' - ' : $user->format_date($last_visit); ?>&nbsp;</td>
918 <td>
919 <label><input type="radio" class="radio" id="keep_user_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="keep" checked="checked" /> <?php echo $lang['KEEP_OLD_NAME']; ?></label><br />
920 <label><input type="radio" class="radio" id="edit_user_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="edit" /> <?php echo $lang['EDIT_USERNAME']; ?></label><br />
921 <?php
922 // some users must not be deleted
923 if ($user_id != ANONYMOUS && $row['user_type'] != USER_FOUNDER)
926 <label><input type="radio" class="radio" id="delete_user_retain_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="delete_retain" /> <?php echo $lang['DELETE_USER_RETAIN']; ?></label><br />
927 <label><input type="radio" class="radio" id="delete_user_remove_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="delete_remove" /> <?php echo $lang['DELETE_USER_REMOVE']; ?></label>
928 <?php
931 </td>
932 <td>
933 <input id="new_username_<?php echo $user_id; ?>" type="text" name="new_usernames[<?php echo $user_id; ?>]" value="<?php echo $row['username']; ?>" />
934 </td>
935 </tr>
936 <?php
939 </tbody>
940 </table>
941 </fieldset>
942 <?php
945 <p class="quick">
946 <input class="button2" id="resolve_conflicts" type="submit" name="resolve_conflicts" value="<?php echo $lang['SUBMIT']; ?>" />
947 </p>
948 </form>
949 <?php
951 else if (sizeof($found_names))
953 $sql = 'SELECT user_id, username, username_clean
954 FROM ' . USERS_TABLE . '
955 WHERE ' . $db->sql_in_set('user_id', array_values($found_names));
956 $result = $db->sql_query($sql);
958 $found_names = array();
959 while ($row = $db->sql_fetchrow($result))
961 $clean_name = utf8_new_clean_string($row['username']);
963 if ($clean_name != $row['username_clean'])
965 $user_id = (int) $row['user_id'];
966 $found_names[$user_id] = $clean_name;
968 // impossible unique clean name
969 $sql = 'UPDATE ' . USERS_TABLE . "
970 SET username_clean = ' {$user_id}'
971 WHERE user_id = {$user_id}";
972 $db->sql_query($sql);
975 $db->sql_freeresult($result);
977 foreach ($found_names as $user_id => $clean_name)
979 $sql = 'UPDATE ' . USERS_TABLE . '
980 SET username_clean = \'' . $db->sql_escape($clean_name) . '\'
981 WHERE user_id = ' . $user_id;
982 $db->sql_query($sql);
985 unset($found_names);
986 unset($colliding_users);
989 if ($exit)
993 </div>
994 </div>
995 <span class="corners-bottom"><span></span></span>
996 </div>
997 </div>
998 </div>
1000 <div id="page-footer">
1001 Powered by phpBB &copy; 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>
1002 </div>
1003 </div>
1005 </body>
1006 </html>
1008 <?php
1009 exit_handler();
1012 // Schema updates
1014 <br /><br />
1016 <h1><?php echo $lang['UPDATE_DATABASE_SCHEMA']; ?></h1>
1018 <br />
1019 <p><?php echo $lang['PROGRESS']; ?> :: <strong>
1021 <?php
1023 flush();
1025 // We go through the schema changes from the lowest to the highest version
1026 // We skip those versions older than the current version
1027 $no_updates = true;
1028 foreach ($database_update_info as $version => $schema_changes)
1030 if (version_compare($version, $current_version, '<'))
1032 continue;
1035 if (!sizeof($schema_changes))
1037 continue;
1040 $no_updates = false;
1042 // Change columns?
1043 if (!empty($schema_changes['change_columns']))
1045 foreach ($schema_changes['change_columns'] as $table => $columns)
1047 foreach ($columns as $column_name => $column_data)
1049 sql_column_change($map_dbms, $table, $column_name, $column_data);
1054 // Add columns?
1055 if (!empty($schema_changes['add_columns']))
1057 foreach ($schema_changes['add_columns'] as $table => $columns)
1059 foreach ($columns as $column_name => $column_data)
1061 // Only add the column if it does not exist yet
1062 if (!column_exists($map_dbms, $table, $column_name))
1064 sql_column_add($map_dbms, $table, $column_name, $column_data);
1070 // Remove keys?
1071 if (!empty($schema_changes['drop_keys']))
1073 foreach ($schema_changes['drop_keys'] as $table => $indexes)
1075 foreach ($indexes as $index_name)
1077 sql_index_drop($map_dbms, $index_name, $table);
1082 // Drop columns?
1083 if (!empty($schema_changes['drop_columns']))
1085 foreach ($schema_changes['drop_columns'] as $table => $columns)
1087 foreach ($columns as $column)
1089 sql_column_remove($map_dbms, $table, $column);
1094 // Add primary keys?
1095 if (!empty($schema_changes['add_primary_keys']))
1097 foreach ($schema_changes['add_primary_keys'] as $table => $columns)
1099 sql_create_primary_key($map_dbms, $table, $columns);
1103 // Add unqiue indexes?
1104 if (!empty($schema_changes['add_unique_index']))
1106 foreach ($schema_changes['add_unique_index'] as $table => $index_array)
1108 foreach ($index_array as $index_name => $column)
1110 sql_create_unique_index($map_dbms, $index_name, $table, $column);
1115 // Add indexes?
1116 if (!empty($schema_changes['add_index']))
1118 foreach ($schema_changes['add_index'] as $table => $index_array)
1120 foreach ($index_array as $index_name => $column)
1122 sql_create_index($map_dbms, $index_name, $table, $column);
1128 _write_result($no_updates, $errored, $error_ary);
1130 // Data updates
1131 $error_ary = array();
1132 $errored = $no_updates = false;
1136 <br /><br />
1137 <h1><?php echo $lang['UPDATING_DATA']; ?></h1>
1138 <br />
1139 <p><?php echo $lang['PROGRESS']; ?> :: <strong>
1141 <?php
1143 flush();
1145 $no_updates = true;
1147 // some code magic
1148 if (version_compare($current_version, '3.0.RC2', '<='))
1150 $smileys = array();
1151 $sql = 'SELECT smiley_id, code
1152 FROM ' . SMILIES_TABLE;
1154 $result = $db->sql_query($sql);
1156 while ($row = $db->sql_fetchrow($result))
1158 $smileys[$row['smiley_id']] = $row['code'];
1160 $db->sql_freeresult($result);
1162 foreach($smileys as $id => $code)
1164 // 2.0 only entitized lt and gt; We need to do something about double quotes.
1165 if (strchr($code, '"') === false)
1167 continue;
1170 $new_code = str_replace('&amp;', '&', $code);
1171 $new_code = str_replace('&lt;', '<', $new_code);
1172 $new_code = str_replace('&gt;', '>', $new_code);
1173 $new_code = utf8_htmlspecialchars($new_code);
1175 $sql = 'UPDATE ' . SMILIES_TABLE . '
1176 SET code = \'' . $db->sql_escape($new_code) . '\'
1177 WHERE smiley_id = ' . (int) $id;
1178 $db->sql_query($sql);
1181 $index_list = sql_list_index($map_dbms, ACL_ROLES_DATA_TABLE);
1183 if (in_array('ath_opt_id', $index_list))
1185 sql_index_drop($map_dbms, 'ath_opt_id', ACL_ROLES_DATA_TABLE);
1186 sql_create_index($map_dbms, 'ath_op_id', ACL_ROLES_DATA_TABLE, array('auth_option_id'));
1189 $no_updates = false;
1192 if (version_compare($current_version, '3.0.RC3', '<='))
1194 if ($map_dbms === 'postgres')
1196 $sql = "SELECT SETVAL('" . FORUMS_TABLE . "_seq',(select case when max(forum_id)>0 then max(forum_id)+1 else 1 end from " . FORUMS_TABLE . '));';
1197 _sql($sql, $errored, $error_ary);
1200 // we check for:
1201 // ath_opt_id
1202 // ath_op_id
1203 // ACL_ROLES_DATA_TABLE_ath_opt_id
1204 // we want ACL_ROLES_DATA_TABLE_ath_op_id
1206 $table_index_fix = array(
1207 ACL_ROLES_DATA_TABLE => array(
1208 'ath_opt_id' => 'ath_op_id',
1209 'ath_op_id' => 'ath_op_id',
1210 ACL_ROLES_DATA_TABLE . '_ath_opt_id' => 'ath_op_id'
1212 STYLES_IMAGESET_DATA_TABLE => array(
1213 'i_id' => 'i_d',
1214 'i_d' => 'i_d',
1215 STYLES_IMAGESET_DATA_TABLE . '_i_id' => 'i_d'
1219 // we need to create some indicies...
1220 $needed_creation = array();
1222 foreach ($table_index_fix as $table_name => $index_info)
1224 $index_list = sql_list_fake($map_dbms, $table_name);
1225 foreach ($index_info as $bad_index => $good_index)
1227 if (in_array($bad_index, $index_list))
1229 // mysql is actually OK, it won't get a hand in this crud
1230 switch ($map_dbms)
1232 // last version, mssql had issues with index removal
1233 case 'mssql':
1234 $sql = 'DROP INDEX ' . $table_name . '.' . $bad_index;
1235 _sql($sql, $errored, $error_ary);
1236 break;
1238 // last version, firebird, oracle, postgresql and sqlite all got bad index names
1239 // we got kinda lucky, tho: they all support the same syntax
1240 case 'firebird':
1241 case 'oracle':
1242 case 'postgres':
1243 case 'sqlite':
1244 $sql = 'DROP INDEX ' . $bad_index;
1245 _sql($sql, $errored, $error_ary);
1246 break;
1249 // If the good index already exist we do not need to create it again...
1250 if (($map_dbms == 'mysql_40' || $map_dbms == 'mysql_41') && $bad_index == $good_index)
1253 else
1255 $needed_creation[$table_name][$good_index] = 1;
1261 $new_index_defs = array('ath_op_id' => array('auth_option_id'), 'i_d' => array('imageset_id'));
1263 foreach ($needed_creation as $bad_table => $index_repair_list)
1265 foreach ($index_repair_list as $new_index => $garbage)
1267 sql_create_index($map_dbms, $new_index, $bad_table, $new_index_defs[$new_index]);
1268 $no_updates = false;
1272 // Make sure empty smiley codes do not exist
1273 $sql = 'DELETE FROM ' . SMILIES_TABLE . "
1274 WHERE code = ''";
1275 _sql($sql, $errored, $error_ary);
1277 set_config('allow_birthdays', '1');
1278 set_config('cron_lock', '0', true);
1280 $no_updates = false;
1283 if (version_compare($current_version, '3.0.RC4', '<='))
1285 $update_auto_increment = array(
1286 STYLES_TABLE => 'style_id',
1287 STYLES_TEMPLATE_TABLE => 'template_id',
1288 STYLES_THEME_TABLE => 'theme_id',
1289 STYLES_IMAGESET_TABLE => 'imageset_id'
1292 $sql = 'SELECT *
1293 FROM ' . STYLES_TABLE . '
1294 WHERE style_id = 0';
1295 $result = _sql($sql, $errored, $error_ary);
1296 $bad_style_row = $db->sql_fetchrow($result);
1297 $db->sql_freeresult($result);
1299 if ($bad_style_row)
1301 $sql = 'SELECT MAX(style_id) as max_id
1302 FROM ' . STYLES_TABLE;
1303 $result = _sql($sql, $errored, $error_ary);
1304 $row = $db->sql_fetchrow($result);
1305 $db->sql_freeresult($result);
1307 $proper_id = $row['max_id'] + 1;
1309 _sql('UPDATE ' . STYLES_TABLE . " SET style_id = $proper_id WHERE style_id = 0", $errored, $error_ary);
1310 _sql('UPDATE ' . FORUMS_TABLE . " SET forum_style = $proper_id WHERE forum_style = 0", $errored, $error_ary);
1311 _sql('UPDATE ' . USERS_TABLE . " SET user_style = $proper_id WHERE user_style = 0", $errored, $error_ary);
1313 $sql = 'SELECT config_value
1314 FROM ' . CONFIG_TABLE . "
1315 WHERE config_name = 'default_style'";
1316 $result = _sql($sql, $errored, $error_ary);
1317 $style_config = $db->sql_fetchrow($result);
1318 $db->sql_freeresult($result);
1320 if ($style_config['config_value'] === '0')
1322 set_config('default_style', (string) $proper_id);
1326 $sql = 'SELECT *
1327 FROM ' . STYLES_TEMPLATE_TABLE . '
1328 WHERE template_id = 0';
1329 $result = _sql($sql, $errored, $error_ary);
1330 $bad_style_row = $db->sql_fetchrow($result);
1331 $db->sql_freeresult($result);
1333 if ($bad_style_row)
1335 $sql = 'SELECT MAX(template_id) as max_id
1336 FROM ' . STYLES_TEMPLATE_TABLE;
1337 $result = _sql($sql, $errored, $error_ary);
1338 $row = $db->sql_fetchrow($result);
1339 $db->sql_freeresult($result);
1341 $proper_id = $row['max_id'] + 1;
1343 _sql('UPDATE ' . STYLES_TABLE . " SET template_id = $proper_id WHERE template_id = 0", $errored, $error_ary);
1346 $sql = 'SELECT *
1347 FROM ' . STYLES_THEME_TABLE . '
1348 WHERE theme_id = 0';
1349 $result = _sql($sql, $errored, $error_ary);
1350 $bad_style_row = $db->sql_fetchrow($result);
1351 $db->sql_freeresult($result);
1353 if ($bad_style_row)
1355 $sql = 'SELECT MAX(theme_id) as max_id
1356 FROM ' . STYLES_THEME_TABLE;
1357 $result = _sql($sql, $errored, $error_ary);
1358 $row = $db->sql_fetchrow($result);
1359 $db->sql_freeresult($result);
1361 $proper_id = $row['max_id'] + 1;
1363 _sql('UPDATE ' . STYLES_TABLE . " SET theme_id = $proper_id WHERE theme_id = 0", $errored, $error_ary);
1366 $sql = 'SELECT *
1367 FROM ' . STYLES_IMAGESET_TABLE . '
1368 WHERE imageset_id = 0';
1369 $result = _sql($sql, $errored, $error_ary);
1370 $bad_style_row = $db->sql_fetchrow($result);
1371 $db->sql_freeresult($result);
1373 if ($bad_style_row)
1375 $sql = 'SELECT MAX(imageset_id) as max_id
1376 FROM ' . STYLES_IMAGESET_TABLE;
1377 $result = _sql($sql, $errored, $error_ary);
1378 $row = $db->sql_fetchrow($result);
1379 $db->sql_freeresult($result);
1381 $proper_id = $row['max_id'] + 1;
1383 _sql('UPDATE ' . STYLES_TABLE . " SET imageset_id = $proper_id WHERE imageset_id = 0", $errored, $error_ary);
1384 _sql('UPDATE ' . STYLES_IMAGESET_DATA_TABLE . " SET imageset_id = $proper_id WHERE imageset_id = 0", $errored, $error_ary);
1387 if ($map_dbms == 'mysql_40' || $map_dbms == 'mysql_41')
1389 foreach ($update_auto_increment as $auto_table_name => $auto_column_name)
1391 $sql = "SELECT MAX({$auto_column_name}) as max_id
1392 FROM {$auto_table_name}";
1393 $result = _sql($sql, $errored, $error_ary);
1394 $row = $db->sql_fetchrow($result);
1395 $db->sql_freeresult($result);
1397 $max_id = ((int) $row['max_id']) + 1;
1398 _sql("ALTER TABLE {$auto_table_name} AUTO_INCREMENT = {$max_id}", $errored, $error_ary);
1401 $no_updates = false;
1403 else if ($map_dbms == 'postgres')
1405 foreach ($update_auto_increment as $auto_table_name => $auto_column_name)
1407 $sql = "SELECT SETVAL('" . $auto_table_name . "_seq',(select case when max({$auto_column_name})>0 then max({$auto_column_name})+1 else 1 end from " . $auto_table_name . '));';
1408 _sql($sql, $errored, $error_ary);
1411 $sql = 'DROP SEQUENCE ' . STYLES_TEMPLATE_DATA_TABLE . '_seq';
1412 _sql($sql, $errored, $error_ary);
1414 else if ($map_dbms == 'firebird')
1416 $sql = 'DROP TRIGGER t_' . STYLES_TEMPLATE_DATA_TABLE;
1417 _sql($sql, $errored, $error_ary);
1419 $sql = 'DROP GENERATOR ' . STYLES_TEMPLATE_DATA_TABLE . '_gen';
1420 _sql($sql, $errored, $error_ary);
1422 else if ($map_dbms == 'oracle')
1424 $sql = 'DROP TRIGGER t_' . STYLES_TEMPLATE_DATA_TABLE;
1425 _sql($sql, $errored, $error_ary);
1427 $sql = 'DROP SEQUENCE ' . STYLES_TEMPLATE_DATA_TABLE . '_seq';
1428 _sql($sql, $errored, $error_ary);
1430 else if ($map_dbms == 'mssql')
1432 // we use transactions because we need to have a working DB at the end of all of this
1433 $db->sql_transaction('begin');
1435 $sql = 'SELECT *
1436 FROM ' . STYLES_TEMPLATE_DATA_TABLE;
1437 $result = _sql($sql, $errored, $error_ary);
1438 $old_style_rows = array();
1439 while ($row = $db->sql_fetchrow($result))
1441 $old_style_rows[] = $row;
1443 $db->sql_freeresult($result);
1445 // death to the table, it is evil!
1446 $sql = 'DROP TABLE ' . STYLES_TEMPLATE_DATA_TABLE;
1447 _sql($sql, $errored, $error_ary);
1449 // the table of awesomeness, praise be to it (or something)
1450 $sql = 'CREATE TABLE [' . STYLES_TEMPLATE_DATA_TABLE . "] (
1451 [template_id] [int] DEFAULT (0) NOT NULL ,
1452 [template_filename] [varchar] (100) DEFAULT ('') NOT NULL ,
1453 [template_included] [varchar] (8000) DEFAULT ('') NOT NULL ,
1454 [template_mtime] [int] DEFAULT (0) NOT NULL ,
1455 [template_data] [text] DEFAULT ('') NOT NULL
1456 ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]";
1457 _sql($sql, $errored, $error_ary);
1459 // index? index
1460 $sql = 'CREATE INDEX [tid] ON [' . STYLES_TEMPLATE_DATA_TABLE . ']([template_id]) ON [PRIMARY]';
1461 _sql($sql, $errored, $error_ary);
1463 // yet another index
1464 $sql = 'CREATE INDEX [tfn] ON [' . STYLES_TEMPLATE_DATA_TABLE . ']([template_filename]) ON [PRIMARY]';
1465 _sql($sql, $errored, $error_ary);
1467 foreach ($old_style_rows as $return_row)
1469 _sql('INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $return_row), $errored, $error_ary);
1472 $db->sql_transaction('commit');
1475 // Setting this here again because new installations may not have it...
1476 set_config('cron_lock', '0', true);
1477 set_config('ldap_port', '');
1478 set_config('ldap_user_filter', '');
1480 $no_updates = false;
1483 if (version_compare($current_version, '3.0.RC5', '<='))
1485 // In case the user is having the bot mediapartner google "as is", adjust it.
1486 $sql = 'UPDATE ' . BOTS_TABLE . "
1487 SET bot_agent = '" . $db->sql_escape('Mediapartners-Google') . "'
1488 WHERE bot_agent = '" . $db->sql_escape('Mediapartners-Google/') . "'";
1489 _sql($sql, $errored, $error_ary);
1491 set_config('form_token_lifetime', '7200');
1492 set_config('form_token_mintime', '0');
1494 $db->sql_transaction('begin');
1496 $sql = 'SELECT forum_id, forum_password
1497 FROM ' . FORUMS_TABLE;
1498 $result = _sql($sql, $errored, $error_ary);
1500 while ($row = $db->sql_fetchrow($result))
1502 if (!empty($row['forum_password']))
1504 _sql('UPDATE ' . FORUMS_TABLE . " SET forum_password = '" . md5($row['forum_password']) . "' WHERE forum_id = {$row['forum_id']}", $errored, $error_ary);
1507 $db->sql_freeresult($result);
1509 $db->sql_transaction('commit');
1511 $no_updates = false;
1514 _write_result($no_updates, $errored, $error_ary);
1516 $error_ary = array();
1517 $errored = $no_updates = false;
1521 <br /><br />
1522 <h1><?php echo $lang['UPDATE_VERSION_OPTIMIZE']; ?></h1>
1523 <br />
1524 <p><?php echo $lang['PROGRESS']; ?> :: <strong>
1526 <?php
1528 flush();
1530 // update the version
1531 $sql = "UPDATE " . CONFIG_TABLE . "
1532 SET config_value = '$updates_to_version'
1533 WHERE config_name = 'version'";
1534 _sql($sql, $errored, $error_ary);
1536 // Reset permissions
1537 $sql = 'UPDATE ' . USERS_TABLE . "
1538 SET user_permissions = ''";
1539 _sql($sql, $errored, $error_ary);
1541 /* Optimize/vacuum analyze the tables where appropriate
1542 // this should be done for each version in future along with
1543 // the version number update
1544 switch ($db->sql_layer)
1546 case 'mysql':
1547 case 'mysqli':
1548 case 'mysql4':
1549 $sql = 'OPTIMIZE TABLE ' . $table_prefix . 'auth_access, ' . $table_prefix . 'banlist, ' . $table_prefix . 'categories, ' . $table_prefix . 'config, ' . $table_prefix . 'disallow, ' . $table_prefix . 'forum_prune, ' . $table_prefix . 'forums, ' . $table_prefix . 'groups, ' . $table_prefix . 'posts, ' . $table_prefix . 'posts_text, ' . $table_prefix . 'privmsgs, ' . $table_prefix . 'privmsgs_text, ' . $table_prefix . 'ranks, ' . $table_prefix . 'search_results, ' . $table_prefix . 'search_wordlist, ' . $table_prefix . 'search_wordmatch, ' . $table_prefix . 'sessions_keys' . $table_prefix . 'smilies, ' . $table_prefix . 'themes, ' . $table_prefix . 'themes_name, ' . $table_prefix . 'topics, ' . $table_prefix . 'topics_watch, ' . $table_prefix . 'user_group, ' . $table_prefix . 'users, ' . $table_prefix . 'vote_desc, ' . $table_prefix . 'vote_results, ' . $table_prefix . 'vote_voters, ' . $table_prefix . 'words';
1550 _sql($sql, $errored, $error_ary);
1551 break;
1553 case 'postgresql':
1554 _sql("VACUUM ANALYZE", $errored, $error_ary);
1555 break;
1559 _write_result($no_updates, $errored, $error_ary);
1563 <br />
1564 <h1><?php echo $lang['UPDATE_COMPLETED']; ?></h1>
1566 <br />
1568 <?php
1570 if (!$inline_update)
1574 <p style="color:red"><?php echo $lang['UPDATE_FILES_NOTICE']; ?></p>
1576 <p><?php echo $lang['COMPLETE_LOGIN_TO_BOARD']; ?></p>
1578 <?php
1580 else
1584 <p><?php echo ((isset($lang['INLINE_UPDATE_SUCCESSFUL'])) ? $lang['INLINE_UPDATE_SUCCESSFUL'] : 'The database update was successful. Now you need to continue the update process.'); ?></p>
1586 <p><a href="<?php echo append_sid("{$phpbb_root_path}install/index.{$phpEx}", "mode=update&amp;sub=file_check&amp;lang=$language"); ?>" class="button1"><?php echo (isset($lang['CONTINUE_UPDATE_NOW'])) ? $lang['CONTINUE_UPDATE_NOW'] : 'Continue the update process now'; ?></a></p>
1588 <?php
1591 // Add database update to log
1592 add_log('admin', 'LOG_UPDATE_DATABASE', $orig_version, $updates_to_version);
1594 // Now we purge the session table as well as all cache files
1595 $cache->purge();
1599 </div>
1600 </div>
1601 <span class="corners-bottom"><span></span></span>
1602 </div>
1603 </div>
1604 </div>
1606 <div id="page-footer">
1607 Powered by phpBB &copy; 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>
1608 </div>
1609 </div>
1611 </body>
1612 </html>
1614 <?php
1616 exit_handler();
1620 * Function for triggering an sql statement
1622 function _sql($sql, &$errored, &$error_ary, $echo_dot = true)
1624 global $db;
1626 if (defined('DEBUG_EXTRA'))
1628 echo "<br />\n{$sql}\n<br />";
1631 $db->sql_return_on_error(true);
1633 $result = $db->sql_query($sql);
1634 if ($db->sql_error_triggered)
1636 $errored = true;
1637 $error_ary['sql'][] = $db->sql_error_sql;
1638 $error_ary['error_code'][] = $db->_sql_error();
1641 $db->sql_return_on_error(false);
1643 if ($echo_dot)
1645 echo ". \n";
1646 flush();
1649 return $result;
1652 function _write_result($no_updates, $errored, $error_ary)
1654 global $lang;
1656 if ($no_updates)
1658 echo ' ' . $lang['NO_UPDATES_REQUIRED'] . '</strong></p>';
1660 else
1662 echo ' <span class="success">' . $lang['DONE'] . '</span></strong><br />' . $lang['RESULT'] . ' :: ';
1664 if ($errored)
1666 echo ' <strong>' . $lang['SOME_QUERIES_FAILED'] . '</strong> <ul>';
1668 for ($i = 0; $i < sizeof($error_ary['sql']); $i++)
1670 echo '<li>' . $lang['ERROR'] . ' :: <strong>' . htmlspecialchars($error_ary['error_code'][$i]['message']) . '</strong><br />';
1671 echo $lang['SQL'] . ' :: <strong>' . htmlspecialchars($error_ary['sql'][$i]) . '</strong><br /><br /></li>';
1674 echo '</ul> <br /><br />' . $lang['SQL_FAILURE_EXPLAIN'] . '</p>';
1676 else
1678 echo '<strong>' . $lang['NO_ERRORS'] . '</strong></p>';
1684 * Check if a specified column exist
1686 function column_exists($dbms, $table, $column_name)
1688 global $db;
1690 switch ($dbms)
1692 case 'mysql_40':
1693 case 'mysql_41':
1694 $sql = "SHOW COLUMNS
1695 FROM $table";
1696 $result = $db->sql_query($sql);
1697 while ($row = $db->sql_fetchrow($result))
1699 // lower case just in case
1700 if (strtolower($row['Field']) == $column_name)
1702 $db->sql_freeresult($result);
1703 return true;
1706 $db->sql_freeresult($result);
1707 return false;
1708 break;
1710 // PostgreSQL has a way of doing this in a much simpler way but would
1711 // not allow us to support all versions of PostgreSQL
1712 case 'postgres':
1713 $sql = "SELECT a.attname
1714 FROM pg_class c, pg_attribute a
1715 WHERE c.relname = '{$table}'
1716 AND a.attnum > 0
1717 AND a.attrelid = c.oid";
1718 $result = $db->sql_query($sql);
1719 while ($row = $db->sql_fetchrow($result))
1721 // lower case just in case
1722 if (strtolower($row['attname']) == $column_name)
1724 $db->sql_freeresult($result);
1725 return true;
1728 $db->sql_freeresult($result);
1729 return false;
1730 break;
1732 // same deal with PostgreSQL, we must perform more complex operations than
1733 // we technically could
1734 case 'mssql':
1735 $sql = "SELECT c.name
1736 FROM syscolumns c
1737 LEFT JOIN sysobjects o (ON c.id = o.id)
1738 WHERE o.name = '{$table}'";
1739 $result = $db->sql_query($sql);
1740 while ($row = $db->sql_fetchrow($result))
1742 // lower case just in case
1743 if (strtolower($row['name']) == $column_name)
1745 $db->sql_freeresult($result);
1746 return true;
1749 $db->sql_freeresult($result);
1750 return false;
1751 break;
1753 case 'oracle':
1754 $sql = "SELECT column_name
1755 FROM user_tab_columns
1756 WHERE table_name = '{$table}'";
1757 $result = $db->sql_query($sql);
1758 while ($row = $db->sql_fetchrow($result))
1760 // lower case just in case
1761 if (strtolower($row['column_name']) == $column_name)
1763 $db->sql_freeresult($result);
1764 return true;
1767 $db->sql_freeresult($result);
1768 return false;
1769 break;
1771 case 'firebird':
1772 $sql = "SELECT RDB\$FIELD_NAME as FNAME
1773 FROM RDB\$RELATION_FIELDS
1774 WHERE RDB\$RELATION_NAME = '{$table}'";
1775 $result = $db->sql_query($sql);
1776 while ($row = $db->sql_fetchrow($result))
1778 // lower case just in case
1779 if (strtolower($row['fname']) == $column_name)
1781 $db->sql_freeresult($result);
1782 return true;
1785 $db->sql_freeresult($result);
1786 return false;
1787 break;
1789 // ugh, SQLite
1790 case 'sqlite':
1791 $sql = "SELECT sql
1792 FROM sqlite_master
1793 WHERE type = 'table'
1794 AND name = '{$table}'";
1795 $result = $db->sql_query($sql);
1797 if (!$result)
1799 return false;
1802 $row = $db->sql_fetchrow($result);
1803 $db->sql_freeresult($result);
1805 preg_match('#\((.*)\)#s', $row['sql'], $matches);
1807 $cols = trim($matches[1]);
1808 $col_array = preg_split('/,(?![\s\w]+\))/m', $cols);
1810 foreach ($col_array as $declaration)
1812 $entities = preg_split('#\s+#', trim($declaration));
1813 if ($entities[0] == 'PRIMARY')
1815 continue;
1818 if (strtolower($entities[0]) == $column_name)
1820 return true;
1823 return false;
1824 break;
1829 * Function to prepare some column information for better usage
1831 function prepare_column_data($dbms, $column_data, $table_name, $column_name)
1833 global $dbms_type_map, $unsigned_types;
1835 // Get type
1836 if (strpos($column_data[0], ':') !== false)
1838 list($orig_column_type, $column_length) = explode(':', $column_data[0]);
1840 if (!is_array($dbms_type_map[$dbms][$orig_column_type . ':']))
1842 $column_type = sprintf($dbms_type_map[$dbms][$orig_column_type . ':'], $column_length);
1844 else
1846 if (isset($dbms_type_map[$dbms][$orig_column_type . ':']['rule']))
1848 switch ($dbms_type_map[$dbms][$orig_column_type . ':']['rule'][0])
1850 case 'div':
1851 $column_length /= $dbms_type_map[$dbms][$orig_column_type . ':']['rule'][1];
1852 $column_length = ceil($column_length);
1853 $column_type = sprintf($dbms_type_map[$dbms][$orig_column_type . ':'][0], $column_length);
1854 break;
1858 if (isset($dbms_type_map[$dbms][$orig_column_type . ':']['limit']))
1860 switch ($dbms_type_map[$dbms][$orig_column_type . ':']['limit'][0])
1862 case 'mult':
1863 $column_length *= $dbms_type_map[$dbms][$orig_column_type . ':']['limit'][1];
1864 if ($column_length > $dbms_type_map[$dbms][$orig_column_type . ':']['limit'][2])
1866 $column_type = $dbms_type_map[$dbms][$orig_column_type . ':']['limit'][3];
1868 else
1870 $column_type = sprintf($dbms_type_map[$dbms][$orig_column_type . ':'][0], $column_length);
1872 break;
1876 $orig_column_type .= ':';
1878 else
1880 $orig_column_type = $column_data[0];
1881 $column_type = $dbms_type_map[$dbms][$column_data[0]];
1884 // Adjust default value if db-dependant specified
1885 if (is_array($column_data[1]))
1887 $column_data[1] = (isset($column_data[1][$dbms])) ? $column_data[1][$dbms] : $column_data[1]['default'];
1890 $sql = '';
1892 $return_array = array();
1894 switch ($dbms)
1896 case 'firebird':
1897 $sql .= " {$column_type} ";
1899 if (!is_null($column_data[1]))
1901 $sql .= 'DEFAULT ' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' ';
1904 $sql .= 'NOT NULL';
1906 // This is a UNICODE column and thus should be given it's fair share
1907 if (preg_match('/^X?STEXT_UNI|VCHAR_(CI|UNI:?)/', $column_data[0]))
1909 $sql .= ' COLLATE UNICODE';
1912 break;
1914 case 'mssql':
1915 $sql .= " {$column_type} ";
1917 // we do not support MSSQL DEFAULTs for the near future
1918 /*if (!is_null($column_data[1]))
1920 // For hexadecimal values do not use single quotes
1921 if (strpos($column_data[1], '0x') === 0)
1923 $sql .= 'DEFAULT (' . $column_data[1] . ') ';
1925 else
1927 $sql .= 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') ';
1931 $sql .= 'NOT NULL';
1932 break;
1934 case 'mysql_40':
1935 case 'mysql_41':
1936 $sql .= " {$column_type} ";
1938 // For hexadecimal values do not use single quotes
1939 if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob')
1941 $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' ";
1943 $sql .= 'NOT NULL';
1945 if (isset($column_data[2]))
1947 if ($column_data[2] == 'auto_increment')
1949 $sql .= ' auto_increment';
1951 else if ($dbms === 'mysql_41' && $column_data[2] == 'true_sort')
1953 $sql .= ' COLLATE utf8_unicode_ci';
1957 break;
1959 case 'oracle':
1960 $sql .= " {$column_type} ";
1961 $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}' " : '';
1963 // In Oracle empty strings ('') are treated as NULL.
1964 // Therefore in oracle we allow NULL's for all DEFAULT '' entries
1965 // Oracle does not like setting NOT NULL on a column that is already NOT NULL (this happens only on number fields)
1966 if (preg_match('/number/i', $column_type))
1968 $sql .= ($column_data[1] === '') ? '' : 'NOT NULL';
1970 break;
1972 case 'postgres':
1973 $return_array['column_type'] = $column_type;
1975 $sql .= " {$column_type} ";
1977 if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
1979 $default_val = "nextval('{$table_name}_seq')";
1981 else if (!is_null($column_data[1]))
1983 $default_val = "'" . $column_data[1] . "'";
1984 $return_array['null'] = 'NOT NULL';
1985 $sql .= 'NOT NULL ';
1988 $return_array['default'] = $default_val;
1990 $sql .= "DEFAULT {$default_val}";
1992 // Unsigned? Then add a CHECK contraint
1993 if (in_array($orig_column_type, $unsigned_types))
1995 $return_array['constraint'] = "CHECK ({$column_name} >= 0)";
1996 $sql .= " CHECK ({$column_name} >= 0)";
1998 break;
2000 case 'sqlite':
2001 if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
2003 $sql .= ' INTEGER PRIMARY KEY';
2005 else
2007 $sql .= ' ' . $column_type;
2010 $sql .= ' NOT NULL ';
2011 $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}'" : '';
2012 break;
2015 $return_array['column_type_sql'] = $sql;
2017 return $return_array;
2021 * Add new column
2023 function sql_column_add($dbms, $table_name, $column_name, $column_data)
2025 global $errored, $error_ary;
2027 $column_data = prepare_column_data($dbms, $column_data, $table_name, $column_name);
2029 switch ($dbms)
2031 case 'firebird':
2032 $sql = 'ALTER TABLE "' . $table_name . '" ADD "' . $column_name . '" ' . $column_data['column_type_sql'];
2033 _sql($sql, $errored, $error_ary);
2034 break;
2036 case 'mssql':
2037 $sql = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql'];
2038 _sql($sql, $errored, $error_ary);
2039 break;
2041 case 'mysql_40':
2042 case 'mysql_41':
2043 $sql = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'];
2044 _sql($sql, $errored, $error_ary);
2045 break;
2047 case 'oracle':
2048 $sql = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
2049 _sql($sql, $errored, $error_ary);
2050 break;
2052 case 'postgres':
2053 $sql = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
2054 _sql($sql, $errored, $error_ary);
2055 break;
2057 case 'sqlite':
2058 if (version_compare(sqlite_libversion(), '3.0') == -1)
2060 global $db;
2061 $sql = "SELECT sql
2062 FROM sqlite_master
2063 WHERE type = 'table'
2064 AND name = '{$table_name}'
2065 ORDER BY type DESC, name;";
2066 $result = $db->sql_query($sql);
2068 if (!$result)
2070 break;
2073 $row = $db->sql_fetchrow($result);
2074 $db->sql_freeresult($result);
2076 $db->sql_transaction('begin');
2078 // Create a backup table and populate it, destroy the existing one
2079 $db->sql_query(preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']));
2080 $db->sql_query('INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name);
2081 $db->sql_query('DROP TABLE ' . $table_name);
2083 preg_match('#\((.*)\)#s', $row['sql'], $matches);
2085 $new_table_cols = trim($matches[1]);
2086 $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
2087 $column_list = array();
2089 foreach ($old_table_cols as $declaration)
2091 $entities = preg_split('#\s+#', trim($declaration));
2092 if ($entities[0] == 'PRIMARY')
2094 continue;
2096 $column_list[] = $entities[0];
2099 $columns = implode(',', $column_list);
2101 $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols;
2103 // create a new table and fill it up. destroy the temp one
2104 $db->sql_query('CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');');
2105 $db->sql_query('INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;');
2106 $db->sql_query('DROP TABLE ' . $table_name . '_temp');
2108 $db->sql_transaction('commit');
2110 else
2112 $sql = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' [' . $column_data['column_type_sql'] . ']';
2113 _sql($sql, $errored, $error_ary);
2115 break;
2120 * Drop column
2122 function sql_column_remove($dbms, $table_name, $column_name)
2124 global $errored, $error_ary;
2126 switch ($dbms)
2128 case 'firebird':
2129 $sql = 'ALTER TABLE "' . $table_name . '" DROP "' . $column_name . '"';
2130 _sql($sql, $errored, $error_ary);
2131 break;
2133 case 'mssql':
2134 $sql = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']';
2135 _sql($sql, $errored, $error_ary);
2136 break;
2138 case 'mysql_40':
2139 case 'mysql_41':
2140 $sql = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`';
2141 _sql($sql, $errored, $error_ary);
2142 break;
2144 case 'oracle':
2145 $sql = 'ALTER TABLE ' . $table_name . ' DROP ' . $column_name;
2146 _sql($sql, $errored, $error_ary);
2147 break;
2149 case 'postgres':
2150 $sql = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"';
2151 _sql($sql, $errored, $error_ary);
2152 break;
2154 case 'sqlite':
2155 if (version_compare(sqlite_libversion(), '3.0') == -1)
2157 global $db;
2158 $sql = "SELECT sql
2159 FROM sqlite_master
2160 WHERE type = 'table'
2161 AND name = '{$table_name}'
2162 ORDER BY type DESC, name;";
2163 $result = $db->sql_query($sql);
2165 if (!$result)
2167 break;
2170 $row = $db->sql_fetchrow($result);
2171 $db->sql_freeresult($result);
2173 $db->sql_transaction('begin');
2175 // Create a backup table and populate it, destroy the existing one
2176 $db->sql_query(preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']));
2177 $db->sql_query('INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name);
2178 $db->sql_query('DROP TABLE ' . $table_name);
2180 preg_match('#\((.*)\)#s', $row['sql'], $matches);
2182 $new_table_cols = trim($matches[1]);
2183 $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
2184 $column_list = array();
2186 foreach ($old_table_cols as $declaration)
2188 $entities = preg_split('#\s+#', trim($declaration));
2189 if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name)
2191 continue;
2193 $column_list[] = $entities[0];
2196 $columns = implode(',', $column_list);
2198 $new_table_cols = $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols);
2200 // create a new table and fill it up. destroy the temp one
2201 $db->sql_query('CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');');
2202 $db->sql_query('INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;');
2203 $db->sql_query('DROP TABLE ' . $table_name . '_temp');
2205 $db->sql_transaction('commit');
2207 else
2209 $sql = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name;
2210 _sql($sql, $errored, $error_ary);
2212 break;
2216 function sql_index_drop($dbms, $index_name, $table_name)
2218 global $dbms_type_map, $db;
2219 global $errored, $error_ary;
2221 switch ($dbms)
2223 case 'mssql':
2224 $sql = 'DROP INDEX ' . $table_name . '.' . $index_name;
2225 _sql($sql, $errored, $error_ary);
2226 break;
2228 case 'mysql_40':
2229 case 'mysql_41':
2230 $sql = 'DROP INDEX ' . $index_name . ' ON ' . $table_name;
2231 _sql($sql, $errored, $error_ary);
2232 break;
2234 case 'firebird':
2235 case 'oracle':
2236 case 'postgres':
2237 case 'sqlite':
2238 $sql = 'DROP INDEX ' . $table_name . '_' . $index_name;
2239 _sql($sql, $errored, $error_ary);
2240 break;
2244 function sql_create_primary_key($dbms, $table_name, $column)
2246 global $dbms_type_map, $db;
2247 global $errored, $error_ary;
2249 switch ($dbms)
2251 case 'firebird':
2252 case 'postgres':
2253 $sql = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
2254 _sql($sql, $errored, $error_ary);
2255 break;
2257 case 'mssql':
2258 $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD ";
2259 $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED (";
2260 $sql .= '[' . implode("],\n\t\t[", $column) . ']';
2261 $sql .= ') ON [PRIMARY]';
2262 _sql($sql, $errored, $error_ary);
2263 break;
2265 case 'mysql_40':
2266 case 'mysql_41':
2267 $sql = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
2268 _sql($sql, $errored, $error_ary);
2269 break;
2271 case 'oracle':
2272 $sql = 'ALTER TABLE ' . $table_name . 'add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')';
2273 _sql($sql, $errored, $error_ary);
2274 break;
2276 case 'sqlite':
2277 $sql = "SELECT sql
2278 FROM sqlite_master
2279 WHERE type = 'table'
2280 AND name = '{$table_name}'
2281 ORDER BY type DESC, name;";
2282 $result = _sql($sql, $errored, $error_ary);
2284 if (!$result)
2286 break;
2289 $row = $db->sql_fetchrow($result);
2290 $db->sql_freeresult($result);
2292 $db->sql_transaction('begin');
2294 // Create a backup table and populate it, destroy the existing one
2295 $db->sql_query(preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']));
2296 $db->sql_query('INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name);
2297 $db->sql_query('DROP TABLE ' . $table_name);
2299 preg_match('#\((.*)\)#s', $row['sql'], $matches);
2301 $new_table_cols = trim($matches[1]);
2302 $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
2303 $column_list = array();
2305 foreach ($old_table_cols as $declaration)
2307 $entities = preg_split('#\s+#', trim($declaration));
2308 if ($entities[0] == 'PRIMARY')
2310 continue;
2312 $column_list[] = $entities[0];
2315 $columns = implode(',', $column_list);
2317 // create a new table and fill it up. destroy the temp one
2318 $db->sql_query('CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));');
2319 $db->sql_query('INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;');
2320 $db->sql_query('DROP TABLE ' . $table_name . '_temp');
2322 $db->sql_transaction('commit');
2323 break;
2327 function sql_create_unique_index($dbms, $index_name, $table_name, $column)
2329 global $dbms_type_map, $db;
2330 global $errored, $error_ary;
2332 switch ($dbms)
2334 case 'firebird':
2335 case 'postgres':
2336 case 'oracle':
2337 case 'sqlite':
2338 $sql = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
2339 _sql($sql, $errored, $error_ary);
2340 break;
2342 case 'mysql_40':
2343 case 'mysql_41':
2344 $sql = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
2345 _sql($sql, $errored, $error_ary);
2346 break;
2348 case 'mssql':
2349 $sql = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]';
2350 _sql($sql, $errored, $error_ary);
2351 break;
2355 function sql_create_index($dbms, $index_name, $table_name, $column)
2357 global $dbms_type_map, $db;
2358 global $errored, $error_ary;
2360 switch ($dbms)
2362 case 'firebird':
2363 case 'postgres':
2364 case 'oracle':
2365 case 'sqlite':
2366 $sql = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
2367 _sql($sql, $errored, $error_ary);
2368 break;
2370 case 'mysql_40':
2371 case 'mysql_41':
2372 $sql = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
2373 _sql($sql, $errored, $error_ary);
2374 break;
2376 case 'mssql':
2377 $sql = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]';
2378 _sql($sql, $errored, $error_ary);
2379 break;
2383 // List all of the indices that belong to a table,
2384 // does not count:
2385 // * UNIQUE indices
2386 // * PRIMARY keys
2387 function sql_list_index($dbms, $table_name)
2389 global $dbms_type_map, $db;
2390 global $errored, $error_ary;
2392 $index_array = array();
2394 if ($dbms == 'mssql')
2396 $sql = "EXEC sp_statistics '$table_name'";
2397 $result = $db->sql_query($sql);
2398 while ($row = $db->sql_fetchrow($result))
2400 if ($row['TYPE'] == 3)
2402 $index_array[] = $row['INDEX_NAME'];
2405 $db->sql_freeresult($result);
2407 else
2409 switch ($dbms)
2411 case 'firebird':
2412 $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
2413 FROM RDB\$INDICES
2414 WHERE RDB\$RELATION_NAME = " . strtoupper($table_name) . "
2415 AND RDB\$UNIQUE_FLAG IS NULL
2416 AND RDB\$FOREIGN_KEY IS NULL";
2417 $col = 'index_name';
2418 break;
2420 case 'postgres':
2421 $sql = "SELECT ic.relname as index_name
2422 FROM pg_class bc, pg_class ic, pg_index i
2423 WHERE (bc.oid = i.indrelid)
2424 AND (ic.oid = i.indexrelid)
2425 AND (bc.relname = '" . $table_name . "')
2426 AND (i.indisunique != 't')
2427 AND (i.indisprimary != 't')";
2428 $col = 'index_name';
2429 break;
2431 case 'mysql_40':
2432 case 'mysql_41':
2433 $sql = 'SHOW KEYS
2434 FROM ' . $table_name;
2435 $col = 'Key_name';
2436 break;
2438 case 'oracle':
2439 $sql = "SELECT index_name
2440 FROM user_indexes
2441 WHERE table_name = '" . $table_name . "'
2442 AND generated = 'N'";
2443 break;
2445 case 'sqlite':
2446 $sql = "PRAGMA index_info('" . $table_name . "');";
2447 $col = 'name';
2448 break;
2451 $result = $db->sql_query($sql);
2452 while ($row = $db->sql_fetchrow($result))
2454 if (($dbms == 'mysql_40' || $dbms == 'mysql_41') && !$row['Non_unique'])
2456 continue;
2459 switch ($dbms)
2461 case 'firebird':
2462 case 'oracle':
2463 case 'postgres':
2464 case 'sqlite':
2465 $row[$col] = substr($row[$col], strlen($table_name) + 1);
2466 break;
2469 $index_array[] = $row[$col];
2471 $db->sql_freeresult($result);
2474 return array_map('strtolower', $index_array);
2477 // This is totally fake, never use it
2478 // it exists only to mend bad update functions introduced
2479 // * UNIQUE indices
2480 // * PRIMARY keys
2481 function sql_list_fake($dbms, $table_name)
2483 global $dbms_type_map, $db;
2484 global $errored, $error_ary;
2486 $index_array = array();
2488 if ($dbms == 'mssql')
2490 $sql = "EXEC sp_statistics '$table_name'";
2491 $result = $db->sql_query($sql);
2492 while ($row = $db->sql_fetchrow($result))
2494 if ($row['TYPE'] == 3)
2496 $index_array[] = $row['INDEX_NAME'];
2499 $db->sql_freeresult($result);
2501 else
2503 switch ($dbms)
2505 case 'firebird':
2506 $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
2507 FROM RDB\$INDICES
2508 WHERE RDB\$RELATION_NAME = " . strtoupper($table_name) . "
2509 AND RDB\$UNIQUE_FLAG IS NULL
2510 AND RDB\$FOREIGN_KEY IS NULL";
2511 $col = 'index_name';
2512 break;
2514 case 'postgres':
2515 $sql = "SELECT ic.relname as index_name
2516 FROM pg_class bc, pg_class ic, pg_index i
2517 WHERE (bc.oid = i.indrelid)
2518 AND (ic.oid = i.indexrelid)
2519 AND (bc.relname = '" . $table_name . "')
2520 AND (i.indisunique != 't')
2521 AND (i.indisprimary != 't')";
2522 $col = 'index_name';
2523 break;
2525 case 'mysql_40':
2526 case 'mysql_41':
2527 $sql = 'SHOW KEYS
2528 FROM ' . $table_name;
2529 $col = 'Key_name';
2530 break;
2532 case 'oracle':
2533 $sql = "SELECT index_name
2534 FROM user_indexes
2535 WHERE table_name = '" . $table_name . "'
2536 AND generated = 'N'";
2537 break;
2539 case 'sqlite':
2540 $sql = "PRAGMA index_info('" . $table_name . "');";
2541 $col = 'name';
2542 break;
2545 $result = $db->sql_query($sql);
2546 while ($row = $db->sql_fetchrow($result))
2548 if (($dbms == 'mysql_40' || $dbms == 'mysql_41') && !$row['Non_unique'])
2550 continue;
2553 $index_array[] = $row[$col];
2555 $db->sql_freeresult($result);
2558 return array_map('strtolower', $index_array);
2562 * Change column type (not name!)
2564 function sql_column_change($dbms, $table_name, $column_name, $column_data)
2566 global $dbms_type_map, $db;
2567 global $errored, $error_ary;
2569 $column_data = prepare_column_data($dbms, $column_data, $table_name, $column_name);
2571 switch ($dbms)
2573 case 'firebird':
2574 // Change type...
2575 $sql = 'ALTER TABLE "' . $table_name . '" ALTER COLUMN "' . $column_name . '" TYPE ' . ' ' . $column_data['column_type_sql'];
2576 _sql($sql, $errored, $error_ary);
2577 break;
2579 case 'mssql':
2580 $sql = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql'];
2581 _sql($sql, $errored, $error_ary);
2582 break;
2584 case 'mysql_40':
2585 case 'mysql_41':
2586 $sql = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql'];
2587 _sql($sql, $errored, $error_ary);
2588 break;
2590 case 'oracle':
2591 $sql = 'ALTER TABLE ' . $table_name . ' MODIFY ' . $column_name . ' ' . $column_data['column_type_sql'];
2592 _sql($sql, $errored, $error_ary);
2593 break;
2595 case 'postgres':
2596 $sql = 'ALTER TABLE ' . $table_name . ' ';
2598 $sql_array = array();
2599 $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type'];
2601 if (isset($column_data['null']))
2603 if ($column_data['null'] == 'NOT NULL')
2605 $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL';
2607 else if ($column_data['null'] == 'NULL')
2609 $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL';
2613 if (isset($column_data['default']))
2615 $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
2618 // we don't want to double up on constraints if we change different number data types
2619 if (isset($column_data['constraint']))
2621 $constraint_sql = "SELECT consrc as constraint_data
2622 FROM pg_constraint, pg_class bc
2623 WHERE conrelid = bc.oid
2624 AND bc.relname = '{$table_name}'
2625 AND NOT EXISTS (
2626 SELECT *
2627 FROM pg_constraint as c, pg_inherits as i
2628 WHERE i.inhrelid = pg_constraint.conrelid
2629 AND c.conname = pg_constraint.conname
2630 AND c.consrc = pg_constraint.consrc
2631 AND c.conrelid = i.inhparent
2634 $constraint_exists = false;
2636 $result = $db->sql_query($constraint_sql);
2637 while ($row = $db->sql_fetchrow($result))
2639 if (trim($row['constraint_data']) == trim($column_data['constraint']))
2641 $constraint_exists = true;
2642 break;
2645 $db->sql_freeresult($result);
2647 if (!$constraint_exists)
2649 $sql_array[] = 'ADD ' . $column_data['constraint'];
2653 $sql .= implode(', ', $sql_array);
2655 _sql($sql, $errored, $error_ary);
2656 break;
2658 case 'sqlite':
2660 $sql = "SELECT sql
2661 FROM sqlite_master
2662 WHERE type = 'table'
2663 AND name = '{$table_name}'
2664 ORDER BY type DESC, name;";
2665 $result = _sql($sql, $errored, $error_ary);
2667 if (!$result)
2669 break;
2672 $row = $db->sql_fetchrow($result);
2673 $db->sql_freeresult($result);
2675 $db->sql_transaction('begin');
2677 // Create a temp table and populate it, destroy the existing one
2678 $db->sql_query(preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']));
2679 $db->sql_query('INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name);
2680 $db->sql_query('DROP TABLE ' . $table_name);
2682 preg_match('#\((.*)\)#s', $row['sql'], $matches);
2684 $new_table_cols = trim($matches[1]);
2685 $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
2686 $column_list = array();
2688 foreach ($old_table_cols as $key => $declaration)
2690 $entities = preg_split('#\s+#', trim($declaration));
2691 $column_list[] = $entities[0];
2692 if ($entities[0] == $column_name)
2694 $old_table_cols[$key] = $column_name . ' ' . $column_data['column_type_sql'];
2698 $columns = implode(',', $column_list);
2700 // create a new table and fill it up. destroy the temp one
2701 $db->sql_query('CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');');
2702 $db->sql_query('INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;');
2703 $db->sql_query('DROP TABLE ' . $table_name . '_temp');
2705 $db->sql_transaction('commit');
2707 break;
2711 function utf8_new_clean_string($text)
2713 static $homographs = array();
2714 static $utf8_case_fold_nfkc = '';
2715 if (empty($homographs))
2717 global $phpbb_root_path, $phpEx;
2718 if (!function_exists('utf8_case_fold_nfkc') || !file_exists($phpbb_root_path . 'includes/utf/data/confusables.' . $phpEx))
2720 if (!file_exists($phpbb_root_path . 'install/data/confusables.' . $phpEx))
2722 global $lang;
2723 trigger_error(sprintf($lang['UPDATE_REQUIRES_FILE'], $phpbb_root_path . 'install/data/confusables.' . $phpEx), E_USER_ERROR);
2725 $homographs = include($phpbb_root_path . 'install/data/confusables.' . $phpEx);
2726 $utf8_case_fold_nfkc = 'utf8_new_case_fold_nfkc';
2728 else
2730 $homographs = include($phpbb_root_path . 'includes/utf/data/confusables.' . $phpEx);
2731 $utf8_case_fold_nfkc = 'utf8_case_fold_nfkc';
2735 $text = $utf8_case_fold_nfkc($text);
2736 $text = strtr($text, $homographs);
2737 // Other control characters
2738 $text = preg_replace('#(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)#', '', $text);
2740 // we can use trim here as all the other space characters should have been turned
2741 // into normal ASCII spaces by now
2742 return trim($text);