PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/db_update.php

https://bitbucket.org/gencer/fluxbb
PHP | 1909 lines | 1263 code | 427 blank | 219 comment | 260 complexity | a004d8302dbf5e509f2ced5b2fd985e8 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Copyright (C) 2008-2012 FluxBB
  4. * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
  5. * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
  6. */
  7. // The FluxBB version this script updates to
  8. define('UPDATE_TO', '1.5.6');
  9. define('UPDATE_TO_DB_REVISION', 21);
  10. define('UPDATE_TO_SI_REVISION', 2);
  11. define('UPDATE_TO_PARSER_REVISION', 2);
  12. define('MIN_PHP_VERSION', '4.4.0');
  13. define('MIN_MYSQL_VERSION', '4.1.2');
  14. define('MIN_PGSQL_VERSION', '7.0.0');
  15. define('PUN_SEARCH_MIN_WORD', 3);
  16. define('PUN_SEARCH_MAX_WORD', 20);
  17. // The MySQL connection character set that was used for FluxBB 1.2 - in 99% of cases this should be detected automatically,
  18. // but can be overridden using the below constant if required.
  19. //define('FORUM_DEFAULT_CHARSET', 'latin1');
  20. // The number of items to process per page view (lower this if the update script times out during UTF-8 conversion)
  21. define('PER_PAGE', 300);
  22. // Don't set to UTF-8 until after we've found out what the default character set is
  23. define('FORUM_NO_SET_NAMES', 1);
  24. // Make sure we are running at least MIN_PHP_VERSION
  25. if (!function_exists('version_compare') || version_compare(PHP_VERSION, MIN_PHP_VERSION, '<'))
  26. 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.');
  27. define('PUN_ROOT', dirname(__FILE__).'/');
  28. // Attempt to load the configuration file config.php
  29. if (file_exists(PUN_ROOT.'config.php'))
  30. include PUN_ROOT.'config.php';
  31. // 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
  32. if (defined('FORUM'))
  33. define('PUN', FORUM);
  34. // If PUN isn't defined, config.php is missing or corrupt
  35. if (!defined('PUN'))
  36. {
  37. header('Location: install.php');
  38. exit;
  39. }
  40. // Enable debug mode
  41. if (!defined('PUN_DEBUG'))
  42. define('PUN_DEBUG', 1);
  43. // Load the functions script
  44. require PUN_ROOT.'include/functions.php';
  45. // Load UTF-8 functions
  46. require PUN_ROOT.'include/utf8/utf8.php';
  47. // Strip out "bad" UTF-8 characters
  48. forum_remove_bad_characters();
  49. // Reverse the effect of register_globals
  50. forum_unregister_globals();
  51. // Turn on full PHP error reporting
  52. error_reporting(E_ALL);
  53. // Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings)
  54. setlocale(LC_CTYPE, 'C');
  55. // Turn off magic_quotes_runtime
  56. if (get_magic_quotes_runtime())
  57. set_magic_quotes_runtime(0);
  58. // Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
  59. if (get_magic_quotes_gpc())
  60. {
  61. function stripslashes_array($array)
  62. {
  63. return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
  64. }
  65. $_GET = stripslashes_array($_GET);
  66. $_POST = stripslashes_array($_POST);
  67. $_COOKIE = stripslashes_array($_COOKIE);
  68. $_REQUEST = stripslashes_array($_REQUEST);
  69. }
  70. // If a cookie name is not specified in config.php, we use the default (forum_cookie)
  71. if (empty($cookie_name))
  72. $cookie_name = 'pun_cookie';
  73. // If the cache directory is not specified, we use the default setting
  74. if (!defined('FORUM_CACHE_DIR'))
  75. define('FORUM_CACHE_DIR', PUN_ROOT.'cache/');
  76. // Turn off PHP time limit
  77. @set_time_limit(0);
  78. // Define a few commonly used constants
  79. define('PUN_UNVERIFIED', 0);
  80. define('PUN_ADMIN', 1);
  81. define('PUN_MOD', 2);
  82. define('PUN_GUEST', 3);
  83. define('PUN_MEMBER', 4);
  84. // Load DB abstraction layer and try to connect
  85. require PUN_ROOT.'include/dblayer/common_db.php';
  86. // Check what the default character set is - since 1.2 didn't specify any we will use whatever the default was (usually latin1)
  87. $old_connection_charset = defined('FORUM_DEFAULT_CHARSET') ? FORUM_DEFAULT_CHARSET : $db->get_names();
  88. // Set the connection to UTF-8 now
  89. $db->set_names('utf8');
  90. // Get the forum config
  91. $result = $db->query('SELECT * FROM '.$db->prefix.'config') or error('Unable to fetch config.', __FILE__, __LINE__, $db->error());
  92. while ($cur_config_item = $db->fetch_row($result))
  93. $pun_config[$cur_config_item[0]] = $cur_config_item[1];
  94. // Load language file
  95. $default_lang = $pun_config['o_default_lang'];
  96. if (!file_exists(PUN_ROOT.'lang/'.$default_lang.'/update.php'))
  97. $default_lang = 'English';
  98. require PUN_ROOT.'lang/'.$default_lang.'/common.php';
  99. require PUN_ROOT.'lang/'.$default_lang.'/update.php';
  100. // Check current version
  101. $cur_version = $pun_config['o_cur_version'];
  102. if (version_compare($cur_version, '1.2', '<'))
  103. error(sprintf($lang_update['Version mismatch error'], $db_name));
  104. // Do some DB type specific checks
  105. $mysql = false;
  106. switch ($db_type)
  107. {
  108. case 'mysql':
  109. case 'mysqli':
  110. case 'mysql_innodb':
  111. case 'mysqli_innodb':
  112. $mysql_info = $db->get_version();
  113. if (version_compare($mysql_info['version'], MIN_MYSQL_VERSION, '<'))
  114. error(sprintf($lang_update['You are running error'], 'MySQL', $mysql_info['version'], UPDATE_TO, MIN_MYSQL_VERSION));
  115. $mysql = true;
  116. break;
  117. case 'pgsql':
  118. $pgsql_info = $db->get_version();
  119. if (version_compare($pgsql_info['version'], MIN_PGSQL_VERSION, '<'))
  120. error(sprintf($lang_update['You are running error'], 'PostgreSQL', $pgsql_info['version'], UPDATE_TO, MIN_PGSQL_VERSION));
  121. break;
  122. }
  123. // Check the database, search index and parser revision and the current version
  124. if (isset($pun_config['o_database_revision']) && $pun_config['o_database_revision'] >= UPDATE_TO_DB_REVISION &&
  125. isset($pun_config['o_searchindex_revision']) && $pun_config['o_searchindex_revision'] >= UPDATE_TO_SI_REVISION &&
  126. isset($pun_config['o_parser_revision']) && $pun_config['o_parser_revision'] >= UPDATE_TO_PARSER_REVISION &&
  127. version_compare($pun_config['o_cur_version'], UPDATE_TO, '>='))
  128. error($lang_update['No update error']);
  129. $default_style = $pun_config['o_default_style'];
  130. if (!file_exists(PUN_ROOT.'style/'.$default_style.'.css'))
  131. $default_style = 'Air';
  132. // Start a session, used to queue up errors if duplicate users occur when converting from FluxBB v1.2.
  133. session_start();
  134. //
  135. // Determines whether $str is UTF-8 encoded or not
  136. //
  137. function seems_utf8($str)
  138. {
  139. $str_len = strlen($str);
  140. for ($i = 0; $i < $str_len; ++$i)
  141. {
  142. if (ord($str[$i]) < 0x80) continue; # 0bbbbbbb
  143. else if ((ord($str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
  144. else if ((ord($str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
  145. else if ((ord($str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
  146. else if ((ord($str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
  147. else if ((ord($str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
  148. else return false; # Does not match any model
  149. for ($j = 0; $j < $n; ++$j) # n bytes matching 10bbbbbb follow ?
  150. {
  151. if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80))
  152. return false;
  153. }
  154. }
  155. return true;
  156. }
  157. //
  158. // Translates the number from a HTML numeric entity into an UTF-8 character
  159. //
  160. function dcr2utf8($src)
  161. {
  162. $dest = '';
  163. if ($src < 0)
  164. return false;
  165. else if ($src <= 0x007f)
  166. $dest .= chr($src);
  167. else if ($src <= 0x07ff)
  168. {
  169. $dest .= chr(0xc0 | ($src >> 6));
  170. $dest .= chr(0x80 | ($src & 0x003f));
  171. }
  172. else if ($src == 0xFEFF)
  173. {
  174. // nop -- zap the BOM
  175. }
  176. else if ($src >= 0xD800 && $src <= 0xDFFF)
  177. {
  178. // found a surrogate
  179. return false;
  180. }
  181. else if ($src <= 0xffff)
  182. {
  183. $dest .= chr(0xe0 | ($src >> 12));
  184. $dest .= chr(0x80 | (($src >> 6) & 0x003f));
  185. $dest .= chr(0x80 | ($src & 0x003f));
  186. }
  187. else if ($src <= 0x10ffff)
  188. {
  189. $dest .= chr(0xf0 | ($src >> 18));
  190. $dest .= chr(0x80 | (($src >> 12) & 0x3f));
  191. $dest .= chr(0x80 | (($src >> 6) & 0x3f));
  192. $dest .= chr(0x80 | ($src & 0x3f));
  193. }
  194. else
  195. {
  196. // out of range
  197. return false;
  198. }
  199. return $dest;
  200. }
  201. //
  202. // Attempts to convert $str from $old_charset to UTF-8. Also converts HTML entities (including numeric entities) to UTF-8 characters
  203. //
  204. function convert_to_utf8(&$str, $old_charset)
  205. {
  206. if (is_null($str) || $str == '')
  207. return false;
  208. $save = $str;
  209. // Replace literal entities (for non-UTF-8 compliant html_entity_encode)
  210. if (version_compare(PHP_VERSION, '5.0.0', '<') && $old_charset == 'ISO-8859-1' || $old_charset == 'ISO-8859-15')
  211. $str = html_entity_decode($str, ENT_QUOTES, $old_charset);
  212. if ($old_charset != 'UTF-8' && !seems_utf8($str))
  213. {
  214. if (function_exists('iconv'))
  215. $str = iconv(!empty($old_charset) ? $old_charset : 'ISO-8859-1', 'UTF-8', $str);
  216. else if (function_exists('mb_convert_encoding'))
  217. $str = mb_convert_encoding($str, 'UTF-8', !empty($old_charset) ? $old_charset : 'ISO-8859-1');
  218. else if ($old_charset == 'ISO-8859-1')
  219. $str = utf8_encode($str);
  220. }
  221. // Replace literal entities (for UTF-8 compliant html_entity_encode)
  222. if (version_compare(PHP_VERSION, '5.0.0', '>='))
  223. $str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
  224. // Replace numeric entities
  225. $str = preg_replace_callback('%&#([0-9]+);%', 'utf8_callback_1', $str);
  226. $str = preg_replace_callback('%&#x([a-f0-9]+);%i', 'utf8_callback_2', $str);
  227. // Remove "bad" characters
  228. $str = remove_bad_characters($str);
  229. return ($save != $str);
  230. }
  231. function utf8_callback_1($matches)
  232. {
  233. return dcr2utf8($matches[1]);
  234. }
  235. function utf8_callback_2($matches)
  236. {
  237. return dcr2utf8(hexdec($matches[1]));
  238. }
  239. //
  240. // Alter a table to be utf8. MySQL only
  241. // Function based on update_convert_table_utf8() from the Drupal project (http://drupal.org/)
  242. //
  243. function alter_table_utf8($table)
  244. {
  245. global $mysql, $db;
  246. static $types;
  247. if (!$mysql)
  248. return;
  249. if (!isset($types))
  250. {
  251. $types = array(
  252. 'char' => 'binary',
  253. 'varchar' => 'varbinary',
  254. 'tinytext' => 'tinyblob',
  255. 'mediumtext' => 'mediumblob',
  256. 'text' => 'blob',
  257. 'longtext' => 'longblob'
  258. );
  259. }
  260. // Set table default charset to utf8
  261. $db->query('ALTER TABLE '.$table.' CHARACTER SET utf8') or error('Unable to set table character set', __FILE__, __LINE__, $db->error());
  262. // Find out which columns need converting and build SQL statements
  263. $result = $db->query('SHOW FULL COLUMNS FROM '.$table) or error('Unable to fetch column information', __FILE__, __LINE__, $db->error());
  264. while ($cur_column = $db->fetch_assoc($result))
  265. {
  266. if (is_null($cur_column['Collation']))
  267. continue;
  268. list($type) = explode('(', $cur_column['Type']);
  269. if (isset($types[$type]) && strpos($cur_column['Collation'], 'utf8') === false)
  270. {
  271. $allow_null = ($cur_column['Null'] == 'YES');
  272. $collate = (substr($cur_column['Collation'], -3) == 'bin') ? 'utf8_bin' : 'utf8_general_ci';
  273. $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());
  274. $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());
  275. }
  276. }
  277. }
  278. //
  279. // Safely converts text type columns into utf8
  280. // If finished returns true, otherwise returns $end_at
  281. //
  282. function convert_table_utf8($table, $callback, $old_charset, $key = null, $start_at = null, $error_callback = null)
  283. {
  284. global $mysql, $db, $old_connection_charset;
  285. $finished = true;
  286. $end_at = 0;
  287. if ($mysql)
  288. {
  289. // Only set up the tables if we are doing this in 1 go, or it's the first go
  290. if (is_null($start_at) || $start_at == 0)
  291. {
  292. // Drop any temp table that exists, in-case it's left over from a failed update
  293. $db->drop_table($table.'_utf8', true) or error('Unable to drop left over temp table', __FILE__, __LINE__, $db->error());
  294. // Copy the table
  295. $db->query('CREATE TABLE '.$table.'_utf8 LIKE '.$table) or error('Unable to create new table', __FILE__, __LINE__, $db->error());
  296. // Set table default charset to utf8
  297. alter_table_utf8($table.'_utf8');
  298. }
  299. // Change to the old character set so MySQL doesn't attempt to perform conversion on the data from the old table
  300. $db->set_names($old_connection_charset);
  301. // Move & Convert everything
  302. $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());
  303. // Change back to utf8 mode so we can insert it into the new table
  304. $db->set_names('utf8');
  305. while ($cur_item = $db->fetch_assoc($result))
  306. {
  307. $cur_item = call_user_func($callback, $cur_item, $old_charset);
  308. $temp = array();
  309. foreach ($cur_item as $idx => $value)
  310. $temp[$idx] = is_null($value) ? 'NULL' : '\''.$db->escape($value).'\'';
  311. $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));
  312. $end_at = $cur_item[$key];
  313. }
  314. // 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
  315. if (!is_null($start_at) && $end_at > 0)
  316. {
  317. $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());
  318. $finished = $db->num_rows($result) == 0;
  319. }
  320. // Only swap the tables if we are doing this in 1 go, or it's the last go
  321. if ($finished)
  322. {
  323. // Delete old table
  324. $db->drop_table($table, true) or error('Unable to drop old table', __FILE__, __LINE__, $db->error());
  325. // Rename table
  326. $db->query('ALTER TABLE '.$table.'_utf8 RENAME '.$table) or error('Unable to rename new table', __FILE__, __LINE__, $db->error());
  327. return true;
  328. }
  329. return $end_at;
  330. }
  331. else
  332. {
  333. // Convert everything
  334. $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());
  335. while ($cur_item = $db->fetch_assoc($result))
  336. {
  337. $cur_item = call_user_func($callback, $cur_item, $old_charset);
  338. $temp = array();
  339. foreach ($cur_item as $idx => $value)
  340. $temp[] = $idx.'='.(is_null($value) ? 'NULL' : '\''.$db->escape($value).'\'');
  341. if (!empty($temp))
  342. $db->query('UPDATE '.$table.' SET '.implode(', ', $temp).' WHERE '.$key.'=\''.$db->escape($cur_item[$key]).'\'') or error('Unable to update data', __FILE__, __LINE__, $db->error());
  343. $end_at = $cur_item[$key];
  344. }
  345. if (!is_null($start_at) && $end_at > 0)
  346. {
  347. $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());
  348. if ($db->num_rows($result) == 0)
  349. return true;
  350. return $end_at;
  351. }
  352. return true;
  353. }
  354. }
  355. header('Content-type: text/html; charset=utf-8');
  356. // Empty all output buffers and stop buffering
  357. while (@ob_end_clean());
  358. $stage = isset($_REQUEST['stage']) ? $_REQUEST['stage'] : '';
  359. $old_charset = isset($_REQUEST['req_old_charset']) ? str_replace('ISO8859', 'ISO-8859', strtoupper($_REQUEST['req_old_charset'])) : 'ISO-8859-1';
  360. $start_at = isset($_REQUEST['start_at']) ? intval($_REQUEST['start_at']) : 0;
  361. $query_str = '';
  362. // Show form
  363. if (empty($stage))
  364. {
  365. if (file_exists(FORUM_CACHE_DIR.'db_update.lock'))
  366. {
  367. // Deal with newlines, tabs and multiple spaces
  368. $pattern = array("\t", ' ', ' ');
  369. $replace = array('&#160; &#160; ', '&#160; ', ' &#160;');
  370. $message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
  371. ?>
  372. <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'] ?>">
  373. <head>
  374. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  375. <title><?php echo $lang_update['Maintenance'] ?></title>
  376. <link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
  377. </head>
  378. <body>
  379. <div id="punmaint" class="pun">
  380. <div class="top-box"><div><!-- Top Corners --></div></div>
  381. <div class="punwrap">
  382. <div id="brdmain">
  383. <div class="block">
  384. <h2><?php echo $lang_update['Maintenance'] ?></h2>
  385. <div class="box">
  386. <div class="inbox">
  387. <p><?php echo $message ?></p>
  388. </div>
  389. </div>
  390. </div>
  391. </div>
  392. </div>
  393. <div class="end-box"><div><!-- Bottom Corners --></div></div>
  394. </div>
  395. </body>
  396. </html>
  397. <?php
  398. }
  399. else
  400. {
  401. ?>
  402. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  403. <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'] ?>">
  404. <head>
  405. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  406. <title><?php echo $lang_update['Update'] ?></title>
  407. <link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
  408. </head>
  409. <body onload="document.getElementById('install').req_db_pass.focus();document.getElementById('install').start.disabled=false;">
  410. <div id="pundb_update" class="pun">
  411. <div class="top-box"><div><!-- Top Corners --></div></div>
  412. <div class="punwrap">
  413. <div id="brdheader" class="block">
  414. <div class="box">
  415. <div id="brdtitle" class="inbox">
  416. <h1><span><?php echo $lang_update['Update'] ?></span></h1>
  417. <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>
  418. </div>
  419. </div>
  420. </div>
  421. <div id="brdmain">
  422. <div class="blockform">
  423. <h2><span><?php echo $lang_update['Update'] ?></span></h2>
  424. <div class="box">
  425. <form id="install" method="post" action="db_update.php">
  426. <input type="hidden" name="stage" value="start" />
  427. <div class="inform">
  428. <fieldset>
  429. <legend><?php echo $lang_update['Administrator only'] ?></legend>
  430. <div class="infldset">
  431. <p><?php echo $lang_update['Database password info'] ?></p>
  432. <p><strong><?php echo $lang_update['Note']; ?></strong> <?php echo $lang_update['Database password note'] ?></p>
  433. <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>
  434. <p><?php echo $lang_update['Maintenance message info'] ?></p>
  435. <div class="txtarea">
  436. <label class="required"><strong><?php echo $lang_update['Maintenance message'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br />
  437. <textarea name="req_maintenance_message" rows="4" cols="65"><?php echo pun_htmlspecialchars($pun_config['o_maintenance_message']) ?></textarea><br /></label>
  438. </div>
  439. </div>
  440. </fieldset>
  441. </div>
  442. <div class="inform">
  443. <div class="forminfo">
  444. <p><?php echo $lang_update['Intro 1'] ?></p>
  445. <p><?php echo $lang_update['Intro 2'] ?></p>
  446. <?php
  447. if (strpos($cur_version, '1.2') === 0)
  448. {
  449. if (!function_exists('iconv') && !function_exists('mb_convert_encoding'))
  450. {
  451. ?>
  452. <p><?php echo $lang_update['No charset conversion'] ?></p>
  453. <?php
  454. }
  455. ?>
  456. </div>
  457. </div>
  458. <div class="inform">
  459. <div class="forminfo">
  460. <p><?php echo $lang_update['Enable conversion'] ?></p>
  461. <p><?php echo $lang_update['Current character set'] ?></p>
  462. </div>
  463. <fieldset>
  464. <legend><?php echo $lang_update['Charset conversion'] ?></legend>
  465. <div class="infldset">
  466. <div class="rbox">
  467. <label><input type="checkbox" name="convert_charset" value="1" checked="checked" /><?php echo $lang_update['Enable conversion label'] ?><br /></label>
  468. </div>
  469. <label>
  470. <strong><?php echo $lang_update['Current character set label'] ?></strong><br /><?php echo $lang_update['Current character set info'] ?><br />
  471. <input type="text" name="req_old_charset" size="12" maxlength="20" value="<?php echo $old_charset ?>" /><br />
  472. </label>
  473. </div>
  474. </fieldset>
  475. <?php
  476. }
  477. else
  478. echo "\t\t\t\t".'</div>'."\n";
  479. ?>
  480. </div>
  481. <p class="buttons"><input type="submit" name="start" value="<?php echo $lang_update['Start update'] ?>" /></p>
  482. </form>
  483. </div>
  484. </div>
  485. </div>
  486. </div>
  487. <div class="end-box"><div><!-- Bottom Corners --></div></div>
  488. </div>
  489. </body>
  490. </html>
  491. <?php
  492. }
  493. $db->end_transaction();
  494. $db->close();
  495. exit;
  496. }
  497. // Read the lock file
  498. $lock = file_exists(FORUM_CACHE_DIR.'db_update.lock') ? trim(file_get_contents(FORUM_CACHE_DIR.'db_update.lock')) : false;
  499. $lock_error = false;
  500. // Generate or fetch the UID - this confirms we have a valid admin
  501. if (isset($_POST['req_db_pass']))
  502. {
  503. $req_db_pass = strtolower(pun_trim($_POST['req_db_pass']));
  504. switch ($db_type)
  505. {
  506. // For SQLite we compare against the database file name, since the password is left blank
  507. case 'sqlite':
  508. if ($req_db_pass != strtolower($db_name))
  509. error(sprintf($lang_update['Invalid file error'], 'config.php'));
  510. break;
  511. // For everything else, check the password matches
  512. default:
  513. if ($req_db_pass != strtolower($db_password))
  514. error(sprintf($lang_update['Invalid password error'], 'config.php'));
  515. break;
  516. }
  517. // Generate a unique id to identify this session, only if this is a valid session
  518. $uid = pun_hash($req_db_pass.'|'.uniqid(rand(), true));
  519. if ($lock) // We already have a lock file
  520. $lock_error = true;
  521. else // Create the lock file
  522. {
  523. $fh = @fopen(FORUM_CACHE_DIR.'db_update.lock', 'wb');
  524. if (!$fh)
  525. error(sprintf($lang_update['Unable to lock error'], 'cache'));
  526. fwrite($fh, $uid);
  527. fclose($fh);
  528. // Update maintenance message
  529. if ($_POST['req_maintenance_message'] != '')
  530. $maintenance_message = pun_trim(pun_linebreaks($_POST['req_maintenance_message']));
  531. else
  532. {
  533. // Load the admin_options.php language file
  534. require PUN_ROOT.'lang/'.$default_lang.'/admin_options.php';
  535. $maintenance_message = $lang_admin_options['Default maintenance message'];
  536. }
  537. $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());
  538. // Regenerate the config cache
  539. if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
  540. require PUN_ROOT.'include/cache.php';
  541. generate_config_cache();
  542. }
  543. }
  544. else if (isset($_GET['uid']))
  545. {
  546. $uid = pun_trim($_GET['uid']);
  547. if (!$lock || $lock != $uid) // The lock doesn't exist or doesn't match the given UID
  548. $lock_error = true;
  549. }
  550. else
  551. error($lang_update['No password error']);
  552. // If there is an error with the lock file
  553. if ($lock_error)
  554. error(sprintf($lang_update['Script runs error'], FORUM_CACHE_DIR.'db_update.lock'));
  555. switch ($stage)
  556. {
  557. // Start by updating the database structure
  558. case 'start':
  559. $query_str = '?stage=preparse_posts';
  560. // If we don't need to update the database, skip this stage
  561. if (isset($pun_config['o_database_revision']) && $pun_config['o_database_revision'] >= UPDATE_TO_DB_REVISION)
  562. break;
  563. // Make all email fields VARCHAR(80)
  564. $db->alter_field('bans', 'email', 'VARCHAR(80)', true) or error('Unable to alter email field', __FILE__, __LINE__, $db->error());
  565. $db->alter_field('posts', 'poster_email', 'VARCHAR(80)', true) or error('Unable to alter poster_email field', __FILE__, __LINE__, $db->error());
  566. $db->alter_field('users', 'email', 'VARCHAR(80)', false, '') or error('Unable to alter email field', __FILE__, __LINE__, $db->error());
  567. $db->alter_field('users', 'jabber', 'VARCHAR(80)', true) or error('Unable to alter jabber field', __FILE__, __LINE__, $db->error());
  568. $db->alter_field('users', 'msn', 'VARCHAR(80)', true) or error('Unable to alter msn field', __FILE__, __LINE__, $db->error());
  569. $db->alter_field('users', 'activate_string', 'VARCHAR(80)', true) or error('Unable to alter activate_string field', __FILE__, __LINE__, $db->error());
  570. // Make all IP fields VARCHAR(39) to support IPv6
  571. $db->alter_field('posts', 'poster_ip', 'VARCHAR(39)', true) or error('Unable to alter poster_ip field', __FILE__, __LINE__, $db->error());
  572. $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());
  573. // Make the message field MEDIUMTEXT to allow proper conversion of 65535 character posts to UTF-8
  574. $db->alter_field('posts', 'message', 'MEDIUMTEXT', true) or error('Unable to alter message field', __FILE__, __LINE__, $db->error());
  575. // Add the DST option to the users table
  576. $db->add_field('users', 'dst', 'TINYINT(1)', false, 0, 'timezone') or error('Unable to add dst field', __FILE__, __LINE__, $db->error());
  577. // Add the last_post column to the online table
  578. $db->add_field('online', 'last_post', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_post field', __FILE__, __LINE__, $db->error());
  579. // Add the last_search column to the online table
  580. $db->add_field('online', 'last_search', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_search field', __FILE__, __LINE__, $db->error());
  581. // Add the last_search column to the users table
  582. $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());
  583. // Drop use_avatar column from users table
  584. $db->drop_field('users', 'use_avatar') or error('Unable to drop use_avatar field', __FILE__, __LINE__, $db->error());
  585. // Drop save_pass column from users table
  586. $db->drop_field('users', 'save_pass') or error('Unable to drop save_pass field', __FILE__, __LINE__, $db->error());
  587. // Drop g_edit_subjects_interval column from groups table
  588. $db->drop_field('groups', 'g_edit_subjects_interval');
  589. // Add database revision number
  590. if (!array_key_exists('o_database_revision', $pun_config))
  591. $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());
  592. // Add search index revision number
  593. if (!array_key_exists('o_searchindex_revision', $pun_config))
  594. $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());
  595. // Add parser revision number
  596. if (!array_key_exists('o_parser_revision', $pun_config))
  597. $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());
  598. // Add default email setting option
  599. if (!array_key_exists('o_default_email_setting', $pun_config))
  600. $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());
  601. // Make sure we have o_additional_navlinks (was added in 1.2.1)
  602. if (!array_key_exists('o_additional_navlinks', $pun_config))
  603. $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());
  604. // Insert new config option o_topic_views
  605. if (!array_key_exists('o_topic_views', $pun_config))
  606. $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());
  607. // Insert new config option o_signatures
  608. if (!array_key_exists('o_signatures', $pun_config))
  609. $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());
  610. // Insert new config option o_smtp_ssl
  611. if (!array_key_exists('o_smtp_ssl', $pun_config))
  612. $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());
  613. // Insert new config option o_default_dst
  614. if (!array_key_exists('o_default_dst', $pun_config))
  615. $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());
  616. // Insert new config option o_quote_depth
  617. if (!array_key_exists('o_quote_depth', $pun_config))
  618. $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());
  619. // Insert new config option o_feed_type
  620. if (!array_key_exists('o_feed_type', $pun_config))
  621. $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());
  622. // Insert new config option o_feed_ttl
  623. if (!array_key_exists('o_feed_ttl', $pun_config))
  624. $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());
  625. // Insert config option o_base_url which was removed in 1.3
  626. if (!array_key_exists('o_base_url', $pun_config))
  627. {
  628. // 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
  629. if (!isset($base_url))
  630. {
  631. // Make an educated guess regarding base_url
  632. $base_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; // protocol
  633. $base_url .= preg_replace('%:(80|443)$%', '', $_SERVER['HTTP_HOST']); // host[:port]
  634. $base_url .= str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])); // path
  635. }
  636. if (substr($base_url, -1) == '/')
  637. $base_url = substr($base_url, 0, -1);
  638. $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());
  639. }
  640. if (strpos($cur_version, '1.2') === 0)
  641. {
  642. // Groups are almost the same as 1.2:
  643. // unverified: 32000 -> 0
  644. $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());
  645. }
  646. else if (strpos($cur_version, '1.3') === 0)
  647. {
  648. // Groups have changed quite a lot from 1.3:
  649. // unverified: 0 -> 0
  650. // admin: 1 -> 1
  651. // mod: ? -> 2
  652. // guest: 2 -> 3
  653. // member: ? -> 4
  654. $result = $db->query('SELECT MAX(g_id) + 1 FROM '.$db->prefix.'groups') or error('Unable to select temp group ID', __FILE__, __LINE__, $db->error());
  655. $temp_id = $db->result($result);
  656. $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());
  657. if ($db->num_rows($result))
  658. $mod_gid = $db->result($result);
  659. else
  660. {
  661. $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());
  662. $mod_gid = $db->insert_id();
  663. }
  664. $member_gid = $pun_config['o_default_user_group'];
  665. // move the mod group to a temp place
  666. $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());
  667. $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());
  668. $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());
  669. if ($member_gid == $mod_gid) $member_gid = $temp_id;
  670. // move whoever is in 3 to a spare slot
  671. $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());
  672. $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());
  673. $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());
  674. if ($member_gid == 3) $member_gid = $mod_gid;
  675. // move guest to 3
  676. $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());
  677. $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());
  678. $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());
  679. if ($member_gid == 2) $member_gid = 3;
  680. // move mod group in temp place to 2
  681. $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());
  682. $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());
  683. $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());
  684. if ($member_gid == $temp_id) $member_gid = 2;
  685. // Only move stuff around if it isn't already in the right place
  686. if ($member_gid != $mod_gid || $member_gid != 4)
  687. {
  688. // move members to temp place
  689. $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());
  690. $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());
  691. $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());
  692. // move whoever is in 4 to members place
  693. $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());
  694. $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());
  695. $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());
  696. // move members in temp place to 4
  697. $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());
  698. $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());
  699. $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());
  700. }
  701. $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());
  702. }
  703. // Server time zone is now simply the default time zone
  704. if (!array_key_exists('o_default_timezone', $pun_config))
  705. $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());
  706. // Increase visit timeout to 30 minutes (only if it hasn't been changed from the default)
  707. if (!array_key_exists('o_database_revision', $pun_config) && $pun_config['o_timeout_visit'] == '600')
  708. $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());
  709. // Remove obsolete g_post_polls permission from groups table
  710. $db->drop_field('groups', 'g_post_polls');
  711. // Make room for multiple moderator groups
  712. if (!$db->field_exists('groups', 'g_moderator'))
  713. {
  714. // Add g_moderator column to groups table
  715. $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());
  716. // Give the moderator group moderator privileges
  717. $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());
  718. }
  719. // Replace obsolete p_mod_edit_users config setting with new per-group permission
  720. if (array_key_exists('p_mod_edit_users', $pun_config))
  721. {
  722. $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());
  723. $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());
  724. $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());
  725. }
  726. // Replace obsolete p_mod_rename_users config setting with new per-group permission
  727. if (array_key_exists('p_mod_rename_users', $pun_config))
  728. {
  729. $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());
  730. $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());
  731. $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());
  732. }
  733. // Replace obsolete p_mod_change_passwords config setting with new per-group permission
  734. if (array_key_exists('p_mod_change_passwords', $pun_config))
  735. {
  736. $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());
  737. $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());
  738. $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());
  739. }
  740. // Replace obsolete p_mod_ban_users config setting with new per-group permission
  741. if (array_key_exists('p_mod_ban_users', $pun_config))
  742. {
  743. $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());
  744. $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());
  745. $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());
  746. }
  747. // We need to add a unique index to avoid users having multiple rows in the online table
  748. if (!$db->index_exists('online', 'user_id_ident_idx'))
  749. {
  750. $db->truncate_table('online') or error('Unable to clear online table', __FILE__, __LINE__, $db->error());
  751. if ($mysql)
  752. $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());
  753. else
  754. $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());
  755. }
  756. // Remove the redundant user_id_idx on the online table
  757. $db->drop_index('online', 'user_id_idx') or error('Unable to drop user_id_idx index', __FILE__, __LINE__, $db->error());
  758. // Add an index to ident on the online table
  759. if ($mysql)
  760. $db->add_index('online', 'ident_idx', array('ident(25)')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error());
  761. else
  762. $db->add_index('online', 'ident_idx', array('ident')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error());
  763. // Add an index to logged in the online table
  764. $db->add_index('online', 'logged_idx', array('logged')) or error('Unable to add logged_idx index', __FILE__, __LINE__, $db->error());
  765. // Add an index to last_post in the topics table
  766. $db->add_index('topics', 'last_post_idx', array('last_post')) or error('Unable to add last_post_idx index', __FILE__, __LINE__, $db->error());
  767. // Add an index to username on the bans table
  768. if ($mysql)
  769. $db->add_index('bans', 'username_idx', array('username(25)')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error());
  770. else
  771. $db->add_index('bans', 'username_idx', array('username')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error());
  772. // Change the username_idx on users to a unique index of max size 25
  773. $db->drop_index('users', 'username_idx') or error('Unable to drop old username_idx index', __FILE__, __LINE__, $db->error());
  774. $field = $mysql ? 'username(25)' : 'username';
  775. // 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
  776. // 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.
  777. if (!$db->add_index('users', 'username_idx', array($field), true))
  778. $db->add_index('users', 'username_idx', array($field)) or error('Unable to add username_idx field', __FILE__, __LINE__, $db->error());
  779. // Add g_view_users column to groups table
  780. $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());
  781. // Add the last_email_sent column to the users table and the g_send_email and
  782. // g_email_flood columns to the groups table
  783. $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());
  784. $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());
  785. $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());
  786. // Add the last_report_sent column to the users table and the g_report_flood
  787. // column to the groups table
  788. $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());
  789. $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());
  790. // Set non-default g_send_email, g_flood_email and g_flood_report values properly
  791. $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());
  792. $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());
  793. // Add the auto notify/subscription option to the users table
  794. $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());
  795. // Add the first_post_id column to the topics table
  796. if (!$db->field_exists('topics', 'first_post_id'))
  797. {
  798. $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());
  799. $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());
  800. // Now that we've added the column and indexed it, we need to give it correct data
  801. $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());
  802. while ($cur_post = $db->fetch_assoc($result))
  803. $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());
  804. }
  805. // Move any users with the old unverified status to their new group
  806. $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());
  807. // Add the ban_creator column to the bans table
  808. $db->add_field('bans', 'ban_creator', 'INT(10) UNSIGNED', false, 0) or error('Unable to add ban_creator field', __FILE__, __LINE__, $db->error());
  809. // Add the time/date format settings to the user table
  810. $db->add_field('users', 'time_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add time_format field', __FILE__, __LINE__, $db->error());
  811. $db->add_field('users', 'date_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add date_format field', __FILE__, __LINE__, $db->error());
  812. // Change the search_data column to mediumtext
  813. $db->alter_field('search_cache', 'search_data', 'MEDIUMTEXT', true) or error('Unable to alter search_data field', __FILE__, __LINE__, $db->error());
  814. // Add the group promotion columns to the groups table
  815. $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());
  816. $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());
  817. // Add a field for the per-group permission to post links
  818. $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());
  819. // Add a field for the per-group permission to promote users to the next auto-promote group
  820. $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());
  821. // In case we had the fulltext search extension installed (1.3-legacy), remove it
  822. $db->drop_index('topics', 'subject_idx') or error('Unable to drop subject_idx index', __FILE__, __LINE__, $db->error());
  823. $db->drop_index('posts', 'message_idx') or error('Unable to drop message_idx index', __FILE__, __LINE__, $db->error());
  824. // In case we had the fulltext search mod installed (1.2), remove it
  825. $db->drop_index('topics', 'subject_fulltext_search') or error('Unable to drop subject_fulltext_search index', __FILE__, __LINE__, $db->error());
  826. $db->drop_index('posts', 'message_fulltext_search') or error('Unable to drop message_fulltext_search index', __FILE__, __LINE__, $db->error());
  827. // If the search_cache table has been dropped by the fulltext search extension, recreate it
  828. if (!$db->table_exists('search_cache'))
  829. {
  830. $schema = array(
  831. 'FIELDS' => array(
  832. 'id' => array(
  833. 'datatype' => 'INT(10) UNSIGNED',
  834. 'allow_null' => false,
  835. 'default' => '0'
  836. ),
  837. 'ident' => array(
  838. 'datatype' => 'VARCHAR(200)',
  839. 'allow_null' => false,
  840. 'default' => '\'\''
  841. ),
  842. 'search_data' => array(
  843. 'datatype' => 'MEDIUMTEXT',
  844. 'allow_null' => true
  845. )
  846. ),
  847. 'PRIMARY KEY' => array('id'),
  848. 'INDEXES' => array(
  849. 'ident_idx' => array('ident')
  850. )
  851. );
  852. if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
  853. $schema['INDEXES']['ident_idx'] = array('ident(8)');
  854. $db->create_table('search_cache', $schema);
  855. }
  856. // If the search_matches table has been dropped by the fulltext search extension, recreate it
  857. if (!$db->table_exists('search_matches'))
  858. {
  859. $schema = array(
  860. 'FIELDS' => array(
  861. 'post_id' => array(
  862. 'datatype' => 'INT(10) UNSIGNED',
  863. 'allow_null' => false,
  864. 'default'

Large files files are truncated, but you can click here to view the full file