/db_update.php
PHP | 1909 lines | 1263 code | 427 blank | 219 comment | 260 complexity | a004d8302dbf5e509f2ced5b2fd985e8 MD5 | raw file
1<?php 2 3/** 4 * Copyright (C) 2008-2012 FluxBB 5 * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB 6 * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher 7 */ 8 9// The FluxBB version this script updates to 10define('UPDATE_TO', '1.5.6'); 11 12define('UPDATE_TO_DB_REVISION', 21); 13define('UPDATE_TO_SI_REVISION', 2); 14define('UPDATE_TO_PARSER_REVISION', 2); 15 16define('MIN_PHP_VERSION', '4.4.0'); 17define('MIN_MYSQL_VERSION', '4.1.2'); 18define('MIN_PGSQL_VERSION', '7.0.0'); 19define('PUN_SEARCH_MIN_WORD', 3); 20define('PUN_SEARCH_MAX_WORD', 20); 21 22// The MySQL connection character set that was used for FluxBB 1.2 - in 99% of cases this should be detected automatically, 23// but can be overridden using the below constant if required. 24//define('FORUM_DEFAULT_CHARSET', 'latin1'); 25 26 27// The number of items to process per page view (lower this if the update script times out during UTF-8 conversion) 28define('PER_PAGE', 300); 29 30// Don't set to UTF-8 until after we've found out what the default character set is 31define('FORUM_NO_SET_NAMES', 1); 32 33// Make sure we are running at least MIN_PHP_VERSION 34if (!function_exists('version_compare') || version_compare(PHP_VERSION, MIN_PHP_VERSION, '<')) 35 exit('You are running PHP version '.PHP_VERSION.'. FluxBB '.UPDATE_TO.' requires at least PHP '.MIN_PHP_VERSION.' to run properly. You must upgrade your PHP installation before you can continue.'); 36 37define('PUN_ROOT', dirname(__FILE__).'/'); 38 39// Attempt to load the configuration file config.php 40if (file_exists(PUN_ROOT.'config.php')) 41 include PUN_ROOT.'config.php'; 42 43// If we have the 1.3-legacy constant defined, define the proper 1.4 constant so we don't get an incorrect "need to install" message 44if (defined('FORUM')) 45 define('PUN', FORUM); 46 47// If PUN isn't defined, config.php is missing or corrupt 48if (!defined('PUN')) 49{ 50 header('Location: install.php'); 51 exit; 52} 53 54// Enable debug mode 55if (!defined('PUN_DEBUG')) 56 define('PUN_DEBUG', 1); 57 58// Load the functions script 59require PUN_ROOT.'include/functions.php'; 60 61// Load UTF-8 functions 62require PUN_ROOT.'include/utf8/utf8.php'; 63 64// Strip out "bad" UTF-8 characters 65forum_remove_bad_characters(); 66 67// Reverse the effect of register_globals 68forum_unregister_globals(); 69 70// Turn on full PHP error reporting 71error_reporting(E_ALL); 72 73// Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings) 74setlocale(LC_CTYPE, 'C'); 75 76// Turn off magic_quotes_runtime 77if (get_magic_quotes_runtime()) 78 set_magic_quotes_runtime(0); 79 80// Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled) 81if (get_magic_quotes_gpc()) 82{ 83 function stripslashes_array($array) 84 { 85 return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array); 86 } 87 88 $_GET = stripslashes_array($_GET); 89 $_POST = stripslashes_array($_POST); 90 $_COOKIE = stripslashes_array($_COOKIE); 91 $_REQUEST = stripslashes_array($_REQUEST); 92} 93 94// If a cookie name is not specified in config.php, we use the default (forum_cookie) 95if (empty($cookie_name)) 96 $cookie_name = 'pun_cookie'; 97 98// If the cache directory is not specified, we use the default setting 99if (!defined('FORUM_CACHE_DIR')) 100 define('FORUM_CACHE_DIR', PUN_ROOT.'cache/'); 101 102// Turn off PHP time limit 103@set_time_limit(0); 104 105// Define a few commonly used constants 106define('PUN_UNVERIFIED', 0); 107define('PUN_ADMIN', 1); 108define('PUN_MOD', 2); 109define('PUN_GUEST', 3); 110define('PUN_MEMBER', 4); 111 112// Load DB abstraction layer and try to connect 113require PUN_ROOT.'include/dblayer/common_db.php'; 114 115// Check what the default character set is - since 1.2 didn't specify any we will use whatever the default was (usually latin1) 116$old_connection_charset = defined('FORUM_DEFAULT_CHARSET') ? FORUM_DEFAULT_CHARSET : $db->get_names(); 117 118// Set the connection to UTF-8 now 119$db->set_names('utf8'); 120 121// Get the forum config 122$result = $db->query('SELECT * FROM '.$db->prefix.'config') or error('Unable to fetch config.', __FILE__, __LINE__, $db->error()); 123while ($cur_config_item = $db->fetch_row($result)) 124 $pun_config[$cur_config_item[0]] = $cur_config_item[1]; 125 126// Load language file 127$default_lang = $pun_config['o_default_lang']; 128 129if (!file_exists(PUN_ROOT.'lang/'.$default_lang.'/update.php')) 130 $default_lang = 'English'; 131 132require PUN_ROOT.'lang/'.$default_lang.'/common.php'; 133require PUN_ROOT.'lang/'.$default_lang.'/update.php'; 134 135// Check current version 136$cur_version = $pun_config['o_cur_version']; 137 138if (version_compare($cur_version, '1.2', '<')) 139 error(sprintf($lang_update['Version mismatch error'], $db_name)); 140 141// Do some DB type specific checks 142$mysql = false; 143switch ($db_type) 144{ 145 case 'mysql': 146 case 'mysqli': 147 case 'mysql_innodb': 148 case 'mysqli_innodb': 149 $mysql_info = $db->get_version(); 150 if (version_compare($mysql_info['version'], MIN_MYSQL_VERSION, '<')) 151 error(sprintf($lang_update['You are running error'], 'MySQL', $mysql_info['version'], UPDATE_TO, MIN_MYSQL_VERSION)); 152 153 $mysql = true; 154 break; 155 156 case 'pgsql': 157 $pgsql_info = $db->get_version(); 158 if (version_compare($pgsql_info['version'], MIN_PGSQL_VERSION, '<')) 159 error(sprintf($lang_update['You are running error'], 'PostgreSQL', $pgsql_info['version'], UPDATE_TO, MIN_PGSQL_VERSION)); 160 161 break; 162} 163 164// Check the database, search index and parser revision and the current version 165if (isset($pun_config['o_database_revision']) && $pun_config['o_database_revision'] >= UPDATE_TO_DB_REVISION && 166 isset($pun_config['o_searchindex_revision']) && $pun_config['o_searchindex_revision'] >= UPDATE_TO_SI_REVISION && 167 isset($pun_config['o_parser_revision']) && $pun_config['o_parser_revision'] >= UPDATE_TO_PARSER_REVISION && 168 version_compare($pun_config['o_cur_version'], UPDATE_TO, '>=')) 169 error($lang_update['No update error']); 170 171$default_style = $pun_config['o_default_style']; 172if (!file_exists(PUN_ROOT.'style/'.$default_style.'.css')) 173 $default_style = 'Air'; 174 175// Start a session, used to queue up errors if duplicate users occur when converting from FluxBB v1.2. 176session_start(); 177 178// 179// Determines whether $str is UTF-8 encoded or not 180// 181function seems_utf8($str) 182{ 183 $str_len = strlen($str); 184 for ($i = 0; $i < $str_len; ++$i) 185 { 186 if (ord($str[$i]) < 0x80) continue; # 0bbbbbbb 187 else if ((ord($str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb 188 else if ((ord($str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb 189 else if ((ord($str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb 190 else if ((ord($str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb 191 else if ((ord($str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b 192 else return false; # Does not match any model 193 194 for ($j = 0; $j < $n; ++$j) # n bytes matching 10bbbbbb follow ? 195 { 196 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) 197 return false; 198 } 199 } 200 201 return true; 202} 203 204 205// 206// Translates the number from a HTML numeric entity into an UTF-8 character 207// 208function dcr2utf8($src) 209{ 210 $dest = ''; 211 if ($src < 0) 212 return false; 213 else if ($src <= 0x007f) 214 $dest .= chr($src); 215 else if ($src <= 0x07ff) 216 { 217 $dest .= chr(0xc0 | ($src >> 6)); 218 $dest .= chr(0x80 | ($src & 0x003f)); 219 } 220 else if ($src == 0xFEFF) 221 { 222 // nop -- zap the BOM 223 } 224 else if ($src >= 0xD800 && $src <= 0xDFFF) 225 { 226 // found a surrogate 227 return false; 228 } 229 else if ($src <= 0xffff) 230 { 231 $dest .= chr(0xe0 | ($src >> 12)); 232 $dest .= chr(0x80 | (($src >> 6) & 0x003f)); 233 $dest .= chr(0x80 | ($src & 0x003f)); 234 } 235 else if ($src <= 0x10ffff) 236 { 237 $dest .= chr(0xf0 | ($src >> 18)); 238 $dest .= chr(0x80 | (($src >> 12) & 0x3f)); 239 $dest .= chr(0x80 | (($src >> 6) & 0x3f)); 240 $dest .= chr(0x80 | ($src & 0x3f)); 241 } 242 else 243 { 244 // out of range 245 return false; 246 } 247 248 return $dest; 249} 250 251 252// 253// Attempts to convert $str from $old_charset to UTF-8. Also converts HTML entities (including numeric entities) to UTF-8 characters 254// 255function convert_to_utf8(&$str, $old_charset) 256{ 257 if (is_null($str) || $str == '') 258 return false; 259 260 $save = $str; 261 262 // Replace literal entities (for non-UTF-8 compliant html_entity_encode) 263 if (version_compare(PHP_VERSION, '5.0.0', '<') && $old_charset == 'ISO-8859-1' || $old_charset == 'ISO-8859-15') 264 $str = html_entity_decode($str, ENT_QUOTES, $old_charset); 265 266 if ($old_charset != 'UTF-8' && !seems_utf8($str)) 267 { 268 if (function_exists('iconv')) 269 $str = iconv(!empty($old_charset) ? $old_charset : 'ISO-8859-1', 'UTF-8', $str); 270 else if (function_exists('mb_convert_encoding')) 271 $str = mb_convert_encoding($str, 'UTF-8', !empty($old_charset) ? $old_charset : 'ISO-8859-1'); 272 else if ($old_charset == 'ISO-8859-1') 273 $str = utf8_encode($str); 274 } 275 276 // Replace literal entities (for UTF-8 compliant html_entity_encode) 277 if (version_compare(PHP_VERSION, '5.0.0', '>=')) 278 $str = html_entity_decode($str, ENT_QUOTES, 'UTF-8'); 279 280 // Replace numeric entities 281 $str = preg_replace_callback('%&#([0-9]+);%', 'utf8_callback_1', $str); 282 $str = preg_replace_callback('%&#x([a-f0-9]+);%i', 'utf8_callback_2', $str); 283 284 // Remove "bad" characters 285 $str = remove_bad_characters($str); 286 287 return ($save != $str); 288} 289 290 291function utf8_callback_1($matches) 292{ 293 return dcr2utf8($matches[1]); 294} 295 296 297function utf8_callback_2($matches) 298{ 299 return dcr2utf8(hexdec($matches[1])); 300} 301 302 303// 304// Alter a table to be utf8. MySQL only 305// Function based on update_convert_table_utf8() from the Drupal project (http://drupal.org/) 306// 307function alter_table_utf8($table) 308{ 309 global $mysql, $db; 310 static $types; 311 312 if (!$mysql) 313 return; 314 315 if (!isset($types)) 316 { 317 $types = array( 318 'char' => 'binary', 319 'varchar' => 'varbinary', 320 'tinytext' => 'tinyblob', 321 'mediumtext' => 'mediumblob', 322 'text' => 'blob', 323 'longtext' => 'longblob' 324 ); 325 } 326 327 // Set table default charset to utf8 328 $db->query('ALTER TABLE '.$table.' CHARACTER SET utf8') or error('Unable to set table character set', __FILE__, __LINE__, $db->error()); 329 330 // Find out which columns need converting and build SQL statements 331 $result = $db->query('SHOW FULL COLUMNS FROM '.$table) or error('Unable to fetch column information', __FILE__, __LINE__, $db->error()); 332 while ($cur_column = $db->fetch_assoc($result)) 333 { 334 if (is_null($cur_column['Collation'])) 335 continue; 336 337 list($type) = explode('(', $cur_column['Type']); 338 if (isset($types[$type]) && strpos($cur_column['Collation'], 'utf8') === false) 339 { 340 $allow_null = ($cur_column['Null'] == 'YES'); 341 $collate = (substr($cur_column['Collation'], -3) == 'bin') ? 'utf8_bin' : 'utf8_general_ci'; 342 343 $db->alter_field($table, $cur_column['Field'], preg_replace('%'.$type.'%i', $types[$type], $cur_column['Type']), $allow_null, $cur_column['Default'], null, true) or error('Unable to alter field to binary', __FILE__, __LINE__, $db->error()); 344 $db->alter_field($table, $cur_column['Field'], $cur_column['Type'].' CHARACTER SET utf8 COLLATE '.$collate, $allow_null, $cur_column['Default'], null, true) or error('Unable to alter field to utf8', __FILE__, __LINE__, $db->error()); 345 } 346 } 347} 348 349// 350// Safely converts text type columns into utf8 351// If finished returns true, otherwise returns $end_at 352// 353function convert_table_utf8($table, $callback, $old_charset, $key = null, $start_at = null, $error_callback = null) 354{ 355 global $mysql, $db, $old_connection_charset; 356 357 $finished = true; 358 $end_at = 0; 359 if ($mysql) 360 { 361 // Only set up the tables if we are doing this in 1 go, or it's the first go 362 if (is_null($start_at) || $start_at == 0) 363 { 364 // Drop any temp table that exists, in-case it's left over from a failed update 365 $db->drop_table($table.'_utf8', true) or error('Unable to drop left over temp table', __FILE__, __LINE__, $db->error()); 366 367 // Copy the table 368 $db->query('CREATE TABLE '.$table.'_utf8 LIKE '.$table) or error('Unable to create new table', __FILE__, __LINE__, $db->error()); 369 370 // Set table default charset to utf8 371 alter_table_utf8($table.'_utf8'); 372 } 373 374 // Change to the old character set so MySQL doesn't attempt to perform conversion on the data from the old table 375 $db->set_names($old_connection_charset); 376 377 // Move & Convert everything 378 $result = $db->query('SELECT * FROM '.$table.(is_null($start_at) ? '' : ' WHERE '.$key.'>'.$start_at).' ORDER BY '.$key.' ASC'.(is_null($start_at) ? '' : ' LIMIT '.PER_PAGE), false) or error('Unable to select from old table', __FILE__, __LINE__, $db->error()); 379 380 // Change back to utf8 mode so we can insert it into the new table 381 $db->set_names('utf8'); 382 383 while ($cur_item = $db->fetch_assoc($result)) 384 { 385 $cur_item = call_user_func($callback, $cur_item, $old_charset); 386 387 $temp = array(); 388 foreach ($cur_item as $idx => $value) 389 $temp[$idx] = is_null($value) ? 'NULL' : '\''.$db->escape($value).'\''; 390 391 $db->query('INSERT INTO '.$table.'_utf8('.implode(',', array_keys($temp)).') VALUES ('.implode(',', array_values($temp)).')') or (is_null($error_callback) ? error('Unable to insert data to new table', __FILE__, __LINE__, $db->error()) : call_user_func($error_callback, $cur_item)); 392 393 $end_at = $cur_item[$key]; 394 } 395 396 // If we aren't doing this all in 1 go and $end_at has a value (i.e. we have processed at least 1 row), figure out if we have more to do or not 397 if (!is_null($start_at) && $end_at > 0) 398 { 399 $result = $db->query('SELECT 1 FROM '.$table.' WHERE '.$key.'>'.$end_at.' ORDER BY '.$key.' ASC LIMIT 1') or error('Unable to check for next row', __FILE__, __LINE__, $db->error()); 400 $finished = $db->num_rows($result) == 0; 401 } 402 403 // Only swap the tables if we are doing this in 1 go, or it's the last go 404 if ($finished) 405 { 406 // Delete old table 407 $db->drop_table($table, true) or error('Unable to drop old table', __FILE__, __LINE__, $db->error()); 408 409 // Rename table 410 $db->query('ALTER TABLE '.$table.'_utf8 RENAME '.$table) or error('Unable to rename new table', __FILE__, __LINE__, $db->error()); 411 412 return true; 413 } 414 415 return $end_at; 416 } 417 else 418 { 419 // Convert everything 420 $result = $db->query('SELECT * FROM '.$table.(is_null($start_at) ? '' : ' WHERE '.$key.'>'.$start_at).' ORDER BY '.$key.' ASC'.(is_null($start_at ) ? '' : ' LIMIT '.PER_PAGE)) or error('Unable to select from table', __FILE__, __LINE__, $db->error()); 421 while ($cur_item = $db->fetch_assoc($result)) 422 { 423 $cur_item = call_user_func($callback, $cur_item, $old_charset); 424 425 $temp = array(); 426 foreach ($cur_item as $idx => $value) 427 $temp[] = $idx.'='.(is_null($value) ? 'NULL' : '\''.$db->escape($value).'\''); 428 429 if (!empty($temp)) 430 $db->query('UPDATE '.$table.' SET '.implode(', ', $temp).' WHERE '.$key.'=\''.$db->escape($cur_item[$key]).'\'') or error('Unable to update data', __FILE__, __LINE__, $db->error()); 431 432 $end_at = $cur_item[$key]; 433 } 434 435 if (!is_null($start_at) && $end_at > 0) 436 { 437 $result = $db->query('SELECT 1 FROM '.$table.' WHERE '.$key.'>'.$end_at.' ORDER BY '.$key.' ASC LIMIT 1') or error('Unable to check for next row', __FILE__, __LINE__, $db->error()); 438 if ($db->num_rows($result) == 0) 439 return true; 440 441 return $end_at; 442 } 443 444 return true; 445 } 446} 447 448 449header('Content-type: text/html; charset=utf-8'); 450 451// Empty all output buffers and stop buffering 452while (@ob_end_clean()); 453 454 455$stage = isset($_REQUEST['stage']) ? $_REQUEST['stage'] : ''; 456$old_charset = isset($_REQUEST['req_old_charset']) ? str_replace('ISO8859', 'ISO-8859', strtoupper($_REQUEST['req_old_charset'])) : 'ISO-8859-1'; 457$start_at = isset($_REQUEST['start_at']) ? intval($_REQUEST['start_at']) : 0; 458$query_str = ''; 459 460// Show form 461if (empty($stage)) 462{ 463 if (file_exists(FORUM_CACHE_DIR.'db_update.lock')) 464 { 465 // Deal with newlines, tabs and multiple spaces 466 $pattern = array("\t", ' ', ' '); 467 $replace = array('    ', '  ', '  '); 468 $message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']); 469 470?> 471<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>"> 472<head> 473<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 474<title><?php echo $lang_update['Maintenance'] ?></title> 475<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" /> 476</head> 477<body> 478 479<div id="punmaint" class="pun"> 480<div class="top-box"><div><!-- Top Corners --></div></div> 481<div class="punwrap"> 482 483<div id="brdmain"> 484<div class="block"> 485 <h2><?php echo $lang_update['Maintenance'] ?></h2> 486 <div class="box"> 487 <div class="inbox"> 488 <p><?php echo $message ?></p> 489 </div> 490 </div> 491</div> 492</div> 493 494</div> 495<div class="end-box"><div><!-- Bottom Corners --></div></div> 496</div> 497 498</body> 499</html> 500<?php 501 502 } 503 else 504 { 505 506?> 507<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 508 509<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>"> 510<head> 511<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 512<title><?php echo $lang_update['Update'] ?></title> 513<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" /> 514</head> 515<body onload="document.getElementById('install').req_db_pass.focus();document.getElementById('install').start.disabled=false;"> 516 517<div id="pundb_update" class="pun"> 518<div class="top-box"><div><!-- Top Corners --></div></div> 519<div class="punwrap"> 520 521<div id="brdheader" class="block"> 522 <div class="box"> 523 <div id="brdtitle" class="inbox"> 524 <h1><span><?php echo $lang_update['Update'] ?></span></h1> 525 <div id="brddesc"><p><?php echo $lang_update['Update message'] ?></p><p><strong><?php echo $lang_update['Note']; ?></strong> <?php echo $lang_update['Members message']; ?></p></div> 526 </div> 527 </div> 528</div> 529 530<div id="brdmain"> 531<div class="blockform"> 532 <h2><span><?php echo $lang_update['Update'] ?></span></h2> 533 <div class="box"> 534 <form id="install" method="post" action="db_update.php"> 535 <input type="hidden" name="stage" value="start" /> 536 <div class="inform"> 537 <fieldset> 538 <legend><?php echo $lang_update['Administrator only'] ?></legend> 539 <div class="infldset"> 540 <p><?php echo $lang_update['Database password info'] ?></p> 541 <p><strong><?php echo $lang_update['Note']; ?></strong> <?php echo $lang_update['Database password note'] ?></p> 542 <label class="required"><strong><?php echo $lang_update['Database password'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br /><input type="password" id="req_db_pass" name="req_db_pass" /><br /></label> 543 <p><?php echo $lang_update['Maintenance message info'] ?></p> 544 <div class="txtarea"> 545 <label class="required"><strong><?php echo $lang_update['Maintenance message'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br /> 546 <textarea name="req_maintenance_message" rows="4" cols="65"><?php echo pun_htmlspecialchars($pun_config['o_maintenance_message']) ?></textarea><br /></label> 547 </div> 548 </div> 549 </fieldset> 550 </div> 551 <div class="inform"> 552 <div class="forminfo"> 553 <p><?php echo $lang_update['Intro 1'] ?></p> 554 <p><?php echo $lang_update['Intro 2'] ?></p> 555<?php 556 557 if (strpos($cur_version, '1.2') === 0) 558 { 559 if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) 560 { 561 562?> 563 <p><?php echo $lang_update['No charset conversion'] ?></p> 564<?php 565 566 } 567 568?> 569 </div> 570 </div> 571 <div class="inform"> 572 <div class="forminfo"> 573 <p><?php echo $lang_update['Enable conversion'] ?></p> 574 <p><?php echo $lang_update['Current character set'] ?></p> 575 </div> 576 <fieldset> 577 <legend><?php echo $lang_update['Charset conversion'] ?></legend> 578 <div class="infldset"> 579 <div class="rbox"> 580 <label><input type="checkbox" name="convert_charset" value="1" checked="checked" /><?php echo $lang_update['Enable conversion label'] ?><br /></label> 581 </div> 582 <label> 583 <strong><?php echo $lang_update['Current character set label'] ?></strong><br /><?php echo $lang_update['Current character set info'] ?><br /> 584 <input type="text" name="req_old_charset" size="12" maxlength="20" value="<?php echo $old_charset ?>" /><br /> 585 </label> 586 </div> 587 </fieldset> 588<?php 589 590 } 591 else 592 echo "\t\t\t\t".'</div>'."\n"; 593 594?> 595 </div> 596 <p class="buttons"><input type="submit" name="start" value="<?php echo $lang_update['Start update'] ?>" /></p> 597 </form> 598 </div> 599</div> 600</div> 601 602</div> 603<div class="end-box"><div><!-- Bottom Corners --></div></div> 604</div> 605 606</body> 607</html> 608<?php 609 610 } 611 $db->end_transaction(); 612 $db->close(); 613 exit; 614 615} 616 617// Read the lock file 618$lock = file_exists(FORUM_CACHE_DIR.'db_update.lock') ? trim(file_get_contents(FORUM_CACHE_DIR.'db_update.lock')) : false; 619$lock_error = false; 620 621// Generate or fetch the UID - this confirms we have a valid admin 622if (isset($_POST['req_db_pass'])) 623{ 624 $req_db_pass = strtolower(pun_trim($_POST['req_db_pass'])); 625 626 switch ($db_type) 627 { 628 // For SQLite we compare against the database file name, since the password is left blank 629 case 'sqlite': 630 if ($req_db_pass != strtolower($db_name)) 631 error(sprintf($lang_update['Invalid file error'], 'config.php')); 632 633 break; 634 // For everything else, check the password matches 635 default: 636 if ($req_db_pass != strtolower($db_password)) 637 error(sprintf($lang_update['Invalid password error'], 'config.php')); 638 639 break; 640 } 641 642 // Generate a unique id to identify this session, only if this is a valid session 643 $uid = pun_hash($req_db_pass.'|'.uniqid(rand(), true)); 644 if ($lock) // We already have a lock file 645 $lock_error = true; 646 else // Create the lock file 647 { 648 $fh = @fopen(FORUM_CACHE_DIR.'db_update.lock', 'wb'); 649 if (!$fh) 650 error(sprintf($lang_update['Unable to lock error'], 'cache')); 651 652 fwrite($fh, $uid); 653 fclose($fh); 654 655 // Update maintenance message 656 if ($_POST['req_maintenance_message'] != '') 657 $maintenance_message = pun_trim(pun_linebreaks($_POST['req_maintenance_message'])); 658 else 659 { 660 // Load the admin_options.php language file 661 require PUN_ROOT.'lang/'.$default_lang.'/admin_options.php'; 662 663 $maintenance_message = $lang_admin_options['Default maintenance message']; 664 } 665 666 $db->query('UPDATE '.$db->prefix.'config SET conf_value=\''.$db->escape($maintenance_message).'\' WHERE conf_name=\'o_maintenance_message\'') or error('Unable to update board config', __FILE__, __LINE__, $db->error()); 667 668 // Regenerate the config cache 669 if (!defined('FORUM_CACHE_FUNCTIONS_LOADED')) 670 require PUN_ROOT.'include/cache.php'; 671 672 generate_config_cache(); 673 } 674} 675else if (isset($_GET['uid'])) 676{ 677 $uid = pun_trim($_GET['uid']); 678 if (!$lock || $lock != $uid) // The lock doesn't exist or doesn't match the given UID 679 $lock_error = true; 680} 681else 682 error($lang_update['No password error']); 683 684// If there is an error with the lock file 685if ($lock_error) 686 error(sprintf($lang_update['Script runs error'], FORUM_CACHE_DIR.'db_update.lock')); 687 688switch ($stage) 689{ 690 // Start by updating the database structure 691 case 'start': 692 $query_str = '?stage=preparse_posts'; 693 694 // If we don't need to update the database, skip this stage 695 if (isset($pun_config['o_database_revision']) && $pun_config['o_database_revision'] >= UPDATE_TO_DB_REVISION) 696 break; 697 698 // Make all email fields VARCHAR(80) 699 $db->alter_field('bans', 'email', 'VARCHAR(80)', true) or error('Unable to alter email field', __FILE__, __LINE__, $db->error()); 700 $db->alter_field('posts', 'poster_email', 'VARCHAR(80)', true) or error('Unable to alter poster_email field', __FILE__, __LINE__, $db->error()); 701 $db->alter_field('users', 'email', 'VARCHAR(80)', false, '') or error('Unable to alter email field', __FILE__, __LINE__, $db->error()); 702 $db->alter_field('users', 'jabber', 'VARCHAR(80)', true) or error('Unable to alter jabber field', __FILE__, __LINE__, $db->error()); 703 $db->alter_field('users', 'msn', 'VARCHAR(80)', true) or error('Unable to alter msn field', __FILE__, __LINE__, $db->error()); 704 $db->alter_field('users', 'activate_string', 'VARCHAR(80)', true) or error('Unable to alter activate_string field', __FILE__, __LINE__, $db->error()); 705 706 // Make all IP fields VARCHAR(39) to support IPv6 707 $db->alter_field('posts', 'poster_ip', 'VARCHAR(39)', true) or error('Unable to alter poster_ip field', __FILE__, __LINE__, $db->error()); 708 $db->alter_field('users', 'registration_ip', 'VARCHAR(39)', false, '0.0.0.0') or error('Unable to alter registration_ip field', __FILE__, __LINE__, $db->error()); 709 710 // Make the message field MEDIUMTEXT to allow proper conversion of 65535 character posts to UTF-8 711 $db->alter_field('posts', 'message', 'MEDIUMTEXT', true) or error('Unable to alter message field', __FILE__, __LINE__, $db->error()); 712 713 // Add the DST option to the users table 714 $db->add_field('users', 'dst', 'TINYINT(1)', false, 0, 'timezone') or error('Unable to add dst field', __FILE__, __LINE__, $db->error()); 715 716 // Add the last_post column to the online table 717 $db->add_field('online', 'last_post', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_post field', __FILE__, __LINE__, $db->error()); 718 719 // Add the last_search column to the online table 720 $db->add_field('online', 'last_search', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_search field', __FILE__, __LINE__, $db->error()); 721 722 // Add the last_search column to the users table 723 $db->add_field('users', 'last_search', 'INT(10) UNSIGNED', true, null, 'last_post') or error('Unable to add last_search field', __FILE__, __LINE__, $db->error()); 724 725 // Drop use_avatar column from users table 726 $db->drop_field('users', 'use_avatar') or error('Unable to drop use_avatar field', __FILE__, __LINE__, $db->error()); 727 728 // Drop save_pass column from users table 729 $db->drop_field('users', 'save_pass') or error('Unable to drop save_pass field', __FILE__, __LINE__, $db->error()); 730 731 // Drop g_edit_subjects_interval column from groups table 732 $db->drop_field('groups', 'g_edit_subjects_interval'); 733 734 // Add database revision number 735 if (!array_key_exists('o_database_revision', $pun_config)) 736 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_database_revision\', \'0\')') or error('Unable to insert config value \'o_database_revision\'', __FILE__, __LINE__, $db->error()); 737 738 // Add search index revision number 739 if (!array_key_exists('o_searchindex_revision', $pun_config)) 740 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_searchindex_revision\', \'0\')') or error('Unable to insert config value \'o_searchindex_revision\'', __FILE__, __LINE__, $db->error()); 741 742 // Add parser revision number 743 if (!array_key_exists('o_parser_revision', $pun_config)) 744 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_parser_revision\', \'0\')') or error('Unable to insert config value \'o_parser_revision\'', __FILE__, __LINE__, $db->error()); 745 746 // Add default email setting option 747 if (!array_key_exists('o_default_email_setting', $pun_config)) 748 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_default_email_setting\', \'1\')') or error('Unable to insert config value \'o_default_email_setting\'', __FILE__, __LINE__, $db->error()); 749 750 // Make sure we have o_additional_navlinks (was added in 1.2.1) 751 if (!array_key_exists('o_additional_navlinks', $pun_config)) 752 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_additional_navlinks\', \'\')') or error('Unable to insert config value \'o_additional_navlinks\'', __FILE__, __LINE__, $db->error()); 753 754 // Insert new config option o_topic_views 755 if (!array_key_exists('o_topic_views', $pun_config)) 756 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_topic_views\', \'1\')') or error('Unable to insert config value \'o_topic_views\'', __FILE__, __LINE__, $db->error()); 757 758 // Insert new config option o_signatures 759 if (!array_key_exists('o_signatures', $pun_config)) 760 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_signatures\', \'1\')') or error('Unable to insert config value \'o_signatures\'', __FILE__, __LINE__, $db->error()); 761 762 // Insert new config option o_smtp_ssl 763 if (!array_key_exists('o_smtp_ssl', $pun_config)) 764 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_smtp_ssl\', \'0\')') or error('Unable to insert config value \'o_smtp_ssl\'', __FILE__, __LINE__, $db->error()); 765 766 // Insert new config option o_default_dst 767 if (!array_key_exists('o_default_dst', $pun_config)) 768 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_default_dst\', \'0\')') or error('Unable to insert config value \'o_default_dst\'', __FILE__, __LINE__, $db->error()); 769 770 // Insert new config option o_quote_depth 771 if (!array_key_exists('o_quote_depth', $pun_config)) 772 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_quote_depth\', \'3\')') or error('Unable to insert config value \'o_quote_depth\'', __FILE__, __LINE__, $db->error()); 773 774 // Insert new config option o_feed_type 775 if (!array_key_exists('o_feed_type', $pun_config)) 776 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_feed_type\', \'2\')') or error('Unable to insert config value \'o_feed_type\'', __FILE__, __LINE__, $db->error()); 777 778 // Insert new config option o_feed_ttl 779 if (!array_key_exists('o_feed_ttl', $pun_config)) 780 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_feed_ttl\', \'0\')') or error('Unable to insert config value \'o_feed_ttl\'', __FILE__, __LINE__, $db->error()); 781 782 // Insert config option o_base_url which was removed in 1.3 783 if (!array_key_exists('o_base_url', $pun_config)) 784 { 785 // If it isn't in $pun_config['o_base_url'] it should be in $base_url, but just in-case it isn't we can make a guess at it 786 if (!isset($base_url)) 787 { 788 // Make an educated guess regarding base_url 789 $base_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; // protocol 790 $base_url .= preg_replace('%:(80|443)$%', '', $_SERVER['HTTP_HOST']); // host[:port] 791 $base_url .= str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])); // path 792 } 793 794 if (substr($base_url, -1) == '/') 795 $base_url = substr($base_url, 0, -1); 796 797 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_base_url\', \''.$db->escape($base_url).'\')') or error('Unable to insert config value \'o_base_url\'', __FILE__, __LINE__, $db->error()); 798 } 799 800 if (strpos($cur_version, '1.2') === 0) 801 { 802 // Groups are almost the same as 1.2: 803 // unverified: 32000 -> 0 804 805 $db->query('UPDATE '.$db->prefix.'users SET group_id = 0 WHERE group_id = 32000') or error('Unable to update unverified users', __FILE__, __LINE__, $db->error()); 806 } 807 else if (strpos($cur_version, '1.3') === 0) 808 { 809 // Groups have changed quite a lot from 1.3: 810 // unverified: 0 -> 0 811 // admin: 1 -> 1 812 // mod: ? -> 2 813 // guest: 2 -> 3 814 // member: ? -> 4 815 816 $result = $db->query('SELECT MAX(g_id) + 1 FROM '.$db->prefix.'groups') or error('Unable to select temp group ID', __FILE__, __LINE__, $db->error()); 817 $temp_id = $db->result($result); 818 819 $result = $db->query('SELECT g_id FROM '.$db->prefix.'groups WHERE g_moderator = 1 AND g_id > 1 LIMIT 1') or error('Unable to select moderator group', __FILE__, __LINE__, $db->error()); 820 if ($db->num_rows($result)) 821 $mod_gid = $db->result($result); 822 else 823 { 824 $db->query('INSERT INTO '.$db->prefix.'groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood, g_report_flood) VALUES('."'Moderators', 'Moderator', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error()); 825 $mod_gid = $db->insert_id(); 826 } 827 828 $member_gid = $pun_config['o_default_user_group']; 829 830 // move the mod group to a temp place 831 $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$temp_id.' WHERE g_id = '.$mod_gid) or error('Unable to update group ID', __FILE__, __LINE__, $db->error()); 832 $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$temp_id.' WHERE group_id = '.$mod_gid) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error()); 833 $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$temp_id.' WHERE group_id = '.$mod_gid) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error()); 834 if ($member_gid == $mod_gid) $member_gid = $temp_id; 835 836 // move whoever is in 3 to a spare slot 837 $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$mod_gid.' WHERE g_id = 3') or error('Unable to update group ID', __FILE__, __LINE__, $db->error()); 838 $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$mod_gid.' WHERE group_id = 3') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error()); 839 $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$mod_gid.' WHERE group_id = 3') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error()); 840 if ($member_gid == 3) $member_gid = $mod_gid; 841 842 // move guest to 3 843 $db->query('UPDATE '.$db->prefix.'groups SET g_id = 3 WHERE g_id = 2') or error('Unable to update group ID', __FILE__, __LINE__, $db->error()); 844 $db->query('UPDATE '.$db->prefix.'users SET group_id = 3 WHERE group_id = 2') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error()); 845 $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 3 WHERE group_id = 2') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error()); 846 if ($member_gid == 2) $member_gid = 3; 847 848 // move mod group in temp place to 2 849 $db->query('UPDATE '.$db->prefix.'groups SET g_id = 2 WHERE g_id = '.$temp_id) or error('Unable to update group ID', __FILE__, __LINE__, $db->error()); 850 $db->query('UPDATE '.$db->prefix.'users SET group_id = 2 WHERE group_id = '.$temp_id) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error()); 851 $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 2 WHERE group_id = '.$temp_id) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error()); 852 if ($member_gid == $temp_id) $member_gid = 2; 853 854 // Only move stuff around if it isn't already in the right place 855 if ($member_gid != $mod_gid || $member_gid != 4) 856 { 857 // move members to temp place 858 $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$temp_id.' WHERE g_id = '.$member_gid) or error('Unable to update group ID', __FILE__, __LINE__, $db->error()); 859 $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$temp_id.' WHERE group_id = '.$member_gid) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error()); 860 $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$temp_id.' WHERE group_id = '.$member_gid) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error()); 861 862 // move whoever is in 4 to members place 863 $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$member_gid.' WHERE g_id = 4') or error('Unable to update group ID', __FILE__, __LINE__, $db->error()); 864 $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$member_gid.' WHERE group_id = 4') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error()); 865 $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$member_gid.' WHERE group_id = 4') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error()); 866 867 // move members in temp place to 4 868 $db->query('UPDATE '.$db->prefix.'groups SET g_id = 4 WHERE g_id = '.$temp_id) or error('Unable to update group ID', __FILE__, __LINE__, $db->error()); 869 $db->query('UPDATE '.$db->prefix.'users SET group_id = 4 WHERE group_id = '.$temp_id) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error()); 870 $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 4 WHERE group_id = '.$temp_id) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error()); 871 } 872 873 $db->query('UPDATE '.$db->prefix.'config SET conf_value=\''.$member_gid.'\' WHERE conf_name=\'o_default_user_group\'') or error('Unable to update default user group ID', __FILE__, __LINE__, $db->error()); 874 } 875 876 // Server time zone is now simply the default time zone 877 if (!array_key_exists('o_default_timezone', $pun_config)) 878 $db->query('UPDATE '.$db->prefix.'config SET conf_name = \'o_default_timezone\' WHERE conf_name = \'o_server_timezone\'') or error('Unable to update time zone config', __FILE__, __LINE__, $db->error()); 879 880 // Increase visit timeout to 30 minutes (only if it hasn't been changed from the default) 881 if (!array_key_exists('o_database_revision', $pun_config) && $pun_config['o_timeout_visit'] == '600') 882 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \'1800\' WHERE conf_name = \'o_timeout_visit\'') or error('Unable to update visit timeout config', __FILE__, __LINE__, $db->error()); 883 884 // Remove obsolete g_post_polls permission from groups table 885 $db->drop_field('groups', 'g_post_polls'); 886 887 // Make room for multiple moderator groups 888 if (!$db->field_exists('groups', 'g_moderator')) 889 { 890 // Add g_moderator column to groups table 891 $db->add_field('groups', 'g_moderator', 'TINYINT(1)', false, 0, 'g_user_title') or error('Unable to add g_moderator field', __FILE__, __LINE__, $db->error()); 892 893 // Give the moderator group moderator privileges 894 $db->query('UPDATE '.$db->prefix.'groups SET g_moderator = 1 WHERE g_id = 2') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 895 } 896 897 // Replace obsolete p_mod_edit_users config setting with new per-group permission 898 if (array_key_exists('p_mod_edit_users', $pun_config)) 899 { 900 $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_edit_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 901 902 $db->add_field('groups', 'g_mod_edit_users', 'TINYINT(1)', false, 0, 'g_moderator') or error('Unable to add g_mod_edit_users field', __FILE__, __LINE__, $db->error()); 903 904 $db->query('UPDATE '.$db->prefix.'groups SET g_mod_edit_users = '.$pun_config['p_mod_edit_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 905 } 906 907 // Replace obsolete p_mod_rename_users config setting with new per-group permission 908 if (array_key_exists('p_mod_rename_users', $pun_config)) 909 { 910 $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_rename_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 911 912 $db->add_field('groups', 'g_mod_rename_users', 'TINYINT(1)', false, 0, 'g_mod_edit_users') or error('Unable to add g_mod_rename_users field', __FILE__, __LINE__, $db->error()); 913 914 $db->query('UPDATE '.$db->prefix.'groups SET g_mod_rename_users = '.$pun_config['p_mod_rename_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 915 } 916 917 // Replace obsolete p_mod_change_passwords config setting with new per-group permission 918 if (array_key_exists('p_mod_change_passwords', $pun_config)) 919 { 920 $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_change_passwords\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 921 922 $db->add_field('groups', 'g_mod_change_passwords', 'TINYINT(1)', false, 0, 'g_mod_rename_users') or error('Unable to add g_mod_change_passwords field', __FILE__, __LINE__, $db->error()); 923 924 $db->query('UPDATE '.$db->prefix.'groups SET g_mod_change_passwords = '.$pun_config['p_mod_change_passwords'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 925 } 926 927 // Replace obsolete p_mod_ban_users config setting with new per-group permission 928 if (array_key_exists('p_mod_ban_users', $pun_config)) 929 { 930 $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_ban_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 931 932 $db->add_field('groups', 'g_mod_ban_users', 'TINYINT(1)', false, 0, 'g_mod_change_passwords') or error('Unable to add g_mod_ban_users field', __FILE__, __LINE__, $db->error()); 933 934 $db->query('UPDATE '.$db->prefix.'groups SET g_mod_ban_users = '.$pun_config['p_mod_ban_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error()); 935 } 936 937 // We need to add a unique index to avoid users having multiple rows in the online table 938 if (!$db->index_exists('online', 'user_id_ident_idx')) 939 { 940 $db->truncate_table('online') or error('Unable to clear online table', __FILE__, __LINE__, $db->error()); 941 942 if ($mysql) 943 $db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident(25)'), true) or error('Unable to add user_id_ident_idx index', __FILE__, __LINE__, $db->error()); 944 else 945 $db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident'), true) or error('Unable to add user_id_ident_idx index', __FILE__, __LINE__, $db->error()); 946 } 947 948 // Remove the redundant user_id_idx on the online table 949 $db->drop_index('online', 'user_id_idx') or error('Unable to drop user_id_idx index', __FILE__, __LINE__, $db->error()); 950 951 // Add an index to ident on the online table 952 if ($mysql) 953 $db->add_index('online', 'ident_idx', array('ident(25)')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error()); 954 else 955 $db->add_index('online', 'ident_idx', array('ident')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error()); 956 957 // Add an index to logged in the online table 958 $db->add_index('online', 'logged_idx', array('logged')) or error('Unable to add logged_idx index', __FILE__, __LINE__, $db->error()); 959 960 // Add an index to last_post in the topics table 961 $db->add_index('topics', 'last_post_idx', array('last_post')) or error('Unable to add last_post_idx index', __FILE__, __LINE__, $db->error()); 962 963 // Add an index to username on the bans table 964 if ($mysql) 965 $db->add_index('bans', 'username_idx', array('username(25)')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error()); 966 else 967 $db->add_index('bans', 'username_idx', array('username')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error()); 968 969 // Change the username_idx on users to a unique index of max size 25 970 $db->drop_index('users', 'username_idx') or error('Unable to drop old username_idx index', __FILE__, __LINE__, $db->error()); 971 $field = $mysql ? 'username(25)' : 'username'; 972 973 // Attempt to add a unique index. If the user doesn't use a transactional database this can fail due to multiple matching usernames in the 974 // users table. This is bad, but just giving up if it happens is even worse! If it fails just add a regular non-unique index. 975 if (!$db->add_index('users', 'username_idx', array($field), true)) 976 $db->add_index('users', 'username_idx', array($field)) or error('Unable to add username_idx field', __FILE__, __LINE__, $db->error()); 977 978 // Add g_view_users column to groups table 979 $db->add_field('groups', 'g_view_users', 'TINYINT(1)', false, 1, 'g_read_board') or error('Unable to add g_view_users field', __FILE__, __LINE__, $db->error()); 980 981 // Add the last_email_sent column to the users table and the g_send_email and 982 // g_email_flood columns to the groups table 983 $db->add_field('users', 'last_email_sent', 'INT(10) UNSIGNED', true, null, 'last_search') or error('Unable to add last_email_sent field', __FILE__, __LINE__, $db->error()); 984 $db->add_field('groups', 'g_send_email', 'TINYINT(1)', false, 1, 'g_search_users') or error('Unable to add g_send_email field', __FILE__, __LINE__, $db->error()); 985 $db->add_field('groups', 'g_email_flood', 'SMALLINT(6)', false, 60, 'g_search_flood') or error('Unable to add g_email_flood field', __FILE__, __LINE__, $db->error()); 986 987 // Add the last_report_sent column to the users table and the g_report_flood 988 // column to the groups table 989 $db->add_field('users', 'last_report_sent', 'INT(10) UNSIGNED', true, null, 'last_email_sent') or error('Unable to add last_report_sent field', __FILE__, __LINE__, $db->error()); 990 $db->add_field('groups', 'g_report_flood', 'SMALLINT(6)', false, 60, 'g_email_flood') or error('Unable to add g_report_flood field', __FILE__, __LINE__, $db->error()); 991 992 // Set non-default g_send_email, g_flood_email and g_flood_report values properly 993 $db->query('UPDATE '.$db->prefix.'groups SET g_send_email = 0 WHERE g_id = 3') or error('Unable to update group email permissions', __FILE__, __LINE__, $db->error()); 994 $db->query('UPDATE '.$db->prefix.'groups SET g_email_flood = 0, g_report_flood = 0 WHERE g_id IN (1,2,3)') or error('Unable to update group email permissions', __FILE__, __LINE__, $db->error()); 995 996 // Add the auto notify/subscription option to the users table 997 $db->add_field('users', 'auto_notify', 'TINYINT(1)', false, 0, 'notify_with_post') or error('Unable to add auto_notify field', __FILE__, __LINE__, $db->error()); 998 999 // Add the first_post_id column to the topics table 1000 if (!$db->field_exists('topics', 'first_post_id')) 1001 { 1002 $db->add_field('topics', 'first_post_id', 'INT(10) UNSIGNED', false, 0, 'posted') or error('Unable to add first_post_id field', __FILE__, __LINE__, $db->error()); 1003 $db->add_index('topics', 'first_post_id_idx', array('first_post_id')) or error('Unable to add first_post_id_idx index', __FILE__, __LINE__, $db->error()); 1004 1005 // Now that we've added the column and indexed it, we need to give it correct data 1006 $result = $db->query('SELECT MIN(id) AS first_post, topic_id FROM '.$db->prefix.'posts GROUP BY topic_id') or error('Unable to fetch first_post_id', __FILE__, __LINE__, $db->error()); 1007 1008 while ($cur_post = $db->fetch_assoc($result)) 1009 $db->query('UPDATE '.$db->prefix.'topics SET first_post_id = '.$cur_post['first_post'].' WHERE id = '.$cur_post['topic_id']) or error('Unable to update first_post_id', __FILE__, __LINE__, $db->error()); 1010 } 1011 1012 // Move any users with the old unverified status to their new group 1013 $db->query('UPDATE '.$db->prefix.'users SET group_id=0 WHERE group_id=32000') or error('Unable to move unverified users', __FILE__, __LINE__, $db->error()); 1014 1015 // Add the ban_creator column to the bans table 1016 $db->add_field('bans', 'ban_creator', 'INT(10) UNSIGNED', false, 0) or error('Unable to add ban_creator field', __FILE__, __LINE__, $db->error()); 1017 1018 // Add the time/date format settings to the user table 1019 $db->add_field('users', 'time_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add time_format field', __FILE__, __LINE__, $db->error()); 1020 $db->add_field('users', 'date_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add date_format field', __FILE__, __LINE__, $db->error()); 1021 1022 // Change the search_data column to mediumtext 1023 $db->alter_field('search_cache', 'search_data', 'MEDIUMTEXT', true) or error('Unable to alter search_data field', __FILE__, __LINE__, $db->error()); 1024 1025 // Add the group promotion columns to the groups table 1026 $db->add_field('groups', 'g_promote_min_posts', 'INT(10) UNSIGNED', false, 0, 'g_user_title') or error('Unable to add g_promote_min_posts field', __FILE__, __LINE__, $db->error()); 1027 $db->add_field('groups', 'g_promote_next_group', 'INT(10) UNSIGNED', false, 0, 'g_promote_min_posts') or error('Unable to add g_promote_next_group field', __FILE__, __LINE__, $db->error()); 1028 1029 // Add a field for the per-group permission to post links 1030 $db->add_field('groups', 'g_post_links', 'TINYINT(1)', false, 1, 'g_delete_topics') or error('Unable to add per-group permission to post links', __FILE__, __LINE__, $db->error()); 1031 1032 // Add a field for the per-group permission to promote users to the next auto-promote group 1033 $db->add_field('groups', 'g_mod_promote_users', 'TINYINT(1)', false, 0, 'g_mod_ban_users') or error('Unable to add per-group permission to promote users', __FILE__, __LINE__, $db->error()); 1034 1035 // In case we had the fulltext search extension installed (1.3-legacy), remove it 1036 $db->drop_index('topics', 'subject_idx') or error('Unable to drop subject_idx index', __FILE__, __LINE__, $db->error()); 1037 $db->drop_index('posts', 'message_idx') or error('Unable to drop message_idx index', __FILE__, __LINE__, $db->error()); 1038 // In case we had the fulltext search mod installed (1.2), remove it 1039 $db->drop_index('topics', 'subject_fulltext_search') or error('Unable to drop subject_fulltext_search index', __FILE__, __LINE__, $db->error()); 1040 $db->drop_index('posts', 'message_fulltext_search') or error('Unable to drop message_fulltext_search index', __FILE__, __LINE__, $db->error()); 1041 1042 // If the search_cache table has been dropped by the fulltext search extension, recreate it 1043 if (!$db->table_exists('search_cache')) 1044 { 1045 $schema = array( 1046 'FIELDS' => array( 1047 'id' => array( 1048 'datatype' => 'INT(10) UNSIGNED', 1049 'allow_null' => false, 1050 'default' => '0' 1051 ), 1052 'ident' => array( 1053 'datatype' => 'VARCHAR(200)', 1054 'allow_null' => false, 1055 'default' => '\'\'' 1056 ), 1057 'search_data' => array( 1058 'datatype' => 'MEDIUMTEXT', 1059 'allow_null' => true 1060 ) 1061 ), 1062 'PRIMARY KEY' => array('id'), 1063 'INDEXES' => array( 1064 'ident_idx' => array('ident') 1065 ) 1066 ); 1067 1068 if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb') 1069 $schema['INDEXES']['ident_idx'] = array('ident(8)'); 1070 1071 $db->create_table('search_cache', $schema); 1072 } 1073 1074 // If the search_matches table has been dropped by the fulltext search extension, recreate it 1075 if (!$db->table_exists('search_matches')) 1076 { 1077 $schema = array( 1078 'FIELDS' => array( 1079 'post_id' => array( 1080 'datatype' => 'INT(10) UNSIGNED', 1081 'allow_null' => false, 1082 'default' => '0' 1083 ), 1084 'word_id' => array( 1085 'datatype' => 'INT(10) UNSIGNED', 1086 'allow_null' => false, 1087 'default' => '0' 1088 ), 1089 'subject_match' => array( 1090 'datatype' => 'TINYINT(1)', 1091 'allow_null' => false, 1092 'default' => '0' 1093 ) 1094 ), 1095 'INDEXES' => array( 1096 'word_id_idx' => array('word_id'), 1097 'post_id_idx' => array('post_id') 1098 ) 1099 ); 1100 1101 $db->create_table('search_matches', $schema); 1102 } 1103 1104 // If the search_words table has been dropped by the fulltext search extension, recreate it 1105 if (!$db->table_exists('search_words')) 1106 { 1107 $schema = array( 1108 'FIELDS' => array( 1109 'id' => array( 1110 'datatype' => 'SERIAL', 1111 'allow_null' => false 1112 ), 1113 'word' => array( 1114 'datatype' => 'VARCHAR(20)', 1115 'allow_null' => false, 1116 'default' => '\'\'', 1117 'collation' => 'bin' 1118 ) 1119 ), 1120 'PRIMARY KEY' => array('word'), 1121 'INDEXES' => array( 1122 'id_idx' => array('id') 1123 ) 1124 ); 1125 1126 if ($db_type == 'sqlite') 1127 { 1128 $schema['PRIMARY KEY'] = array('id'); 1129 $schema['UNIQUE KEYS'] = array('word_idx' => array('word')); 1130 } 1131 1132 $db->create_table('search_words', $schema); 1133 } 1134 1135 // Rename the subscription table 1136 $db->rename_table('subscriptions', 'topic_subscriptions'); 1137 1138 // if we don't have the forum_subscriptions table, create it 1139 if (!$db->table_exists('forum_subscriptions')) 1140 { 1141 $schema = array( 1142 'FIELDS' => array( 1143 'user_id' => array( 1144 'datatype' => 'INT(10) UNSIGNED', 1145 'allow_null' => false, 1146 'default' => '0' 1147 ), 1148 'forum_id' => array( 1149 'datatype' => 'INT(10) UNSIGNED', 1150 'allow_null' => false, 1151 'default' => '0' 1152 ) 1153 ), 1154 'PRIMARY KEY' => array('user_id', 'forum_id') 1155 ); 1156 1157 $db->create_table('forum_subscriptions', $schema) or error('Unable to create forum subscriptions table', __FILE__, __LINE__, $db->error()); 1158 } 1159 1160 // Insert new config option o_forum_subscriptions 1161 if (!array_key_exists('o_forum_subscriptions', $pun_config)) 1162 $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_forum_subscriptions\', \'1\')') or error('Unable to insert config value \'o_forum_subscriptions\'', __FILE__, __LINE__, $db->error()); 1163 1164 // Rename config option o_subscriptions to o_topic_subscriptions 1165 if (!array_key_exists('o_topic_subscriptions', $pun_config)) 1166 $db->query('UPDATE '.$db->prefix.'config SET conf_name=\'o_topic_subscriptions\' WHERE conf_name=\'o_subscriptions\'') or error('Unable to rename config value \'o_subscriptions\'', __FILE__, __LINE__, $db->error()); 1167 1168 // Change the default style if the old doesn't exist anymore 1169 if ($pun_config['o_default_style'] != $default_style) 1170 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.$db->escape($default_style).'\' WHERE conf_name = \'o_default_style\'') or error('Unable to update default style config', __FILE__, __LINE__, $db->error()); 1171 1172 // For MySQL(i) without InnoDB, change the engine of the online table (for performance reasons) 1173 if ($db_type == 'mysql' || $db_type == 'mysqli') 1174 $db->query('ALTER TABLE '.$db->prefix.'online ENGINE = MyISAM') or error('Unable to change engine type of online table to MyISAM', __FILE__, __LINE__, $db->error()); 1175 1176 // Remove config option o_ranks 1177 if (array_key_exists('o_ranks', $pun_config)) 1178 $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name=\'o_ranks\'') or error('Unable to remove config value \'o_ranks\'', __FILE__, __LINE__, $db->error()); 1179 1180 // Remove the ranks table 1181 if ($db->table_exists('ranks')) 1182 $db->drop_table('ranks') or error('Unable to drop ranks table', __FILE__, __LINE__, $db->error()); 1183 1184 // Should we do charset conversion or not? 1185 if (strpos($cur_version, '1.2') === 0 && isset($_POST['convert_charset'])) 1186 $query_str = '?stage=conv_bans&req_old_charset='.$old_charset; 1187 1188 break; 1189 1190 1191 // Convert bans 1192 case 'conv_bans': 1193 $query_str = '?stage=conv_categories&req_old_charset='.$old_charset; 1194 1195 function _conv_bans($cur_item, $old_charset) 1196 { 1197 global $lang_update; 1198 1199 echo sprintf($lang_update['Converting item'], $lang_update['ban'], $cur_item['id']).'<br />'."\n"; 1200 1201 convert_to_utf8($cur_item['username'], $old_charset); 1202 convert_to_utf8($cur_item['message'], $old_charset); 1203 1204 return $cur_item; 1205 } 1206 1207 $end_at = convert_table_utf8($db->prefix.'bans', '_conv_bans', $old_charset, 'id', $start_at); 1208 1209 if ($end_at !== true) 1210 $query_str = '?stage=conv_bans&req_old_charset='.$old_charset.'&start_at='.$end_at; 1211 1212 break; 1213 1214 1215 // Convert categories 1216 case 'conv_categories': 1217 $query_str = '?stage=conv_censors&req_old_charset='.$old_charset; 1218 1219 echo sprintf($lang_update['Converting'], $lang_update['categories']).'<br />'."\n"; 1220 1221 function _conv_categories($cur_item, $old_charset) 1222 { 1223 convert_to_utf8($cur_item['cat_name'], $old_charset); 1224 1225 return $cur_item; 1226 } 1227 1228 convert_table_utf8($db->prefix.'categories', '_conv_categories', $old_charset, 'id'); 1229 1230 break; 1231 1232 1233 // Convert censor words 1234 case 'conv_censors': 1235 $query_str = '?stage=conv_config&req_old_charset='.$old_charset; 1236 1237 echo sprintf($lang_update['Converting'], $lang_update['censor words']).'<br />'."\n"; 1238 1239 function _conv_censoring($cur_item, $old_charset) 1240 { 1241 convert_to_utf8($cur_item['search_for'], $old_charset); 1242 convert_to_utf8($cur_item['replace_with'], $old_charset); 1243 1244 return $cur_item; 1245 } 1246 1247 convert_table_utf8($db->prefix.'censoring', '_conv_censoring', $old_charset, 'id'); 1248 1249 break; 1250 1251 1252 // Convert config 1253 case 'conv_config': 1254 $query_str = '?stage=conv_forums&req_old_charset='.$old_charset; 1255 1256 echo sprintf($lang_update['Converting'], $lang_update['configuration']).'<br />'."\n"; 1257 1258 function _conv_config($cur_item, $old_charset) 1259 { 1260 convert_to_utf8($cur_item['conf_value'], $old_charset); 1261 1262 return $cur_item; 1263 } 1264 1265 convert_table_utf8($db->prefix.'config', '_conv_config', $old_charset, 'conf_name'); 1266 1267 break; 1268 1269 1270 // Convert forums 1271 case 'conv_forums': 1272 $query_str = '?stage=conv_perms&req_old_charset='.$old_charset; 1273 1274 echo sprintf($lang_update['Converting'], $lang_update['forums']).'<br />'."\n"; 1275 1276 function _conv_forums($cur_item, $old_charset) 1277 { 1278 $moderators = ($cur_item['moderators'] != '') ? unserialize($cur_item['moderators']) : array(); 1279 $moderators_utf8 = array(); 1280 foreach ($moderators as $mod_username => $mod_user_id) 1281 { 1282 convert_to_utf8($mod_username, $old_charset); 1283 $moderators_utf8[$mod_username] = $mod_user_id; 1284 } 1285 1286 convert_to_utf8($cur_item['forum_name'], $old_charset); 1287 convert_to_utf8($cur_item['forum_desc'], $old_charset); 1288 convert_to_utf8($cur_item['last_poster'], $old_charset); 1289 1290 if (!empty($moderators_utf8)) 1291 $cur_item['moderators'] = serialize($moderators_utf8); 1292 1293 return $cur_item; 1294 } 1295 1296 convert_table_utf8($db->prefix.'forums', '_conv_forums', $old_charset, 'id'); 1297 1298 break; 1299 1300 1301 // Convert forum permissions 1302 case 'conv_perms': 1303 $query_str = '?stage=conv_groups&req_old_charset='.$old_charset; 1304 1305 alter_table_utf8($db->prefix.'forum_perms'); 1306 1307 break; 1308 1309 1310 // Convert groups 1311 case 'conv_groups': 1312 $query_str = '?stage=conv_online&req_old_charset='.$old_charset; 1313 1314 echo sprintf($lang_update['Converting'], $lang_update['groups']).'<br />'."\n"; 1315 1316 function _conv_groups($cur_item, $old_charset) 1317 { 1318 convert_to_utf8($cur_item['g_title'], $old_charset); 1319 convert_to_utf8($cur_item['g_user_title'], $old_charset); 1320 1321 return $cur_item; 1322 } 1323 1324 convert_table_utf8($db->prefix.'groups', '_conv_groups', $old_charset, 'g_id'); 1325 1326 break; 1327 1328 1329 // Convert online 1330 case 'conv_online': 1331 $query_str = '?stage=conv_posts&req_old_charset='.$old_charset; 1332 1333 // Truncate the table 1334 $db->truncate_table('online') or error('Unable to empty online table', __FILE__, __LINE__, $db->error()); 1335 1336 alter_table_utf8($db->prefix.'online'); 1337 1338 break; 1339 1340 1341 // Convert posts 1342 case 'conv_posts': 1343 $query_str = '?stage=conv_reports&req_old_charset='.$old_charset; 1344 1345 function _conv_posts($cur_item, $old_charset) 1346 { 1347 global $lang_update; 1348 1349 echo sprintf($lang_update['Converting item'], $lang_update['post'], $cur_item['id']).'<br />'."\n"; 1350 1351 convert_to_utf8($cur_item['poster'], $old_charset); 1352 convert_to_utf8($cur_item['message'], $old_charset); 1353 convert_to_utf8($cur_item['edited_by'], $old_charset); 1354 1355 return $cur_item; 1356 } 1357 1358 $end_at = convert_table_utf8($db->prefix.'posts', '_conv_posts', $old_charset, 'id', $start_at); 1359 1360 if ($end_at !== true) 1361 $query_str = '?stage=conv_posts&req_old_charset='.$old_charset.'&start_at='.$end_at; 1362 1363 break; 1364 1365 1366 // Convert reports 1367 case 'conv_reports': 1368 $query_str = '?stage=conv_search_cache&req_old_charset='.$old_charset; 1369 1370 function _conv_reports($cur_item, $old_charset) 1371 { 1372 global $lang_update; 1373 1374 echo sprintf($lang_update['Converting item'], $lang_update['report'], $cur_item['id']).'<br />'."\n"; 1375 1376 convert_to_utf8($cur_item['message'], $old_charset); 1377 1378 return $cur_item; 1379 } 1380 1381 $end_at = convert_table_utf8($db->prefix.'reports', '_conv_reports', $old_charset, 'id', $start_at); 1382 1383 if ($end_at !== true) 1384 $query_str = '?stage=conv_reports&req_old_charset='.$old_charset.'&start_at='.$end_at; 1385 1386 break; 1387 1388 1389 // Convert search cache 1390 case 'conv_search_cache': 1391 $query_str = '?stage=conv_search_matches&req_old_charset='.$old_charset; 1392 1393 // Truncate the table 1394 $db->truncate_table('search_cache') or error('Unable to empty search cache table', __FILE__, __LINE__, $db->error()); 1395 1396 alter_table_utf8($db->prefix.'search_cache'); 1397 1398 break; 1399 1400 1401 // Convert search matches 1402 case 'conv_search_matches': 1403 $query_str = '?stage=conv_search_words&req_old_charset='.$old_charset; 1404 1405 // Truncate the table 1406 $db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error()); 1407 1408 alter_table_utf8($db->prefix.'search_matches'); 1409 1410 break; 1411 1412 1413 // Convert search words 1414 case 'conv_search_words': 1415 $query_str = '?stage=conv_subscriptions&req_old_charset='.$old_charset; 1416 1417 // Truncate the table 1418 $db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error()); 1419 1420 // Reset the sequence for the search words (not needed for SQLite) 1421 switch ($db_type) 1422 { 1423 case 'mysql': 1424 case 'mysqli': 1425 case 'mysql_innodb': 1426 case 'mysqli_innodb': 1427 $db->query('ALTER TABLE '.$db->prefix.'search_words auto_increment=1') or error('Unable to update table auto_increment', __FILE__, __LINE__, $db->error()); 1428 break; 1429 1430 case 'pgsql'; 1431 $db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error()); 1432 break; 1433 } 1434 1435 alter_table_utf8($db->prefix.'search_words'); 1436 1437 break; 1438 1439 1440 // Convert subscriptions 1441 case 'conv_subscriptions': 1442 $query_str = '?stage=conv_topics&req_old_charset='.$old_charset; 1443 1444 // By this stage we should have already renamed the subscription table 1445 alter_table_utf8($db->prefix.'topic_subscriptions'); 1446 alter_table_utf8($db->prefix.'forum_subscriptions'); // This should actually already be utf8, but for consistency... 1447 1448 break; 1449 1450 1451 // Convert topics 1452 case 'conv_topics': 1453 $query_str = '?stage=conv_users&req_old_charset='.$old_charset; 1454 1455 function _conv_topics($cur_item, $old_charset) 1456 { 1457 global $lang_update; 1458 1459 echo sprintf($lang_update['Converting item'], $lang_update['topic'], $cur_item['id']).'<br />'."\n"; 1460 1461 convert_to_utf8($cur_item['poster'], $old_charset); 1462 convert_to_utf8($cur_item['subject'], $old_charset); 1463 convert_to_utf8($cur_item['last_poster'], $old_charset); 1464 1465 return $cur_item; 1466 } 1467 1468 $end_at = convert_table_utf8($db->prefix.'topics', '_conv_topics', $old_charset, 'id', $start_at); 1469 1470 if ($end_at !== true) 1471 $query_str = '?stage=conv_topics&req_old_charset='.$old_charset.'&start_at='.$end_at; 1472 1473 break; 1474 1475 1476 // Convert users 1477 case 'conv_users': 1478 $query_str = '?stage=preparse_posts'; 1479 1480 if ($start_at == 0) 1481 $_SESSION['dupe_users'] = array(); 1482 1483 function _conv_users($cur_item, $old_charset) 1484 { 1485 global $lang_update; 1486 1487 echo sprintf($lang_update['Converting item'], $lang_update['user'], $cur_item['id']).'<br />'."\n"; 1488 1489 convert_to_utf8($cur_item['username'], $old_charset); 1490 convert_to_utf8($cur_item['title'], $old_charset); 1491 convert_to_utf8($cur_item['realname'], $old_charset); 1492 convert_to_utf8($cur_item['location'], $old_charset); 1493 convert_to_utf8($cur_item['signature'], $old_charset); 1494 convert_to_utf8($cur_item['admin_note'], $old_charset); 1495 1496 return $cur_item; 1497 } 1498 1499 function _error_users($cur_user) 1500 { 1501 $_SESSION['dupe_users'][$cur_user['id']] = $cur_user; 1502 } 1503 1504 $end_at = convert_table_utf8($db->prefix.'users', '_conv_users', $old_charset, 'id', $start_at, '_error_users'); 1505 1506 if ($end_at !== true) 1507 $query_str = '?stage=conv_users&req_old_charset='.$old_charset.'&start_at='.$end_at; 1508 else if (!empty($_SESSION['dupe_users'])) 1509 $query_str = '?stage=conv_users_dupe'; 1510 1511 break; 1512 1513 1514 // Handle any duplicate users which occured due to conversion 1515 case 'conv_users_dupe': 1516 $query_str = '?stage=preparse_posts'; 1517 1518 if (!$mysql || empty($_SESSION['dupe_users'])) 1519 break; 1520 1521 if (isset($_POST['form_sent'])) 1522 { 1523 $errors = array(); 1524 1525 require PUN_ROOT.'include/email.php'; 1526 1527 foreach ($_SESSION['dupe_users'] as $id => $cur_user) 1528 { 1529 $errors[$id] = array(); 1530 1531 $username = pun_trim($_POST['dupe_users'][$id]); 1532 1533 if (pun_strlen($username) < 2) 1534 $errors[$id][] = $lang_update['Username too short error']; 1535 else if (pun_strlen($username) > 25) // This usually doesn't happen since the form element only accepts 25 characters 1536 $errors[$id][] = $lang_update['Username too long error']; 1537 else if (!strcasecmp($username, 'Guest')) 1538 $errors[$id][] = $lang_update['Username Guest reserved error']; 1539 else if (preg_match('%[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}%', $username) || preg_match('%((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))%', $username)) 1540 $errors[$id][] = $lang_update['Username IP format error']; 1541 else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false) 1542 $errors[$id][] = $lang_update['Username bad characters error']; 1543 else if (preg_match('%(?:\[/?(?:b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list|\*)\]|\[(?:img|url|quote|list)=)%i', $username)) 1544 $errors[$id][] = $lang_update['Username BBCode error']; 1545 1546 $result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$db->escape($username).'\') OR UPPER(username)=UPPER(\''.$db->escape(ucp_preg_replace('%[^\p{L}\p{N}]%u', '', $username)).'\')) AND id>1') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error()); 1547 1548 if ($db->num_rows($result)) 1549 { 1550 $busy = $db->result($result); 1551 $errors[$id][] = sprintf($lang_update['Username duplicate error'], pun_htmlspecialchars($busy)); 1552 } 1553 1554 if (empty($errors[$id])) 1555 { 1556 $old_username = $cur_user['username']; 1557 $_SESSION['dupe_users'][$id]['username'] = $cur_user['username'] = $username; 1558 1559 $temp = array(); 1560 foreach ($cur_user as $idx => $value) 1561 $temp[$idx] = is_null($value) ? 'NULL' : '\''.$db->escape($value).'\''; 1562 1563 // Insert the renamed user 1564 $db->query('INSERT INTO '.$db->prefix.'users('.implode(',', array_keys($temp)).') VALUES ('.implode(',', array_values($temp)).')') or error('Unable to insert data to new table', __FILE__, __LINE__, $db->error()); 1565 1566 // Renaming a user also affects a bunch of other stuff, lets fix that too... 1567 $db->query('UPDATE '.$db->prefix.'posts SET poster=\''.$db->escape($username).'\' WHERE poster_id='.$id) or error('Unable to update posts', __FILE__, __LINE__, $db->error()); 1568 1569 // TODO: The following must compare using collation utf8_bin otherwise we will accidently update posts/topics/etc belonging to both of the duplicate users, not just the one we renamed! 1570 $db->query('UPDATE '.$db->prefix.'posts SET edited_by=\''.$db->escape($username).'\' WHERE edited_by=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update posts', __FILE__, __LINE__, $db->error()); 1571 $db->query('UPDATE '.$db->prefix.'topics SET poster=\''.$db->escape($username).'\' WHERE poster=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update topics', __FILE__, __LINE__, $db->error()); 1572 $db->query('UPDATE '.$db->prefix.'topics SET last_poster=\''.$db->escape($username).'\' WHERE last_poster=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update topics', __FILE__, __LINE__, $db->error()); 1573 $db->query('UPDATE '.$db->prefix.'forums SET last_poster=\''.$db->escape($username).'\' WHERE last_poster=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update forums', __FILE__, __LINE__, $db->error()); 1574 $db->query('UPDATE '.$db->prefix.'online SET ident=\''.$db->escape($username).'\' WHERE ident=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update online list', __FILE__, __LINE__, $db->error()); 1575 1576 // If the user is a moderator or an administrator we have to update the moderator lists 1577 $result = $db->query('SELECT g_moderator FROM '.$db->prefix.'groups WHERE g_id='.$cur_user['group_id']) or error('Unable to fetch group', __FILE__, __LINE__, $db->error()); 1578 $group_mod = $db->result($result); 1579 1580 if ($cur_user['group_id'] == PUN_ADMIN || $group_mod == '1') 1581 { 1582 $result = $db->query('SELECT id, moderators FROM '.$db->prefix.'forums') or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error()); 1583 1584 while ($cur_forum = $db->fetch_assoc($result)) 1585 { 1586 $cur_moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array(); 1587 1588 if (in_array($id, $cur_moderators)) 1589 { 1590 unset($cur_moderators[$old_username]); 1591 $cur_moderators[$username] = $id; 1592 uksort($cur_moderators, 'utf8_strcasecmp'); 1593 1594 $db->query('UPDATE '.$db->prefix.'forums SET moderators=\''.$db->escape(serialize($cur_moderators)).'\' WHERE id='.$cur_forum['id']) or error('Unable to update forum', __FILE__, __LINE__, $db->error()); 1595 } 1596 } 1597 } 1598 1599 // Email the user alerting them of the change 1600 if (file_exists(PUN_ROOT.'lang/'.$cur_user['language'].'/mail_templates/rename.tpl')) 1601 $mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$cur_user['language'].'/mail_templates/rename.tpl')); 1602 else if (file_exists(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/mail_templates/rename.tpl')) 1603 $mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/mail_templates/rename.tpl')); 1604 else 1605 $mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/English/mail_templates/rename.tpl')); 1606 1607 // The first row contains the subject 1608 $first_crlf = strpos($mail_tpl, "\n"); 1609 $mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8)); 1610 $mail_message = trim(substr($mail_tpl, $first_crlf)); 1611 1612 $mail_subject = str_replace('<board_title>', $pun_config['o_board_title'], $mail_subject); 1613 $mail_message = str_replace('<base_url>', get_base_url().'/', $mail_message); 1614 $mail_message = str_replace('<old_username>', $old_username, $mail_message); 1615 $mail_message = str_replace('<new_username>', $username, $mail_message); 1616 $mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message); 1617 1618 pun_mail($cur_user['email'], $mail_subject, $mail_message); 1619 1620 unset($_SESSION['dupe_users'][$id]); 1621 } 1622 } 1623 } 1624 1625 if (!empty($_SESSION['dupe_users'])) 1626 { 1627 $query_str = ''; 1628 1629?> 1630<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 1631 1632<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>"> 1633<head> 1634<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 1635<title><?php echo $lang_update['Update'] ?></title> 1636<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" /> 1637</head> 1638<body> 1639 1640<div id="pundb_update" class="pun"> 1641<div class="top-box"><div><!-- Top Corners --></div></div> 1642<div class="punwrap"> 1643 1644<div class="blockform"> 1645 <h2><span><?php echo $lang_update['Error converting users'] ?></span></h2> 1646 <div class="box"> 1647 <form method="post" action="db_update.php?stage=conv_users_dupe&uid=<?php echo $uid ?>"> 1648 <input type="hidden" name="form_sent" value="1" /> 1649 <div class="inform"> 1650 <div class="forminfo"> 1651 <p style="font-size: 1.1em"><?php echo $lang_update['Error info 1'] ?></p> 1652 <p style="font-size: 1.1em"><?php echo $lang_update['Error info 2'] ?></p> 1653 </div> 1654 </div> 1655<?php 1656 1657 foreach ($_SESSION['dupe_users'] as $id => $cur_user) 1658 { 1659 1660?> 1661 <div class="inform"> 1662 <fieldset> 1663 <legend><?php echo pun_htmlspecialchars($cur_user['username']); ?></legend> 1664 <div class="infldset"> 1665 <label class="required"><strong><?php echo $lang_update['New username'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br /><input type="text" name="<?php echo 'dupe_users['.$id.']'; ?>" value="<?php if (isset($_POST['dupe_users'][$id])) echo pun_htmlspecialchars($_POST['dupe_users'][$id]); ?>" size="25" maxlength="25" /><br /></label> 1666 </div> 1667 </fieldset> 1668<?php if (!empty($errors[$id])): ?> <div class="forminfo error-info"> 1669 <h3><?php echo $lang_update['Correct errors'] ?></h3> 1670 <ul class="error-list"> 1671<?php 1672 1673foreach ($errors[$id] as $cur_error) 1674 echo "\t\t\t\t\t\t".'<li><strong>'.$cur_error.'</strong></li>'."\n"; 1675?> 1676 </ul> 1677 </div> 1678<?php endif; ?> </div> 1679<?php 1680 1681 } 1682 1683?> 1684 <p class="buttons"><input type="submit" name="rename" value="<?php echo $lang_update['Rename users'] ?>" /></p> 1685 </form> 1686 </div> 1687</div> 1688 1689</div> 1690<div class="end-box"><div><!-- Bottom Corners --></div></div> 1691</div> 1692 1693</body> 1694</html> 1695<?php 1696 1697 } 1698 1699 break; 1700 1701 1702 // Preparse posts 1703 case 'preparse_posts': 1704 $query_str = '?stage=preparse_sigs'; 1705 1706 // If we don't need to parse the posts, skip this stage 1707 if (isset($pun_config['o_parser_revision']) && $pun_config['o_parser_revision'] >= UPDATE_TO_PARSER_REVISION) 1708 break; 1709 1710 require PUN_ROOT.'include/parser.php'; 1711 1712 // Fetch posts to process this cycle 1713 $result = $db->query('SELECT id, message FROM '.$db->prefix.'posts WHERE id > '.$start_at.' ORDER BY id ASC LIMIT '.PER_PAGE) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error()); 1714 1715 $temp = array(); 1716 $end_at = 0; 1717 while ($cur_item = $db->fetch_assoc($result)) 1718 { 1719 echo sprintf($lang_update['Preparsing item'], $lang_update['post'], $cur_item['id']).'<br />'."\n"; 1720 $db->query('UPDATE '.$db->prefix.'posts SET message = \''.$db->escape(preparse_bbcode($cur_item['message'], $temp)).'\' WHERE id = '.$cur_item['id']) or error('Unable to update post', __FILE__, __LINE__, $db->error()); 1721 1722 $end_at = $cur_item['id']; 1723 } 1724 1725 // Check if there is more work to do 1726 if ($end_at > 0) 1727 { 1728 $result = $db->query('SELECT 1 FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error()); 1729 1730 if ($db->num_rows($result) > 0) 1731 $query_str = '?stage=preparse_posts&start_at='.$end_at; 1732 } 1733 1734 break; 1735 1736 1737 // Preparse signatures 1738 case 'preparse_sigs': 1739 $query_str = '?stage=rebuild_idx'; 1740 1741 // If we don't need to parse the sigs, skip this stage 1742 if (isset($pun_config['o_parser_revision']) && $pun_config['o_parser_revision'] >= UPDATE_TO_PARSER_REVISION) 1743 break; 1744 1745 require PUN_ROOT.'include/parser.php'; 1746 1747 // Fetch users to process this cycle 1748 $result = $db->query('SELECT id, signature FROM '.$db->prefix.'users WHERE id > '.$start_at.' ORDER BY id ASC LIMIT '.PER_PAGE) or error('Unable to fetch users', __FILE__, __LINE__, $db->error()); 1749 1750 $temp = array(); 1751 $end_at = 0; 1752 while ($cur_item = $db->fetch_assoc($result)) 1753 { 1754 echo sprintf($lang_update['Preparsing item'], $lang_update['signature'], $cur_item['id']).'<br />'."\n"; 1755 $db->query('UPDATE '.$db->prefix.'users SET signature = \''.$db->escape(preparse_bbcode($cur_item['signature'], $temp, true)).'\' WHERE id = '.$cur_item['id']) or error('Unable to update user', __FILE__, __LINE__, $db->error()); 1756 1757 $end_at = $cur_item['id']; 1758 } 1759 1760 // Check if there is more work to do 1761 if ($end_at > 0) 1762 { 1763 $result = $db->query('SELECT 1 FROM '.$db->prefix.'users WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error()); 1764 if ($db->num_rows($result) > 0) 1765 $query_str = '?stage=preparse_sigs&start_at='.$end_at; 1766 } 1767 1768 break; 1769 1770 1771 // Rebuild the search index 1772 case 'rebuild_idx': 1773 $query_str = '?stage=finish'; 1774 1775 // If we don't need to update the search index, skip this stage 1776 if (isset($pun_config['o_searchindex_revision']) && $pun_config['o_searchindex_revision'] >= UPDATE_TO_SI_REVISION) 1777 break; 1778 1779 if ($start_at == 0) 1780 { 1781 // Truncate the tables just in-case we didn't already (if we are coming directly here without converting the tables) 1782 $db->truncate_table('search_cache') or error('Unable to empty search cache table', __FILE__, __LINE__, $db->error()); 1783 $db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error()); 1784 $db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error()); 1785 1786 // Reset the sequence for the search words (not needed for SQLite) 1787 switch ($db_type) 1788 { 1789 case 'mysql': 1790 case 'mysqli': 1791 case 'mysql_innodb': 1792 case 'mysqli_innodb': 1793 $db->query('ALTER TABLE '.$db->prefix.'search_words auto_increment=1') or error('Unable to update table auto_increment', __FILE__, __LINE__, $db->error()); 1794 break; 1795 1796 case 'pgsql'; 1797 $db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error()); 1798 break; 1799 } 1800 } 1801 1802 require PUN_ROOT.'include/search_idx.php'; 1803 1804 // Fetch posts to process this cycle 1805 $result = $db->query('SELECT p.id, p.message, t.subject, t.first_post_id FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE p.id > '.$start_at.' ORDER BY p.id ASC LIMIT '.PER_PAGE) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error()); 1806 1807 $end_at = 0; 1808 while ($cur_item = $db->fetch_assoc($result)) 1809 { 1810 echo sprintf($lang_update['Rebuilding index item'], $lang_update['post'], $cur_item['id']).'<br />'."\n"; 1811 1812 if ($cur_item['id'] == $cur_item['first_post_id']) 1813 update_search_index('post', $cur_item['id'], $cur_item['message'], $cur_item['subject']); 1814 else 1815 update_search_index('post', $cur_item['id'], $cur_item['message']); 1816 1817 $end_at = $cur_item['id']; 1818 } 1819 1820 // Check if there is more work to do 1821 if ($end_at > 0) 1822 { 1823 $result = $db->query('SELECT 1 FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error()); 1824 1825 if ($db->num_rows($result) > 0) 1826 $query_str = '?stage=rebuild_idx&start_at='.$end_at; 1827 } 1828 1829 break; 1830 1831 1832 // Show results page 1833 case 'finish': 1834 // We update the version number 1835 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO.'\' WHERE conf_name = \'o_cur_version\'') or error('Unable to update version', __FILE__, __LINE__, $db->error()); 1836 1837 // And the database revision number 1838 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO_DB_REVISION.'\' WHERE conf_name = \'o_database_revision\'') or error('Unable to update database revision number', __FILE__, __LINE__, $db->error()); 1839 1840 // And the search index revision number 1841 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO_SI_REVISION.'\' WHERE conf_name = \'o_searchindex_revision\'') or error('Unable to update search index revision number', __FILE__, __LINE__, $db->error()); 1842 1843 // And the parser revision number 1844 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO_PARSER_REVISION.'\' WHERE conf_name = \'o_parser_revision\'') or error('Unable to update parser revision number', __FILE__, __LINE__, $db->error()); 1845 1846 // Check the default language still exists! 1847 if (!file_exists(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/common.php')) 1848 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \'English\' WHERE conf_name = \'o_default_lang\'') or error('Unable to update default language', __FILE__, __LINE__, $db->error()); 1849 1850 // Check the default style still exists! 1851 if (!file_exists(PUN_ROOT.'style/'.$pun_config['o_default_style'].'.css')) 1852 $db->query('UPDATE '.$db->prefix.'config SET conf_value = \'Air\' WHERE conf_name = \'o_default_style\'') or error('Unable to update default style', __FILE__, __LINE__, $db->error()); 1853 1854 // This feels like a good time to synchronize the forums 1855 $result = $db->query('SELECT id FROM '.$db->prefix.'forums') or error('Unable to fetch forum IDs', __FILE__, __LINE__, $db->error()); 1856 1857 while ($row = $db->fetch_row($result)) 1858 update_forum($row[0]); 1859 1860 // Empty the PHP cache 1861 forum_clear_cache(); 1862 1863 // Delete the update lock file 1864 @unlink(FORUM_CACHE_DIR.'db_update.lock'); 1865 1866?> 1867<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 1868 1869<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>"> 1870<head> 1871<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 1872<title><?php echo $lang_update['Update'] ?></title> 1873<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" /> 1874</head> 1875<body> 1876 1877<div id="pundb_update" class="pun"> 1878<div class="top-box"><div><!-- Top Corners --></div></div> 1879<div class="punwrap"> 1880 1881<div class="blockform"> 1882 <h2><span><?php echo $lang_update['Update'] ?></span></h2> 1883 <div class="box"> 1884 <div class="fakeform"> 1885 <div class="inform"> 1886 <div class="forminfo"> 1887 <p style="font-size: 1.1em"><?php printf($lang_update['Successfully updated'], sprintf('<a href="index.php">%s</a>', $lang_update['go to index'])) ?></p> 1888 </div> 1889 </div> 1890 </div> 1891 </div> 1892</div> 1893 1894</div> 1895<div class="end-box"><div><!-- Bottom Corners --></div></div> 1896</div> 1897 1898</body> 1899</html> 1900<?php 1901 1902 break; 1903} 1904 1905$db->end_transaction(); 1906$db->close(); 1907 1908if ($query_str != '') 1909 exit('<script type="text/javascript">window.location="db_update.php'.$query_str.'&uid='.$uid.'"</script><noscript><meta http-equiv="refresh" content="0;url=db_update.php'.$query_str.'&uid='.$uid.'" /></noscript>');