[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/install/ -> database_update.php (source)

   1  <?php
   2  /**
   3  *
   4  * @package install
   5  * @version $Id$
   6  * @copyright (c) 2006 phpBB Group
   7  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
   8  *
   9  */
  10  
  11  define('UPDATES_TO_VERSION', '3.0.12');
  12  
  13  // Enter any version to update from to test updates. The version within the db will not be updated.
  14  define('DEBUG_FROM_VERSION', false);
  15  
  16  // Which oldest version does this updater support?
  17  define('OLDEST_FROM_VERSION', '3.0.0');
  18  
  19  // Return if we "just include it" to find out for which version the database update is responsible for
  20  if (defined('IN_PHPBB') && defined('IN_INSTALL'))
  21  {
  22      $updates_to_version = UPDATES_TO_VERSION;
  23      $debug_from_version = DEBUG_FROM_VERSION;
  24      $oldest_from_version = OLDEST_FROM_VERSION;
  25  
  26      return;
  27  }
  28  
  29  /**
  30  */
  31  define('IN_PHPBB', true);
  32  define('IN_INSTALL', true);
  33  
  34  $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../';
  35  $phpEx = substr(strrchr(__FILE__, '.'), 1);
  36  
  37  if (!function_exists('phpbb_require_updated'))
  38  {
  39  	function phpbb_require_updated($path, $optional = false)
  40      {
  41          global $phpbb_root_path;
  42  
  43          $new_path = $phpbb_root_path . 'install/update/new/' . $path;
  44          $old_path = $phpbb_root_path . $path;
  45  
  46          if (file_exists($new_path))
  47          {
  48              require($new_path);
  49          }
  50          else if (!$optional || file_exists($old_path))
  51          {
  52              require($old_path);
  53          }
  54      }
  55  }
  56  
  57  phpbb_require_updated('includes/startup.' . $phpEx);
  58  
  59  $updates_to_version = UPDATES_TO_VERSION;
  60  $debug_from_version = DEBUG_FROM_VERSION;
  61  $oldest_from_version = OLDEST_FROM_VERSION;
  62  
  63  @set_time_limit(0);
  64  
  65  // Include essential scripts
  66  include($phpbb_root_path . 'config.' . $phpEx);
  67  
  68  if (!defined('PHPBB_INSTALLED') || empty($dbms) || empty($acm_type))
  69  {
  70      die("Please read: <a href='../docs/INSTALL.html'>INSTALL.html</a> before attempting to update.");
  71  }
  72  
  73  // Load Extensions
  74  if (!empty($load_extensions) && function_exists('dl'))
  75  {
  76      $load_extensions = explode(',', $load_extensions);
  77  
  78      foreach ($load_extensions as $extension)
  79      {
  80          @dl(trim($extension));
  81      }
  82  }
  83  
  84  // Include files
  85  require($phpbb_root_path . 'includes/acm/acm_' . $acm_type . '.' . $phpEx);
  86  require($phpbb_root_path . 'includes/cache.' . $phpEx);
  87  require($phpbb_root_path . 'includes/template.' . $phpEx);
  88  require($phpbb_root_path . 'includes/session.' . $phpEx);
  89  require($phpbb_root_path . 'includes/auth.' . $phpEx);
  90  
  91  require($phpbb_root_path . 'includes/functions.' . $phpEx);
  92  
  93  phpbb_require_updated('includes/functions_content.' . $phpEx, true);
  94  
  95  require($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
  96  require($phpbb_root_path . 'includes/constants.' . $phpEx);
  97  require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
  98  require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
  99  
 100  phpbb_require_updated('includes/db/db_tools.' . $phpEx);
 101  
 102  // new table constants are separately defined here in case the updater is run
 103  // before the files are updated
 104  if (!defined('LOGIN_ATTEMPT_TABLE'))
 105  {
 106      define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts');
 107  }
 108  
 109  $user = new user();
 110  $cache = new cache();
 111  $db = new $sql_db();
 112  
 113  // Add own hook handler, if present. :o
 114  if (file_exists($phpbb_root_path . 'includes/hooks/index.' . $phpEx))
 115  {
 116      require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
 117      $phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));
 118  
 119      foreach ($cache->obtain_hooks() as $hook)
 120      {
 121          @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx);
 122      }
 123  }
 124  else
 125  {
 126      $phpbb_hook = false;
 127  }
 128  
 129  // Connect to DB
 130  $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);
 131  
 132  // We do not need this any longer, unset for safety purposes
 133  unset($dbpasswd);
 134  
 135  $user->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '';
 136  $user->ip = (stripos($user->ip, '::ffff:') === 0) ? substr($user->ip, 7) : $user->ip;
 137  
 138  $sql = "SELECT config_value
 139      FROM " . CONFIG_TABLE . "
 140      WHERE config_name = 'default_lang'";
 141  $result = $db->sql_query($sql);
 142  $row = $db->sql_fetchrow($result);
 143  $db->sql_freeresult($result);
 144  
 145  $language = basename(request_var('language', ''));
 146  
 147  if (!$language)
 148  {
 149      $language = $row['config_value'];
 150  }
 151  
 152  if (!file_exists($phpbb_root_path . 'language/' . $language))
 153  {
 154      die('No language found!');
 155  }
 156  
 157  // And finally, load the relevant language files
 158  include($phpbb_root_path . 'language/' . $language . '/common.' . $phpEx);
 159  include($phpbb_root_path . 'language/' . $language . '/acp/common.' . $phpEx);
 160  include($phpbb_root_path . 'language/' . $language . '/install.' . $phpEx);
 161  
 162  // Set PHP error handler to ours
 163  //set_error_handler('msg_handler');
 164  
 165  // Define some variables for the database update
 166  $inline_update = (request_var('type', 0)) ? true : false;
 167  
 168  // To let set_config() calls succeed, we need to make the config array available globally
 169  $config = array();
 170  
 171  $sql = 'SELECT *
 172      FROM ' . CONFIG_TABLE;
 173  $result = $db->sql_query($sql);
 174  
 175  while ($row = $db->sql_fetchrow($result))
 176  {
 177      $config[$row['config_name']] = $row['config_value'];
 178  }
 179  $db->sql_freeresult($result);
 180  
 181  // phpbb_db_tools will be taken from new files (under install/update/new)
 182  // if possible, falling back to the board's copy.
 183  $db_tools = new phpbb_db_tools($db, true);
 184  
 185  $database_update_info = database_update_info();
 186  
 187  $error_ary = array();
 188  $errored = false;
 189  
 190  header('Content-type: text/html; charset=UTF-8');
 191  
 192  ?>
 193  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 194  <html xmlns="http://www.w3.org/1999/xhtml" dir="<?php echo $lang['DIRECTION']; ?>" lang="<?php echo $lang['USER_LANG']; ?>" xml:lang="<?php echo $lang['USER_LANG']; ?>">
 195  <head>
 196  
 197  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
 198  <meta http-equiv="content-language" content="<?php echo $lang['USER_LANG']; ?>" />
 199  <meta http-equiv="content-style-type" content="text/css" />
 200  <meta http-equiv="imagetoolbar" content="no" />
 201  
 202  <title><?php echo $lang['UPDATING_TO_LATEST_STABLE']; ?></title>
 203  
 204  <link href="../adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" />
 205  
 206  </head>
 207  
 208  <body>
 209  <div id="wrap">
 210      <div id="page-header">&nbsp;</div>
 211  
 212      <div id="page-body">
 213          <div id="acp">
 214          <div class="panel">
 215              <span class="corners-top"><span></span></span>
 216                  <div id="content">
 217                      <div id="main" class="install-body">
 218  
 219      <h1><?php echo $lang['UPDATING_TO_LATEST_STABLE']; ?></h1>
 220  
 221      <br />
 222  
 223      <p><?php echo $lang['DATABASE_TYPE']; ?> :: <strong><?php echo $db->sql_layer; ?></strong><br />
 224  <?php
 225  
 226  if ($debug_from_version !== false)
 227  {
 228      $config['version'] = $debug_from_version;
 229  }
 230  
 231  echo $lang['PREVIOUS_VERSION'] . ' :: <strong>' . $config['version'] . '</strong><br />';
 232  echo $lang['UPDATED_VERSION'] . ' :: <strong>' . $updates_to_version . '</strong></p>';
 233  
 234  $current_version = str_replace('rc', 'RC', strtolower($config['version']));
 235  $latest_version = str_replace('rc', 'RC', strtolower($updates_to_version));
 236  $orig_version = $config['version'];
 237  
 238  // Fill DB version
 239  if (empty($config['dbms_version']))
 240  {
 241      set_config('dbms_version', $db->sql_server_info(true));
 242  }
 243  
 244  // Firebird update from Firebird 2.0 to 2.1+ required?
 245  if ($db->sql_layer == 'firebird')
 246  {
 247      // We do not trust any PHP5 function enabled, we will simply test for a function new in 2.1
 248      $db->sql_return_on_error(true);
 249  
 250      $sql = 'SELECT 1 FROM RDB$DATABASE
 251          WHERE BIN_AND(10, 1) = 0';
 252      $result = $db->sql_query($sql);
 253  
 254      if (!$result || $db->sql_error_triggered)
 255      {
 256          echo '<br /><br />';
 257          echo '<h1>' . $lang['ERROR'] . '</h1><br />';
 258  
 259          echo '<p>' . $lang['FIREBIRD_DBMS_UPDATE_REQUIRED'] . '</p>';
 260  
 261          _print_footer();
 262  
 263          exit_handler();
 264          exit;
 265      }
 266  
 267      $db->sql_freeresult($result);
 268      $db->sql_return_on_error(false);
 269  }
 270  
 271  // MySQL update from MySQL 3.x/4.x to > 4.1.x required?
 272  if ($db->sql_layer == 'mysql' || $db->sql_layer == 'mysql4' || $db->sql_layer == 'mysqli')
 273  {
 274      // Verify by fetching column... if the column type matches the new type we update dbms_version...
 275      $sql = "SHOW COLUMNS FROM " . CONFIG_TABLE;
 276      $result = $db->sql_query($sql);
 277  
 278      $column_type = '';
 279      while ($row = $db->sql_fetchrow($result))
 280      {
 281          $field = strtolower($row['Field']);
 282  
 283          if ($field == 'config_value')
 284          {
 285              $column_type = strtolower($row['Type']);
 286              break;
 287          }
 288      }
 289      $db->sql_freeresult($result);
 290  
 291      // If column type is blob, but mysql version says we are on > 4.1.3, then the schema needs an update
 292      if (strpos($column_type, 'blob') !== false && version_compare($db->sql_server_info(true), '4.1.3', '>='))
 293      {
 294          echo '<br /><br />';
 295          echo '<h1>' . $lang['ERROR'] . '</h1><br />';
 296  
 297          echo '<p>' . sprintf($lang['MYSQL_SCHEMA_UPDATE_REQUIRED'], $config['dbms_version'], $db->sql_server_info(true)) . '</p>';
 298  
 299          _print_footer();
 300  
 301          exit_handler();
 302          exit;
 303      }
 304  }
 305  
 306  // Now check if the user wants to update from a version we no longer support updates from
 307  if (version_compare($current_version, $oldest_from_version, '<'))
 308  {
 309      echo '<br /><br /><h1>' . $lang['ERROR'] . '</h1><br />';
 310      echo '<p>' . sprintf($lang['DB_UPDATE_NOT_SUPPORTED'], $oldest_from_version, $current_version) . '</p>';
 311  
 312      _print_footer();
 313      exit_handler();
 314      exit;
 315  }
 316  
 317  // If the latest version and the current version are 'unequal', we will update the version_update_from, else we do not update anything.
 318  if ($inline_update)
 319  {
 320      if ($current_version !== $latest_version)
 321      {
 322          set_config('version_update_from', $orig_version);
 323      }
 324  }
 325  else
 326  {
 327      // If not called from the update script, we will actually remove the traces
 328      $db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'version_update_from'");
 329  }
 330  
 331  // Schema updates
 332  ?>
 333      <br /><br />
 334  
 335      <h1><?php echo $lang['UPDATE_DATABASE_SCHEMA']; ?></h1>
 336  
 337      <br />
 338      <p><?php echo $lang['PROGRESS']; ?> :: <strong>
 339  
 340  <?php
 341  
 342  flush();
 343  
 344  // We go through the schema changes from the lowest to the highest version
 345  // We try to also include versions 'in-between'...
 346  $no_updates = true;
 347  $versions = array_keys($database_update_info);
 348  for ($i = 0; $i < sizeof($versions); $i++)
 349  {
 350      $version = $versions[$i];
 351      $schema_changes = $database_update_info[$version];
 352  
 353      $next_version = (isset($versions[$i + 1])) ? $versions[$i + 1] : $updates_to_version;
 354  
 355      // If the installed version to be updated to is < than the current version, and if the current version is >= as the version to be updated to next, we will skip the process
 356      if (version_compare($version, $current_version, '<') && version_compare($current_version, $next_version, '>='))
 357      {
 358          continue;
 359      }
 360  
 361      if (!sizeof($schema_changes))
 362      {
 363          continue;
 364      }
 365  
 366      $no_updates = false;
 367  
 368      // We run one index after the other... to be consistent with schema changes...
 369      foreach ($schema_changes as $key => $changes)
 370      {
 371          $statements = $db_tools->perform_schema_changes(array($key => $changes));
 372  
 373          foreach ($statements as $sql)
 374          {
 375              _sql($sql, $errored, $error_ary);
 376          }
 377      }
 378  }
 379  
 380  _write_result($no_updates, $errored, $error_ary);
 381  
 382  // Data updates
 383  $error_ary = array();
 384  $errored = $no_updates = false;
 385  
 386  ?>
 387  
 388  <br /><br />
 389  <h1><?php echo $lang['UPDATING_DATA']; ?></h1>
 390  <br />
 391  <p><?php echo $lang['PROGRESS']; ?> :: <strong>
 392  
 393  <?php
 394  
 395  flush();
 396  
 397  $no_updates = true;
 398  $versions = array_keys($database_update_info);
 399  
 400  // some code magic
 401  for ($i = 0; $i < sizeof($versions); $i++)
 402  {
 403      $version = $versions[$i];
 404      $next_version = (isset($versions[$i + 1])) ? $versions[$i + 1] : $updates_to_version;
 405  
 406      // If the installed version to be updated to is < than the current version, and if the current version is >= as the version to be updated to next, we will skip the process
 407      if (version_compare($version, $current_version, '<') && version_compare($current_version, $next_version, '>='))
 408      {
 409          continue;
 410      }
 411  
 412      change_database_data($no_updates, $version);
 413  }
 414  
 415  _write_result($no_updates, $errored, $error_ary);
 416  
 417  $error_ary = array();
 418  $errored = $no_updates = false;
 419  
 420  ?>
 421  
 422  <br /><br />
 423  <h1><?php echo $lang['UPDATE_VERSION_OPTIMIZE']; ?></h1>
 424  <br />
 425  <p><?php echo $lang['PROGRESS']; ?> :: <strong>
 426  
 427  <?php
 428  
 429  flush();
 430  
 431  if ($debug_from_version === false)
 432  {
 433      // update the version
 434      $sql = "UPDATE " . CONFIG_TABLE . "
 435          SET config_value = '$updates_to_version'
 436          WHERE config_name = 'version'";
 437      _sql($sql, $errored, $error_ary);
 438  }
 439  
 440  // Reset permissions
 441  $sql = 'UPDATE ' . USERS_TABLE . "
 442      SET user_permissions = '',
 443          user_perm_from = 0";
 444  _sql($sql, $errored, $error_ary);
 445  
 446  // Update the dbms version if everything is ok...
 447  set_config('dbms_version', $db->sql_server_info(true));
 448  
 449  /* Optimize/vacuum analyze the tables where appropriate
 450  // this should be done for each version in future along with
 451  // the version number update
 452  switch ($db->sql_layer)
 453  {
 454      case 'mysql':
 455      case 'mysqli':
 456      case 'mysql4':
 457          $sql = 'OPTIMIZE TABLE ' . $table_prefix . 'auth_access, ' . $table_prefix . 'banlist, ' . $table_prefix . 'categories, ' . $table_prefix . 'config, ' . $table_prefix . 'disallow, ' . $table_prefix . 'forum_prune, ' . $table_prefix . 'forums, ' . $table_prefix . 'groups, ' . $table_prefix . 'posts, ' . $table_prefix . 'posts_text, ' . $table_prefix . 'privmsgs, ' . $table_prefix . 'privmsgs_text, ' . $table_prefix . 'ranks, ' . $table_prefix . 'search_results, ' . $table_prefix . 'search_wordlist, ' . $table_prefix . 'search_wordmatch, ' . $table_prefix . 'sessions_keys' . $table_prefix . 'smilies, ' . $table_prefix . 'themes, ' . $table_prefix . 'themes_name, ' . $table_prefix . 'topics, ' . $table_prefix . 'topics_watch, ' . $table_prefix . 'user_group, ' . $table_prefix . 'users, ' . $table_prefix . 'vote_desc, ' . $table_prefix . 'vote_results, ' . $table_prefix . 'vote_voters, ' . $table_prefix . 'words';
 458          _sql($sql, $errored, $error_ary);
 459      break;
 460  
 461      case 'postgresql':
 462          _sql("VACUUM ANALYZE", $errored, $error_ary);
 463      break;
 464  }
 465  */
 466  
 467  _write_result($no_updates, $errored, $error_ary);
 468  
 469  ?>
 470  
 471  <br />
 472  <h1><?php echo $lang['UPDATE_COMPLETED']; ?></h1>
 473  
 474  <br />
 475  
 476  <?php
 477  
 478  if (!$inline_update)
 479  {
 480  ?>
 481  
 482      <p style="color:red"><?php echo $lang['UPDATE_FILES_NOTICE']; ?></p>
 483  
 484      <p><?php echo $lang['COMPLETE_LOGIN_TO_BOARD']; ?></p>
 485  
 486  <?php
 487  }
 488  else
 489  {
 490  ?>
 491  
 492      <p><?php echo ((isset($lang['INLINE_UPDATE_SUCCESSFUL'])) ? $lang['INLINE_UPDATE_SUCCESSFUL'] : 'The database update was successful. Now you need to continue the update process.'); ?></p>
 493  
 494      <p><a href="<?php echo append_sid("{$phpbb_root_path}install/index.{$phpEx}", "mode=update&amp;sub=file_check&amp;language=$language"); ?>" class="button1"><?php echo (isset($lang['CONTINUE_UPDATE_NOW'])) ? $lang['CONTINUE_UPDATE_NOW'] : 'Continue the update process now'; ?></a></p>
 495  
 496  <?php
 497  }
 498  
 499  // Add database update to log
 500  add_log('admin', 'LOG_UPDATE_DATABASE', $orig_version, $updates_to_version);
 501  
 502  // Now we purge the session table as well as all cache files
 503  $cache->purge();
 504  
 505  _print_footer();
 506  
 507  garbage_collection();
 508  
 509  if (function_exists('exit_handler'))
 510  {
 511      exit_handler();
 512  }
 513  
 514  /**
 515  * Print out footer
 516  */
 517  function _print_footer()
 518  {
 519      echo <<<EOF
 520                      </div>
 521                  </div>
 522              <span class="corners-bottom"><span></span></span>
 523          </div>
 524          </div>
 525      </div>
 526  
 527      <div id="page-footer">
 528          Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Group
 529      </div>
 530  </div>
 531  
 532  </body>
 533  </html>
 534  EOF;
 535  }
 536  
 537  /**
 538  * Function for triggering an sql statement
 539  */
 540  function _sql($sql, &$errored, &$error_ary, $echo_dot = true)
 541  {
 542      global $db;
 543  
 544      if (defined('DEBUG_EXTRA'))
 545      {
 546          echo "<br />\n{$sql}\n<br />";
 547      }
 548  
 549      $db->sql_return_on_error(true);
 550  
 551      if ($sql === 'begin')
 552      {
 553          $result = $db->sql_transaction('begin');
 554      }
 555      else if ($sql === 'commit')
 556      {
 557          $result = $db->sql_transaction('commit');
 558      }
 559      else
 560      {
 561          $result = $db->sql_query($sql);
 562          if ($db->sql_error_triggered)
 563          {
 564              $errored = true;
 565              $error_ary['sql'][] = $db->sql_error_sql;
 566              $error_ary['error_code'][] = $db->sql_error_returned;
 567          }
 568      }
 569  
 570      $db->sql_return_on_error(false);
 571  
 572      if ($echo_dot)
 573      {
 574          echo ". \n";
 575          flush();
 576      }
 577  
 578      return $result;
 579  }
 580  
 581  function _write_result($no_updates, $errored, $error_ary)
 582  {
 583      global $lang;
 584  
 585      if ($no_updates)
 586      {
 587          echo ' ' . $lang['NO_UPDATES_REQUIRED'] . '</strong></p>';
 588      }
 589      else
 590      {
 591          echo ' <span class="success">' . $lang['DONE'] . '</span></strong><br />' . $lang['RESULT'] . ' :: ';
 592  
 593          if ($errored)
 594          {
 595              echo ' <strong>' . $lang['SOME_QUERIES_FAILED'] . '</strong> <ul>';
 596  
 597              for ($i = 0; $i < sizeof($error_ary['sql']); $i++)
 598              {
 599                  echo '<li>' . $lang['ERROR'] . ' :: <strong>' . htmlspecialchars($error_ary['error_code'][$i]['message']) . '</strong><br />';
 600                  echo $lang['SQL'] . ' :: <strong>' . htmlspecialchars($error_ary['sql'][$i]) . '</strong><br /><br /></li>';
 601              }
 602  
 603              echo '</ul> <br /><br />' . $lang['SQL_FAILURE_EXPLAIN'] . '</p>';
 604          }
 605          else
 606          {
 607              echo '<strong>' . $lang['NO_ERRORS'] . '</strong></p>';
 608          }
 609      }
 610  }
 611  
 612  function _add_modules($modules_to_install)
 613  {
 614      global $phpbb_root_path, $phpEx, $db;
 615  
 616      include_once($phpbb_root_path . 'includes/acp/acp_modules.' . $phpEx);
 617  
 618      $_module = new acp_modules();
 619  
 620      foreach ($modules_to_install as $module_mode => $module_data)
 621      {
 622          $_module->module_class = $module_data['class'];
 623  
 624          // Determine parent id first
 625          $sql = 'SELECT module_id
 626              FROM ' . MODULES_TABLE . "
 627              WHERE module_class = '" . $db->sql_escape($module_data['class']) . "'
 628                  AND module_langname = '" . $db->sql_escape($module_data['cat']) . "'
 629                  AND module_mode = ''
 630                  AND module_basename = ''";
 631          $result = $db->sql_query($sql);
 632  
 633          // There may be more than one categories with the same name
 634          $categories = array();
 635          while ($row = $db->sql_fetchrow($result))
 636          {
 637              $categories[] = (int) $row['module_id'];
 638          }
 639          $db->sql_freeresult($result);
 640  
 641          if (!sizeof($categories))
 642          {
 643              continue;
 644          }
 645  
 646          // Add the module to all categories found
 647          foreach ($categories as $parent_id)
 648          {
 649              // Check if the module already exists
 650              $sql = 'SELECT *
 651                  FROM ' . MODULES_TABLE . "
 652                  WHERE module_basename = '" . $db->sql_escape($module_data['base']) . "'
 653                      AND module_class = '" . $db->sql_escape($module_data['class']) . "'
 654                      AND module_langname = '" . $db->sql_escape($module_data['title']) . "'
 655                      AND module_mode = '" . $db->sql_escape($module_mode) . "'
 656                      AND module_auth = '" . $db->sql_escape($module_data['auth']) . "'
 657                      AND parent_id = {$parent_id}";
 658              $result = $db->sql_query($sql);
 659              $row = $db->sql_fetchrow($result);
 660              $db->sql_freeresult($result);
 661  
 662              // If it exists, we simply continue with the next category
 663              if ($row)
 664              {
 665                  continue;
 666              }
 667  
 668              // Build the module sql row
 669              $module_row = array(
 670                  'module_basename'    => $module_data['base'],
 671                  'module_enabled'    => (isset($module_data['enabled'])) ? (int) $module_data['enabled'] : 1,
 672                  'module_display'    => (isset($module_data['display'])) ? (int) $module_data['display'] : 1,
 673                  'parent_id'            => $parent_id,
 674                  'module_class'        => $module_data['class'],
 675                  'module_langname'    => $module_data['title'],
 676                  'module_mode'        => $module_mode,
 677                  'module_auth'        => $module_data['auth'],
 678              );
 679  
 680              $_module->update_module_data($module_row, true);
 681  
 682              // Ok, do we need to re-order the module, move it up or down?
 683              if (!isset($module_data['after']))
 684              {
 685                  continue;
 686              }
 687  
 688              $after_mode = $module_data['after'][0];
 689              $after_langname = $module_data['after'][1];
 690  
 691              // First of all, get the module id for the module this one has to be placed after
 692              $sql = 'SELECT left_id
 693                  FROM ' . MODULES_TABLE . "
 694                  WHERE module_class = '" . $db->sql_escape($module_data['class']) . "'
 695                      AND module_basename = '" . $db->sql_escape($module_data['base']) . "'
 696                      AND module_langname = '" . $db->sql_escape($after_langname) . "'
 697                      AND module_mode = '" . $db->sql_escape($after_mode) . "'
 698                      AND parent_id = '{$parent_id}'";
 699              $result = $db->sql_query($sql);
 700              $first_left_id = (int) $db->sql_fetchfield('left_id');
 701              $db->sql_freeresult($result);
 702  
 703              if (!$first_left_id)
 704              {
 705                  continue;
 706              }
 707  
 708              // Ok, count the number of modules between $after_mode and the added module
 709              $sql = 'SELECT COUNT(module_id) as num_modules
 710                  FROM ' . MODULES_TABLE . "
 711                  WHERE module_class = '" . $db->sql_escape($module_data['class']) . "'
 712                      AND parent_id = {$parent_id}
 713                      AND left_id BETWEEN {$first_left_id} AND {$module_row['left_id']}";
 714              $result = $db->sql_query($sql);
 715              $steps = (int) $db->sql_fetchfield('num_modules');
 716              $db->sql_freeresult($result);
 717  
 718              // We need to substract 2
 719              $steps -= 2;
 720  
 721              if ($steps <= 0)
 722              {
 723                  continue;
 724              }
 725  
 726              // Ok, move module up $num_modules times. ;)
 727              $_module->move_module_by($module_row, 'move_up', $steps);
 728          }
 729      }
 730  
 731      $_module->remove_cache_file();
 732  }
 733  
 734  /****************************************************************************
 735  * ADD YOUR DATABASE SCHEMA CHANGES HERE                                        *
 736  *****************************************************************************/
 737  function database_update_info()
 738  {
 739      return array(
 740          // Changes from 3.0.0 to the next version
 741          '3.0.0'            => array(
 742              // Add the following columns
 743              'add_columns'        => array(
 744                  FORUMS_TABLE            => array(
 745                      'display_subforum_list'        => array('BOOL', 1),
 746                  ),
 747                  SESSIONS_TABLE            => array(
 748                      'session_forum_id'        => array('UINT', 0),
 749                  ),
 750              ),
 751              'drop_keys'        => array(
 752                  GROUPS_TABLE            => array('group_legend'),
 753              ),
 754              'add_index'        => array(
 755                  SESSIONS_TABLE            => array(
 756                      'session_forum_id'        => array('session_forum_id'),
 757                  ),
 758                  GROUPS_TABLE            => array(
 759                      'group_legend_name'        => array('group_legend', 'group_name'),
 760                  ),
 761              ),
 762          ),
 763          // No changes from 3.0.1-RC1 to 3.0.1
 764          '3.0.1-RC1'        => array(),
 765          // No changes from 3.0.1 to 3.0.2-RC1
 766          '3.0.1'            => array(),
 767          // Changes from 3.0.2-RC1 to 3.0.2-RC2
 768          '3.0.2-RC1'        => array(
 769              'change_columns'    => array(
 770                  DRAFTS_TABLE            => array(
 771                      'draft_subject'        => array('STEXT_UNI', ''),
 772                  ),
 773                  FORUMS_TABLE    => array(
 774                      'forum_last_post_subject' => array('STEXT_UNI', ''),
 775                  ),
 776                  POSTS_TABLE        => array(
 777                      'post_subject'            => array('STEXT_UNI', '', 'true_sort'),
 778                  ),
 779                  PRIVMSGS_TABLE    => array(
 780                      'message_subject'        => array('STEXT_UNI', ''),
 781                  ),
 782                  TOPICS_TABLE    => array(
 783                      'topic_title'                => array('STEXT_UNI', '', 'true_sort'),
 784                      'topic_last_post_subject'    => array('STEXT_UNI', ''),
 785                  ),
 786              ),
 787              'drop_keys'        => array(
 788                  SESSIONS_TABLE            => array('session_forum_id'),
 789              ),
 790              'add_index'        => array(
 791                  SESSIONS_TABLE            => array(
 792                      'session_fid'        => array('session_forum_id'),
 793                  ),
 794              ),
 795          ),
 796          // No changes from 3.0.2-RC2 to 3.0.2
 797          '3.0.2-RC2'        => array(),
 798  
 799          // Changes from 3.0.2 to 3.0.3-RC1
 800          '3.0.2'            => array(
 801              // Add the following columns
 802              'add_columns'        => array(
 803                  STYLES_TEMPLATE_TABLE            => array(
 804                      'template_inherits_id'        => array('UINT:4', 0),
 805                      'template_inherit_path'        => array('VCHAR', ''),
 806                  ),
 807                  GROUPS_TABLE                    => array(
 808                      'group_max_recipients'        => array('UINT', 0),
 809                  ),
 810              ),
 811          ),
 812  
 813          // No changes from 3.0.3-RC1 to 3.0.3
 814          '3.0.3-RC1'        => array(),
 815  
 816          // Changes from 3.0.3 to 3.0.4-RC1
 817          '3.0.3'            => array(
 818              'add_columns'        => array(
 819                  PROFILE_FIELDS_TABLE            => array(
 820                      'field_show_profile'        => array('BOOL', 0),
 821                  ),
 822              ),
 823              'change_columns'    => array(
 824                  STYLES_TABLE                => array(
 825                      'style_id'                => array('UINT', NULL, 'auto_increment'),
 826                      'template_id'            => array('UINT', 0),
 827                      'theme_id'                => array('UINT', 0),
 828                      'imageset_id'            => array('UINT', 0),
 829                  ),
 830                  STYLES_IMAGESET_TABLE        => array(
 831                      'imageset_id'                => array('UINT', NULL, 'auto_increment'),
 832                  ),
 833                  STYLES_IMAGESET_DATA_TABLE    => array(
 834                      'image_id'                => array('UINT', NULL, 'auto_increment'),
 835                      'imageset_id'            => array('UINT', 0),
 836                  ),
 837                  STYLES_THEME_TABLE            => array(
 838                      'theme_id'                => array('UINT', NULL, 'auto_increment'),
 839                  ),
 840                  STYLES_TEMPLATE_TABLE        => array(
 841                      'template_id'            => array('UINT', NULL, 'auto_increment'),
 842                  ),
 843                  STYLES_TEMPLATE_DATA_TABLE    => array(
 844                      'template_id'            => array('UINT', 0),
 845                  ),
 846                  FORUMS_TABLE                => array(
 847                      'forum_style'            => array('UINT', 0),
 848                  ),
 849                  USERS_TABLE                    => array(
 850                      'user_style'            => array('UINT', 0),
 851                  ),
 852              ),
 853          ),
 854  
 855          // Changes from 3.0.4-RC1 to 3.0.4
 856          '3.0.4-RC1'        => array(),
 857  
 858          // Changes from 3.0.4 to 3.0.5-RC1
 859          '3.0.4'            => array(
 860              'change_columns'    => array(
 861                  FORUMS_TABLE                => array(
 862                      'forum_style'            => array('UINT', 0),
 863                  ),
 864              ),
 865          ),
 866  
 867          // No changes from 3.0.5-RC1 to 3.0.5
 868          '3.0.5-RC1'        => array(),
 869  
 870          // Changes from 3.0.5 to 3.0.6-RC1
 871          '3.0.5'        => array(
 872              'add_columns'        => array(
 873                  CONFIRM_TABLE            => array(
 874                      'attempts'        => array('UINT', 0),
 875                  ),
 876                  USERS_TABLE            => array(
 877                      'user_new'            => array('BOOL', 1),
 878                      'user_reminded'        => array('TINT:4', 0),
 879                      'user_reminded_time'=> array('TIMESTAMP', 0),
 880                  ),
 881                  GROUPS_TABLE            => array(
 882                      'group_skip_auth'        => array('BOOL', 0, 'after' => 'group_founder_manage'),
 883                  ),
 884                  PRIVMSGS_TABLE        => array(
 885                      'message_reported'    => array('BOOL', 0),
 886                  ),
 887                  REPORTS_TABLE        => array(
 888                      'pm_id'                => array('UINT', 0),
 889                  ),
 890                  PROFILE_FIELDS_TABLE            => array(
 891                      'field_show_on_vt'        => array('BOOL', 0),
 892                  ),
 893                  FORUMS_TABLE        => array(
 894                      'forum_options'            => array('UINT:20', 0),
 895                  ),
 896              ),
 897              'change_columns'        => array(
 898                  USERS_TABLE                => array(
 899                      'user_options'        => array('UINT:11', 230271),
 900                  ),
 901              ),
 902              'add_index'        => array(
 903                  REPORTS_TABLE        => array(
 904                      'post_id'        => array('post_id'),
 905                      'pm_id'            => array('pm_id'),
 906                  ),
 907                  POSTS_TABLE            => array(
 908                      'post_username'        => array('post_username:255'),
 909                  ),
 910              ),
 911          ),
 912  
 913          // No changes from 3.0.6-RC1 to 3.0.6-RC2
 914          '3.0.6-RC1'        => array(),
 915          // No changes from 3.0.6-RC2 to 3.0.6-RC3
 916          '3.0.6-RC2'        => array(),
 917          // No changes from 3.0.6-RC3 to 3.0.6-RC4
 918          '3.0.6-RC3'        => array(),
 919          // No changes from 3.0.6-RC4 to 3.0.6
 920          '3.0.6-RC4'        => array(),
 921  
 922          // Changes from 3.0.6 to 3.0.7-RC1
 923          '3.0.6'        => array(
 924              'drop_keys'        => array(
 925                  LOG_TABLE            => array('log_time'),
 926              ),
 927              'add_index'        => array(
 928                  TOPICS_TRACK_TABLE    => array(
 929                      'topic_id'        => array('topic_id'),
 930                  ),
 931              ),
 932          ),
 933  
 934          // No changes from 3.0.7-RC1 to 3.0.7-RC2
 935          '3.0.7-RC1'        => array(),
 936          // No changes from 3.0.7-RC2 to 3.0.7
 937          '3.0.7-RC2'        => array(),
 938          // No changes from 3.0.7 to 3.0.7-PL1
 939          '3.0.7'        => array(),
 940          // No changes from 3.0.7-PL1 to 3.0.8-RC1
 941          '3.0.7-PL1'        => array(),
 942          // No changes from 3.0.8-RC1 to 3.0.8
 943          '3.0.8-RC1'        => array(),
 944          // Changes from 3.0.8 to 3.0.9-RC1
 945          '3.0.8'            => array(
 946              'add_tables'        => array(
 947                  LOGIN_ATTEMPT_TABLE    => array(
 948                      'COLUMNS'            => array(
 949                          // this column was removed from the database updater
 950                          // after 3.0.9-RC3 was released. It might still exist
 951                          // in 3.0.9-RCX installations and has to be dropped in
 952                          // 3.0.13 after the db_tools class is capable of properly
 953                          // removing a primary key.
 954                          // 'attempt_id'            => array('UINT', NULL, 'auto_increment'),
 955                          'attempt_ip'            => array('VCHAR:40', ''),
 956                          'attempt_browser'        => array('VCHAR:150', ''),
 957                          'attempt_forwarded_for'    => array('VCHAR:255', ''),
 958                          'attempt_time'            => array('TIMESTAMP', 0),
 959                          'user_id'                => array('UINT', 0),
 960                          'username'                => array('VCHAR_UNI:255', 0),
 961                          'username_clean'        => array('VCHAR_CI', 0),
 962                      ),
 963                      //'PRIMARY_KEY'        => 'attempt_id',
 964                      'KEYS'                => array(
 965                          'att_ip'            => array('INDEX', array('attempt_ip', 'attempt_time')),
 966                          'att_for'    => array('INDEX', array('attempt_forwarded_for', 'attempt_time')),
 967                          'att_time'            => array('INDEX', array('attempt_time')),
 968                          'user_id'                => array('INDEX', 'user_id'),
 969                      ),
 970                  ),
 971              ),
 972              'change_columns'    => array(
 973                  BBCODES_TABLE    => array(
 974                      'bbcode_id'    => array('USINT', 0),
 975                  ),
 976              ),
 977          ),
 978          // No changes from 3.0.9-RC1 to 3.0.9-RC2
 979          '3.0.9-RC1'        => array(),
 980          // No changes from 3.0.9-RC2 to 3.0.9-RC3
 981          '3.0.9-RC2'        => array(),
 982          // No changes from 3.0.9-RC3 to 3.0.9-RC4
 983          '3.0.9-RC3'     => array(),
 984          // No changes from 3.0.9-RC4 to 3.0.9
 985          '3.0.9-RC4'     => array(),
 986          // No changes from 3.0.9 to 3.0.10-RC1
 987          '3.0.9'            => array(),
 988          // No changes from 3.0.10-RC1 to 3.0.10-RC2
 989          '3.0.10-RC1'    => array(),
 990          // No changes from 3.0.10-RC2 to 3.0.10-RC3
 991          '3.0.10-RC2'    => array(),
 992          // No changes from 3.0.10-RC3 to 3.0.10
 993          '3.0.10-RC3'    => array(),
 994          // No changes from 3.0.10 to 3.0.11-RC1
 995          '3.0.10'        => array(),
 996          // Changes from 3.0.11-RC1 to 3.0.11-RC2
 997          '3.0.11-RC1'    => array(
 998              'add_columns'        => array(
 999                  PROFILE_FIELDS_TABLE            => array(
1000                      'field_show_novalue'        => array('BOOL', 0),
1001                  ),
1002              ),
1003          ),
1004          // No changes from 3.0.11-RC2 to 3.0.11
1005          '3.0.11-RC2'    => array(),
1006          // No changes from 3.0.11 to 3.0.12-RC1
1007          '3.0.11'        => array(),
1008          // No changes from 3.0.12-RC1 to 3.0.12-RC2
1009          '3.0.12-RC1'    => array(),
1010          // No changes from 3.0.12-RC2 to 3.0.12-RC3
1011          '3.0.12-RC2'    => array(),
1012          // No changes from 3.0.12-RC3 to 3.0.12
1013          '3.0.12-RC3'    => array(),
1014  
1015          /** @todo DROP LOGIN_ATTEMPT_TABLE.attempt_id in 3.0.13-RC1 */
1016      );
1017  }
1018  
1019  /****************************************************************************
1020  * ADD YOUR DATABASE DATA CHANGES HERE                                        *
1021  * REMEMBER: You NEED to enter a schema array above and a data array here,    *
1022  * even if both or one of them are empty.                                    *
1023  *****************************************************************************/
1024  function change_database_data(&$no_updates, $version)
1025  {
1026      global $db, $db_tools, $errored, $error_ary, $config, $table_prefix, $phpbb_root_path, $phpEx;
1027  
1028      switch ($version)
1029      {
1030          case '3.0.0':
1031  
1032              $sql = 'UPDATE ' . TOPICS_TABLE . "
1033                  SET topic_last_view_time = topic_last_post_time
1034                  WHERE topic_last_view_time = 0";
1035              _sql($sql, $errored, $error_ary);
1036  
1037              // Update smiley sizes
1038              $smileys = array('icon_e_surprised.gif', 'icon_eek.gif', 'icon_cool.gif', 'icon_lol.gif', 'icon_mad.gif', 'icon_razz.gif', 'icon_redface.gif', 'icon_cry.gif', 'icon_evil.gif', 'icon_twisted.gif', 'icon_rolleyes.gif', 'icon_exclaim.gif', 'icon_question.gif', 'icon_idea.gif', 'icon_arrow.gif', 'icon_neutral.gif', 'icon_mrgreen.gif', 'icon_e_ugeek.gif');
1039  
1040              foreach ($smileys as $smiley)
1041              {
1042                  if (file_exists($phpbb_root_path . 'images/smilies/' . $smiley))
1043                  {
1044                      list($width, $height) = getimagesize($phpbb_root_path . 'images/smilies/' . $smiley);
1045  
1046                      $sql = 'UPDATE ' . SMILIES_TABLE . '
1047                          SET smiley_width = ' . $width . ', smiley_height = ' . $height . "
1048                          WHERE smiley_url = '" . $db->sql_escape($smiley) . "'";
1049  
1050                      _sql($sql, $errored, $error_ary);
1051                  }
1052              }
1053  
1054              $no_updates = false;
1055          break;
1056  
1057          // No changes from 3.0.1-RC1 to 3.0.1
1058          case '3.0.1-RC1':
1059          break;
1060  
1061          // changes from 3.0.1 to 3.0.2-RC1
1062          case '3.0.1':
1063  
1064              set_config('referer_validation', '1');
1065              set_config('check_attachment_content', '1');
1066              set_config('mime_triggers', 'body|head|html|img|plaintext|a href|pre|script|table|title');
1067  
1068              $no_updates = false;
1069          break;
1070  
1071          // No changes from 3.0.2-RC1 to 3.0.2-RC2
1072          case '3.0.2-RC1':
1073          break;
1074  
1075          // No changes from 3.0.2-RC2 to 3.0.2
1076          case '3.0.2-RC2':
1077          break;
1078  
1079          // Changes from 3.0.2 to 3.0.3-RC1
1080          case '3.0.2':
1081              set_config('enable_queue_trigger', '0');
1082              set_config('queue_trigger_posts', '3');
1083  
1084              set_config('pm_max_recipients', '0');
1085  
1086              // Set maximum number of recipients for the registered users, bots, guests group
1087              $sql = 'UPDATE ' . GROUPS_TABLE . ' SET group_max_recipients = 5
1088                  WHERE ' . $db->sql_in_set('group_name', array('GUESTS', 'REGISTERED', 'REGISTERED_COPPA', 'BOTS'));
1089              _sql($sql, $errored, $error_ary);
1090  
1091              // Not prefilling yet
1092              set_config('dbms_version', '');
1093  
1094              // Add new permission u_masspm_group and duplicate settings from u_masspm
1095              include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx);
1096              $auth_admin = new auth_admin();
1097  
1098              // Only add the new permission if it does not already exist
1099              if (empty($auth_admin->acl_options['id']['u_masspm_group']))
1100              {
1101                  $auth_admin->acl_add_option(array('global' => array('u_masspm_group')));
1102  
1103                  // Now the tricky part, filling the permission
1104                  $old_id = $auth_admin->acl_options['id']['u_masspm'];
1105                  $new_id = $auth_admin->acl_options['id']['u_masspm_group'];
1106  
1107                  $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE);
1108  
1109                  foreach ($tables as $table)
1110                  {
1111                      $sql = 'SELECT *
1112                          FROM ' . $table . '
1113                          WHERE auth_option_id = ' . $old_id;
1114                      $result = _sql($sql, $errored, $error_ary);
1115  
1116                      $sql_ary = array();
1117                      while ($row = $db->sql_fetchrow($result))
1118                      {
1119                          $row['auth_option_id'] = $new_id;
1120                          $sql_ary[] = $row;
1121                      }
1122                      $db->sql_freeresult($result);
1123  
1124                      if (sizeof($sql_ary))
1125                      {
1126                          $db->sql_multi_insert($table, $sql_ary);
1127                      }
1128                  }
1129  
1130                  // Remove any old permission entries
1131                  $auth_admin->acl_clear_prefetch();
1132              }
1133  
1134              /**
1135              * Do not resync post counts here. An admin may do this later from the ACP
1136              $start = 0;
1137              $step = ($config['num_posts']) ? (max((int) ($config['num_posts'] / 5), 20000)) : 20000;
1138  
1139              $sql = 'UPDATE ' . USERS_TABLE . ' SET user_posts = 0';
1140              _sql($sql, $errored, $error_ary);
1141  
1142              do
1143              {
1144                  $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
1145                      FROM ' . POSTS_TABLE . '
1146                      WHERE post_id BETWEEN ' . ($start + 1) . ' AND ' . ($start + $step) . '
1147                          AND post_postcount = 1 AND post_approved = 1
1148                      GROUP BY poster_id';
1149                  $result = _sql($sql, $errored, $error_ary);
1150  
1151                  if ($row = $db->sql_fetchrow($result))
1152                  {
1153                      do
1154                      {
1155                          $sql = 'UPDATE ' . USERS_TABLE . " SET user_posts = user_posts + {$row['num_posts']} WHERE user_id = {$row['poster_id']}";
1156                          _sql($sql, $errored, $error_ary);
1157                      }
1158                      while ($row = $db->sql_fetchrow($result));
1159  
1160                      $start += $step;
1161                  }
1162                  else
1163                  {
1164                      $start = 0;
1165                  }
1166                  $db->sql_freeresult($result);
1167              }
1168              while ($start);
1169              */
1170  
1171              $sql = 'UPDATE ' . MODULES_TABLE . '
1172                  SET module_auth = \'acl_a_email && cfg_email_enable\'
1173                  WHERE module_class = \'acp\'
1174                      AND module_basename = \'email\'';
1175              _sql($sql, $errored, $error_ary);
1176  
1177              $no_updates = false;
1178          break;
1179  
1180          // Changes from 3.0.3-RC1 to 3.0.3
1181          case '3.0.3-RC1':
1182              if ($db->sql_layer == 'oracle')
1183              {
1184                  // log_operation is CLOB - but we can change this later
1185                  $sql = 'UPDATE ' . LOG_TABLE . "
1186                      SET log_operation = 'LOG_DELETE_TOPIC'
1187                      WHERE log_operation LIKE 'LOG_TOPIC_DELETED'";
1188                  _sql($sql, $errored, $error_ary);
1189              }
1190              else
1191              {
1192                  $sql = 'UPDATE ' . LOG_TABLE . "
1193                      SET log_operation = 'LOG_DELETE_TOPIC'
1194                      WHERE log_operation = 'LOG_TOPIC_DELETED'";
1195                  _sql($sql, $errored, $error_ary);
1196              }
1197  
1198              $no_updates = false;
1199          break;
1200  
1201          // Changes from 3.0.3 to 3.0.4-RC1
1202          case '3.0.3':
1203              // Update the Custom Profile Fields based on previous settings to the new format
1204              $sql = 'SELECT field_id, field_required, field_show_on_reg, field_hide
1205                      FROM ' . PROFILE_FIELDS_TABLE;
1206              $result = _sql($sql, $errored, $error_ary);
1207  
1208              while ($row = $db->sql_fetchrow($result))
1209              {
1210                  $sql_ary = array(
1211                      'field_required'    => 0,
1212                      'field_show_on_reg'    => 0,
1213                      'field_hide'        => 0,
1214                      'field_show_profile'=> 0,
1215                  );
1216  
1217                  if ($row['field_required'])
1218                  {
1219                      $sql_ary['field_required'] = $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1;
1220                  }
1221                  else if ($row['field_show_on_reg'])
1222                  {
1223                      $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1;
1224                  }
1225                  else if ($row['field_hide'])
1226                  {
1227                      // Only administrators and moderators can see this CPF, if the view is enabled, they can see it, otherwise just admins in the acp_users module
1228                      $sql_ary['field_hide'] = 1;
1229                  }
1230                  else
1231                  {
1232                      // equivelant to "none", which is the "Display in user control panel" option
1233                      $sql_ary['field_show_profile'] = 1;
1234                  }
1235  
1236                  _sql('UPDATE ' . PROFILE_FIELDS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE field_id = ' . $row['field_id'], $errored, $error_ary);
1237              }
1238              $no_updates = false;
1239  
1240          break;
1241  
1242          // Changes from 3.0.4-RC1 to 3.0.4
1243          case '3.0.4-RC1':
1244          break;
1245  
1246          // Changes from 3.0.4 to 3.0.5-RC1
1247          case '3.0.4':
1248  
1249              // Captcha config variables
1250              set_config('captcha_gd_wave', 0);
1251              set_config('captcha_gd_3d_noise', 1);
1252              set_config('captcha_gd_fonts', 1);
1253              set_config('confirm_refresh', 1);
1254  
1255              // Maximum number of keywords
1256              set_config('max_num_search_keywords', 10);
1257  
1258              // Remove static config var and put it back as dynamic variable
1259              $sql = 'UPDATE ' . CONFIG_TABLE . "
1260                  SET is_dynamic = 1
1261                  WHERE config_name = 'search_indexing_state'";
1262              _sql($sql, $errored, $error_ary);
1263  
1264              // Hash old MD5 passwords
1265              $sql = 'SELECT user_id, user_password
1266                      FROM ' . USERS_TABLE . '
1267                      WHERE user_pass_convert = 1';
1268              $result = _sql($sql, $errored, $error_ary);
1269  
1270              while ($row = $db->sql_fetchrow($result))
1271              {
1272                  if (strlen($row['user_password']) == 32)
1273                  {
1274                      $sql_ary = array(
1275                          'user_password'    => phpbb_hash($row['user_password']),
1276                      );
1277  
1278                      _sql('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $row['user_id'], $errored, $error_ary);
1279                  }
1280              }
1281              $db->sql_freeresult($result);
1282  
1283              // Adjust bot entry
1284              $sql = 'UPDATE ' . BOTS_TABLE . "
1285                  SET bot_agent = 'ichiro/'
1286                  WHERE bot_agent = 'ichiro/2'";
1287              _sql($sql, $errored, $error_ary);
1288  
1289  
1290              // Before we are able to add a unique key to auth_option, we need to remove duplicate entries
1291  
1292              // We get duplicate entries first
1293              $sql = 'SELECT auth_option
1294                  FROM ' . ACL_OPTIONS_TABLE . '
1295                  GROUP BY auth_option
1296                  HAVING COUNT(*) >= 2';
1297              $result = $db->sql_query($sql);
1298  
1299              $auth_options = array();
1300              while ($row = $db->sql_fetchrow($result))
1301              {
1302                  $auth_options[] = $row['auth_option'];
1303              }
1304              $db->sql_freeresult($result);
1305  
1306              // Remove specific auth options
1307              if (!empty($auth_options))
1308              {
1309                  foreach ($auth_options as $option)
1310                  {
1311                      // Select auth_option_ids... the largest id will be preserved
1312                      $sql = 'SELECT auth_option_id
1313                          FROM ' . ACL_OPTIONS_TABLE . "
1314                          WHERE auth_option = '" . $db->sql_escape($option) . "'
1315                          ORDER BY auth_option_id DESC";
1316                      // sql_query_limit not possible here, due to bug in postgresql layer
1317                      $result = $db->sql_query($sql);
1318  
1319                      // Skip first row, this is our original auth option we want to preserve
1320                      $row = $db->sql_fetchrow($result);
1321  
1322                      while ($row = $db->sql_fetchrow($result))
1323                      {
1324                          // Ok, remove this auth option...
1325                          _sql('DELETE FROM ' . ACL_OPTIONS_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id'], $errored, $error_ary);
1326                          _sql('DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id'], $errored, $error_ary);
1327                          _sql('DELETE FROM ' . ACL_GROUPS_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id'], $errored, $error_ary);
1328                          _sql('DELETE FROM ' . ACL_USERS_TABLE . ' WHERE auth_option_id = ' . $row['auth_option_id'], $errored, $error_ary);
1329                      }
1330                      $db->sql_freeresult($result);
1331                  }
1332              }
1333  
1334              // Now make auth_option UNIQUE, by dropping the old index and adding a UNIQUE one.
1335              $changes = array(
1336                  'drop_keys'            => array(
1337                      ACL_OPTIONS_TABLE        => array('auth_option'),
1338                  ),
1339              );
1340  
1341              $statements = $db_tools->perform_schema_changes($changes);
1342  
1343              foreach ($statements as $sql)
1344              {
1345                  _sql($sql, $errored, $error_ary);
1346              }
1347  
1348              $changes = array(
1349                  'add_unique_index'    => array(
1350                      ACL_OPTIONS_TABLE        => array(
1351                          'auth_option'        => array('auth_option'),
1352                      ),
1353                  ),
1354              );
1355  
1356              $statements = $db_tools->perform_schema_changes($changes);
1357  
1358              foreach ($statements as $sql)
1359              {
1360                  _sql($sql, $errored, $error_ary);
1361              }
1362  
1363              $no_updates = false;
1364  
1365          break;
1366  
1367          // No changes from 3.0.5-RC1 to 3.0.5
1368          case '3.0.5-RC1':
1369          break;
1370  
1371          // Changes from 3.0.5 to 3.0.6-RC1
1372          case '3.0.5':
1373              // Let's see if the GD Captcha can be enabled... we simply look for what *is* enabled...
1374              if (!empty($config['captcha_gd']) && !isset($config['captcha_plugin']))
1375              {
1376                  set_config('captcha_plugin', 'phpbb_captcha_gd');
1377              }
1378              else if (!isset($config['captcha_plugin']))
1379              {
1380                  set_config('captcha_plugin', 'phpbb_captcha_nogd');
1381              }
1382  
1383              // Entries for the Feed Feature
1384              set_config('feed_enable', '0');
1385              set_config('feed_limit', '10');
1386  
1387              set_config('feed_overall_forums', '1');
1388              set_config('feed_overall_forums_limit', '15');
1389  
1390              set_config('feed_overall_topics', '0');
1391              set_config('feed_overall_topics_limit', '15');
1392  
1393              set_config('feed_forum', '1');
1394              set_config('feed_topic', '1');
1395              set_config('feed_item_statistics', '1');
1396  
1397              // Entries for smiley pagination
1398              set_config('smilies_per_page', '50');
1399  
1400              // Entry for reporting PMs
1401              set_config('allow_pm_report', '1');
1402  
1403              // Install modules
1404              $modules_to_install = array(
1405                  'feed'                    => array(
1406                      'base'        => 'board',
1407                      'class'        => 'acp',
1408                      'title'        => 'ACP_FEED_SETTINGS',
1409                      'auth'        => 'acl_a_board',
1410                      'cat'        => 'ACP_BOARD_CONFIGURATION',
1411                      'after'        => array('signature', 'ACP_SIGNATURE_SETTINGS')
1412                  ),
1413                  'warnings'                => array(
1414                      'base'        => 'users',
1415                      'class'        => 'acp',
1416                      'title'        => 'ACP_USER_WARNINGS',
1417                      'auth'        => 'acl_a_user',
1418                      'display'    => 0,
1419                      'cat'        => 'ACP_CAT_USERS',
1420                      'after'        => array('feedback', 'ACP_USER_FEEDBACK')
1421                  ),
1422                  'send_statistics'        => array(
1423                      'base'        => 'send_statistics',
1424                      'class'        => 'acp',
1425                      'title'        => 'ACP_SEND_STATISTICS',
1426                      'auth'        => 'acl_a_server',
1427                      'cat'        => 'ACP_SERVER_CONFIGURATION'
1428                  ),
1429                  'setting_forum_copy'    => array(
1430                      'base'        => 'permissions',
1431                      'class'        => 'acp',
1432                      'title'        => 'ACP_FORUM_PERMISSIONS_COPY',
1433                      'auth'        => 'acl_a_fauth && acl_a_authusers && acl_a_authgroups && acl_a_mauth',
1434                      'cat'        => 'ACP_FORUM_BASED_PERMISSIONS',
1435                      'after'        => array('setting_forum_local', 'ACP_FORUM_PERMISSIONS')
1436                  ),
1437                  'pm_reports'            => array(
1438                      'base'        => 'pm_reports',
1439                      'class'        => 'mcp',
1440                      'title'        => 'MCP_PM_REPORTS_OPEN',
1441                      'auth'        => 'aclf_m_report',
1442                      'cat'        => 'MCP_REPORTS'
1443                  ),
1444                  'pm_reports_closed'        => array(
1445                      'base'        => 'pm_reports',
1446                      'class'        => 'mcp',
1447                      'title'        => 'MCP_PM_REPORTS_CLOSED',
1448                      'auth'        => 'aclf_m_report',
1449                      'cat'        => 'MCP_REPORTS'
1450                  ),
1451                  'pm_report_details'        => array(
1452                      'base'        => 'pm_reports',
1453                      'class'        => 'mcp',
1454                      'title'        => 'MCP_PM_REPORT_DETAILS',
1455                      'auth'        => 'aclf_m_report',
1456                      'cat'        => 'MCP_REPORTS'
1457                  ),
1458              );
1459  
1460              _add_modules($modules_to_install);
1461  
1462              // Add newly_registered group... but check if it already exists (we always supported running the updater on any schema)
1463              $sql = 'SELECT group_id
1464                  FROM ' . GROUPS_TABLE . "
1465                  WHERE group_name = 'NEWLY_REGISTERED'";
1466              $result = $db->sql_query($sql);
1467              $group_id = (int) $db->sql_fetchfield('group_id');
1468              $db->sql_freeresult($result);
1469  
1470              if (!$group_id)
1471              {
1472                  $sql = 'INSERT INTO ' .  GROUPS_TABLE . " (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, '', '', '', 5)";
1473                  _sql($sql, $errored, $error_ary);
1474  
1475                  $group_id = $db->sql_nextid();
1476              }
1477  
1478              // Insert new user role... at the end of the chain
1479              $sql = 'SELECT role_id
1480                  FROM ' . ACL_ROLES_TABLE . "
1481                  WHERE role_name = 'ROLE_USER_NEW_MEMBER'
1482                      AND role_type = 'u_'";
1483              $result = $db->sql_query($sql);
1484              $u_role = (int) $db->sql_fetchfield('role_id');
1485              $db->sql_freeresult($result);
1486  
1487              if (!$u_role)
1488              {
1489                  $sql = 'SELECT MAX(role_order) as max_order_id
1490                      FROM ' . ACL_ROLES_TABLE . "
1491                      WHERE role_type = 'u_'";
1492                  $result = $db->sql_query($sql);
1493                  $next_order_id = (int) $db->sql_fetchfield('max_order_id');
1494                  $db->sql_freeresult($result);
1495  
1496                  $next_order_id++;
1497  
1498                  $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES ('ROLE_USER_NEW_MEMBER', 'ROLE_DESCRIPTION_USER_NEW_MEMBER', 'u_', $next_order_id)";
1499                  _sql($sql, $errored, $error_ary);
1500                  $u_role = $db->sql_nextid();
1501  
1502                  if (!$errored)
1503                  {
1504                      // Now add the correct data to the roles...
1505                      // The standard role says that new users are not able to send a PM, Mass PM, are not able to PM groups
1506                      $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $u_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group')";
1507                      _sql($sql, $errored, $error_ary);
1508  
1509                      // Add user role to group
1510                      $sql = 'INSERT INTO ' . ACL_GROUPS_TABLE . " (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES ($group_id, 0, 0, $u_role, 0)";
1511                      _sql($sql, $errored, $error_ary);
1512                  }
1513              }
1514  
1515              // Insert new forum role
1516              $sql = 'SELECT role_id
1517                  FROM ' . ACL_ROLES_TABLE . "
1518                  WHERE role_name = 'ROLE_FORUM_NEW_MEMBER'
1519                      AND role_type = 'f_'";
1520              $result = $db->sql_query($sql);
1521              $f_role = (int) $db->sql_fetchfield('role_id');
1522              $db->sql_freeresult($result);
1523  
1524              if (!$f_role)
1525              {
1526                  $sql = 'SELECT MAX(role_order) as max_order_id
1527                      FROM ' . ACL_ROLES_TABLE . "
1528                      WHERE role_type = 'f_'";
1529                  $result = $db->sql_query($sql);
1530                  $next_order_id = (int) $db->sql_fetchfield('max_order_id');
1531                  $db->sql_freeresult($result);
1532  
1533                  $next_order_id++;
1534  
1535                  $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES  ('ROLE_FORUM_NEW_MEMBER', 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER', 'f_', $next_order_id)";
1536                  _sql($sql, $errored, $error_ary);
1537                  $f_role = $db->sql_nextid();
1538  
1539                  if (!$errored)
1540                  {
1541                      $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $f_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_noapprove')";
1542                      _sql($sql, $errored, $error_ary);
1543                  }
1544              }
1545  
1546              // Set every members user_new column to 0 (old users) only if there is no one yet (this makes sure we do not execute this more than once)
1547              $sql = 'SELECT 1
1548                  FROM ' . USERS_TABLE . '
1549                  WHERE user_new = 0';
1550              $result = $db->sql_query_limit($sql, 1);
1551              $row = $db->sql_fetchrow($result);
1552              $db->sql_freeresult($result);
1553  
1554              if (!$row)
1555              {
1556                  $sql = 'UPDATE ' . USERS_TABLE . ' SET user_new = 0';
1557                  _sql($sql, $errored, $error_ary);
1558              }
1559  
1560              // Newly registered users limit
1561              if (!isset($config['new_member_post_limit']))
1562              {
1563                  set_config('new_member_post_limit', (!empty($config['enable_queue_trigger'])) ? $config['queue_trigger_posts'] : 0);
1564              }
1565  
1566              if (!isset($config['new_member_group_default']))
1567              {
1568                  set_config('new_member_group_default', 0);
1569              }
1570  
1571              // To mimick the old "feature" we will assign the forum role to every forum, regardless of the setting (this makes sure there are no "this does not work!!!! YUO!!!" posts...
1572              // Check if the role is already assigned...
1573              $sql = 'SELECT forum_id
1574                  FROM ' . ACL_GROUPS_TABLE . '
1575                  WHERE group_id = ' . $group_id . '
1576                      AND auth_role_id = ' . $f_role;
1577              $result = $db->sql_query($sql);
1578              $is_options = (int) $db->sql_fetchfield('forum_id');
1579              $db->sql_freeresult($result);
1580  
1581              // Not assigned at all... :/
1582              if (!$is_options)
1583              {
1584                  // Get postable forums
1585                  $sql = 'SELECT forum_id
1586                      FROM ' . FORUMS_TABLE . '
1587                      WHERE forum_type != ' . FORUM_LINK;
1588                  $result = $db->sql_query($sql);
1589  
1590                  while ($row = $db->sql_fetchrow($result))
1591                  {
1592                      _sql('INSERT INTO ' . ACL_GROUPS_TABLE . ' (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES (' . $group_id . ', ' . (int) $row['forum_id'] . ', 0, ' . $f_role . ', 0)', $errored, $error_ary);
1593                  }
1594                  $db->sql_freeresult($result);
1595              }
1596  
1597              // Clear permissions...
1598              include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx);
1599              $auth_admin = new auth_admin();
1600              $auth_admin->acl_clear_prefetch();
1601  
1602              if (!isset($config['allow_avatar']))
1603              {
1604                  if ($config['allow_avatar_upload'] || $config['allow_avatar_local'] || $config['allow_avatar_remote'])
1605                  {
1606                      set_config('allow_avatar', '1');
1607                  }
1608                  else
1609                  {
1610                      set_config('allow_avatar', '0');
1611                  }
1612              }
1613  
1614              if (!isset($config['allow_avatar_remote_upload']))
1615              {
1616                  if ($config['allow_avatar_remote'] && $config['allow_avatar_upload'])
1617                  {
1618                      set_config('allow_avatar_remote_upload', '1');
1619                  }
1620                  else
1621                  {
1622                      set_config('allow_avatar_remote_upload', '0');
1623                  }
1624              }
1625  
1626              // Minimum number of characters
1627              if (!isset($config['min_post_chars']))
1628              {
1629                  set_config('min_post_chars', '1');
1630              }
1631  
1632              if (!isset($config['allow_quick_reply']))
1633              {
1634                  set_config('allow_quick_reply', '1');
1635              }
1636  
1637              // Set every members user_options column to enable
1638              // bbcode, smilies and URLs for signatures by default
1639              $sql = 'SELECT user_options
1640                  FROM ' . USERS_TABLE . '
1641                  WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
1642              $result = $db->sql_query_limit($sql, 1);
1643              $user_option = (int) $db->sql_fetchfield('user_options');
1644              $db->sql_freeresult($result);
1645  
1646              // Check if we already updated the database by checking bit 15 which we used to store the sig_bbcode option
1647              if (!($user_option & 1 << 15))
1648              {
1649                  // 229376 is the added value to enable all three signature options
1650                  $sql = 'UPDATE ' . USERS_TABLE . ' SET user_options = user_options + 229376';
1651                  _sql($sql, $errored, $error_ary);
1652              }
1653  
1654              if (!isset($config['delete_time']))
1655              {
1656                  set_config('delete_time', $config['edit_time']);
1657              }
1658  
1659              $no_updates = false;
1660          break;
1661  
1662          // No changes from 3.0.6-RC1 to 3.0.6-RC2
1663          case '3.0.6-RC1':
1664          break;
1665  
1666          // Changes from 3.0.6-RC2 to 3.0.6-RC3
1667          case '3.0.6-RC2':
1668  
1669              // Update the Custom Profile Fields based on previous settings to the new format
1670              $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . '
1671                  SET field_show_on_vt = 1
1672                  WHERE field_hide = 0
1673                      AND (field_required = 1 OR field_show_on_reg = 1 OR field_show_profile = 1)';
1674              _sql($sql, $errored, $error_ary);
1675              $no_updates = false;
1676  
1677          break;
1678  
1679          // No changes from 3.0.6-RC3 to 3.0.6-RC4
1680          case '3.0.6-RC3':
1681          break;
1682  
1683          // No changes from 3.0.6-RC4 to 3.0.6
1684          case '3.0.6-RC4':
1685          break;
1686  
1687          // Changes from 3.0.6 to 3.0.7-RC1
1688          case '3.0.6':
1689  
1690              // ATOM Feeds
1691              set_config('feed_overall', '1');
1692              set_config('feed_http_auth', '0');
1693              set_config('feed_limit_post', (string) (isset($config['feed_limit']) ? (int) $config['feed_limit'] : 15));
1694              set_config('feed_limit_topic', (string) (isset($config['feed_overall_topics_limit']) ? (int) $config['feed_overall_topics_limit'] : 10));
1695              set_config('feed_topics_new', (!empty($config['feed_overall_topics']) ? '1' : '0'));
1696              set_config('feed_topics_active', (!empty($config['feed_overall_topics']) ? '1' : '0'));
1697  
1698              // Delete all text-templates from the template_data
1699              $sql = 'DELETE FROM ' . STYLES_TEMPLATE_DATA_TABLE . '
1700                  WHERE template_filename ' . $db->sql_like_expression($db->any_char . '.txt');
1701              _sql($sql, $errored, $error_ary);
1702  
1703              $no_updates = false;
1704          break;
1705  
1706          // Changes from 3.0.7-RC1 to 3.0.7-RC2
1707          case '3.0.7-RC1':
1708  
1709              $sql = 'SELECT user_id, user_email, user_email_hash
1710                  FROM ' . USERS_TABLE . '
1711                  WHERE user_type <> ' . USER_IGNORE . "
1712                      AND user_email <> ''";
1713              $result = $db->sql_query($sql);
1714  
1715              $i = 0;
1716              while ($row = $db->sql_fetchrow($result))
1717              {
1718                  // Snapshot of the phpbb_email_hash() function
1719                  // We cannot call it directly because the auto updater updates the DB first. :/
1720                  $user_email_hash = sprintf('%u', crc32(strtolower($row['user_email']))) . strlen($row['user_email']);
1721  
1722                  if ($user_email_hash != $row['user_email_hash'])
1723                  {
1724                      $sql_ary = array(
1725                          'user_email_hash'    => $user_email_hash,
1726                      );
1727  
1728                      $sql = 'UPDATE ' . USERS_TABLE . '
1729                          SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1730                          WHERE user_id = ' . (int) $row['user_id'];
1731                      _sql($sql, $errored, $error_ary, ($i % 100 == 0));
1732  
1733                      ++$i;
1734                  }
1735              }
1736              $db->sql_freeresult($result);
1737  
1738              $no_updates = false;
1739  
1740          break;
1741  
1742          // No changes from 3.0.7-RC2 to 3.0.7
1743          case '3.0.7-RC2':
1744          break;
1745  
1746          // No changes from 3.0.7 to 3.0.7-PL1
1747          case '3.0.7':
1748          break;
1749  
1750          // Changes from 3.0.7-PL1 to 3.0.8-RC1
1751          case '3.0.7-PL1':
1752              // Update file extension group names to use language strings.
1753              $sql = 'SELECT lang_dir
1754                  FROM ' . LANG_TABLE;
1755              $result = $db->sql_query($sql);
1756  
1757              $extension_groups_updated = array();
1758              while ($lang_dir = $db->sql_fetchfield('lang_dir'))
1759              {
1760                  $lang_dir = basename($lang_dir);
1761  
1762                  // The language strings we need are either in language/.../acp/attachments.php
1763                  // in the update package if we're updating to 3.0.8-RC1 or later,
1764                  // or they are in language/.../install.php when we're updating from 3.0.7-PL1 or earlier.
1765                  // On an already updated board, they can also already be in language/.../acp/attachments.php
1766                  // in the board root.
1767                  $lang_files = array(
1768                      "{$phpbb_root_path}install/update/new/language/$lang_dir/acp/attachments.$phpEx",
1769                      "{$phpbb_root_path}language/$lang_dir/install.$phpEx",
1770                      "{$phpbb_root_path}language/$lang_dir/acp/attachments.$phpEx",
1771                  );
1772  
1773                  foreach ($lang_files as $lang_file)
1774                  {
1775                      if (!file_exists($lang_file))
1776                      {
1777                          continue;
1778                      }
1779  
1780                      $lang = array();
1781                      include($lang_file);
1782  
1783                      foreach($lang as $lang_key => $lang_val)
1784                      {
1785                          if (isset($extension_groups_updated[$lang_key]) || strpos($lang_key, 'EXT_GROUP_') !== 0)
1786                          {
1787                              continue;
1788                          }
1789  
1790                          $sql_ary = array(
1791                              'group_name'    => substr($lang_key, 10), // Strip off 'EXT_GROUP_'
1792                          );
1793  
1794                          $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . '
1795                              SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
1796                              WHERE group_name = '" . $db->sql_escape($lang_val) . "'";
1797                          _sql($sql, $errored, $error_ary);
1798  
1799                          $extension_groups_updated[$lang_key] = true;
1800                      }
1801                  }
1802              }
1803              $db->sql_freeresult($result);
1804  
1805              // Install modules
1806              $modules_to_install = array(
1807                  'post'                    => array(
1808                      'base'        => 'board',
1809                      'class'        => 'acp',
1810                      'title'        => 'ACP_POST_SETTINGS',
1811                      'auth'        => 'acl_a_board',
1812                      'cat'        => 'ACP_MESSAGES',
1813                      'after'        => array('message', 'ACP_MESSAGE_SETTINGS')
1814                  ),
1815              );
1816  
1817              _add_modules($modules_to_install);
1818  
1819              // update
1820              $sql = 'UPDATE ' . MODULES_TABLE . '
1821                  SET module_auth = \'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)\'
1822                  WHERE module_class = \'ucp\'
1823                      AND module_basename = \'profile\'
1824                      AND module_mode = \'avatar\'';
1825              _sql($sql, $errored, $error_ary);
1826  
1827              // add Bing Bot
1828              $bot_name = 'Bing [Bot]';
1829              $bot_name_clean = utf8_clean_string($bot_name);
1830  
1831              $sql = 'SELECT user_id
1832                  FROM ' . USERS_TABLE . "
1833                  WHERE username_clean = '" . $db->sql_escape($bot_name_clean) . "'";
1834              $result = $db->sql_query($sql);
1835              $bing_already_added = (bool) $db->sql_fetchfield('user_id');
1836              $db->sql_freeresult($result);
1837  
1838              if (!$bing_already_added)
1839              {
1840                  $bot_agent = 'bingbot/';
1841                  $bot_ip = '';
1842                  $sql = 'SELECT group_id, group_colour
1843                      FROM ' . GROUPS_TABLE . "
1844                      WHERE group_name = 'BOTS'";
1845                  $result = $db->sql_query($sql);
1846                  $group_row = $db->sql_fetchrow($result);
1847                  $db->sql_freeresult($result);
1848  
1849                  if (!$group_row)
1850                  {
1851                      // default fallback, should never get here
1852                      $group_row['group_id'] = 6;
1853                      $group_row['group_colour'] = '9E8DA7';
1854                  }
1855  
1856                  if (!function_exists('user_add'))
1857                  {
1858                      include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
1859                  }
1860  
1861                  $user_row = array(
1862                      'user_type'                => USER_IGNORE,
1863                      'group_id'                => $group_row['group_id'],
1864                      'username'                => $bot_name,
1865                      'user_regdate'            => time(),
1866                      'user_password'            => '',
1867                      'user_colour'            => $group_row['group_colour'],
1868                      'user_email'            => '',
1869                      'user_lang'                => $config['default_lang'],
1870                      'user_style'            => $config['default_style'],
1871                      'user_timezone'            => 0,
1872                      'user_dateformat'        => $config['default_dateformat'],
1873                      'user_allow_massemail'    => 0,
1874                  );
1875  
1876                  $user_id = user_add($user_row);
1877  
1878                  $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1879                      'bot_active'    => 1,
1880                      'bot_name'        => (string) $bot_name,
1881                      'user_id'        => (int) $user_id,
1882                      'bot_agent'        => (string) $bot_agent,
1883                      'bot_ip'        => (string) $bot_ip,
1884                  ));
1885  
1886                  _sql($sql, $errored, $error_ary);
1887              }
1888              // end Bing Bot addition
1889  
1890              // Delete shadow topics pointing to not existing topics
1891              $batch_size = 500;
1892  
1893              // Set of affected forums we have to resync
1894              $sync_forum_ids = array();
1895  
1896              do
1897              {
1898                  $sql_array = array(
1899                      'SELECT'    => 't1.topic_id, t1.forum_id',
1900                      'FROM'        => array(
1901                          TOPICS_TABLE    => 't1',
1902                      ),
1903                      'LEFT_JOIN'    => array(
1904                          array(
1905                              'FROM'    => array(TOPICS_TABLE    => 't2'),
1906                              'ON'    => 't1.topic_moved_id = t2.topic_id',
1907                          ),
1908                      ),
1909                      'WHERE'        => 't1.topic_moved_id <> 0
1910                                  AND t2.topic_id IS NULL',
1911                  );
1912                  $sql = $db->sql_build_query('SELECT', $sql_array);
1913                  $result = $db->sql_query_limit($sql, $batch_size);
1914  
1915                  $topic_ids = array();
1916                  while ($row = $db->sql_fetchrow($result))
1917                  {
1918                      $topic_ids[] = (int) $row['topic_id'];
1919  
1920                      $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id'];
1921                  }
1922                  $db->sql_freeresult($result);
1923  
1924                  if (!empty($topic_ids))
1925                  {
1926                      $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1927                          WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1928                      $db->sql_query($sql);
1929                  }
1930              }
1931              while (sizeof($topic_ids) == $batch_size);
1932  
1933              // Sync the forums we have deleted shadow topics from.
1934              sync('forum', 'forum_id', $sync_forum_ids, true, true);
1935  
1936              // Unread posts search load switch
1937              set_config('load_unreads_search', '1');
1938  
1939              // Reduce queue interval to 60 seconds, email package size to 20
1940              if ($config['queue_interval'] == 600)
1941              {
1942                  set_config('queue_interval', '60');
1943              }
1944  
1945              if ($config['email_package_size'] == 50)
1946              {
1947                  set_config('email_package_size', '20');
1948              }
1949  
1950              $no_updates = false;
1951          break;
1952  
1953          // No changes from 3.0.8-RC1 to 3.0.8
1954          case '3.0.8-RC1':
1955          break;
1956  
1957          // Changes from 3.0.8 to 3.0.9-RC1
1958          case '3.0.8':
1959              set_config('ip_login_limit_max', '50');
1960              set_config('ip_login_limit_time', '21600');
1961              set_config('ip_login_limit_use_forwarded', '0');
1962  
1963              // Update file extension group names to use language strings, again.
1964              $sql = 'SELECT group_id, group_name
1965                  FROM ' . EXTENSION_GROUPS_TABLE . '
1966                  WHERE group_name ' . $db->sql_like_expression('EXT_GROUP_' . $db->any_char);
1967              $result = $db->sql_query($sql);
1968  
1969              while ($row = $db->sql_fetchrow($result))
1970              {
1971                  $sql_ary = array(
1972                      'group_name'    => substr($row['group_name'], 10), // Strip off 'EXT_GROUP_'
1973                  );
1974  
1975                  $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . '
1976                      SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1977                      WHERE group_id = ' . $row['group_id'];
1978                  _sql($sql, $errored, $error_ary);
1979              }
1980              $db->sql_freeresult($result);
1981  
1982              /*
1983              * Due to a bug, vanilla phpbb could not create captcha tables
1984              * in 3.0.8 on firebird. It was possible for board administrators
1985              * to adjust the code to work. If code was manually adjusted by
1986              * board administrators, index names would not be the same as
1987              * what 3.0.9 and newer expect. This code fragment drops captcha
1988              * tables, destroying all entered Q&A captcha configuration, such
1989              * that when Q&A is configured next the respective tables will be
1990              * created with correct index names.
1991              *
1992              * If you wish to preserve your Q&A captcha configuration, you can
1993              * manually rename indexes to the currently expected name:
1994              *     phpbb_captcha_questions_lang_iso    => phpbb_captcha_questions_lang
1995              *     phpbb_captcha_answers_question_id    => phpbb_captcha_answers_qid
1996              *
1997              * Again, this needs to be done only if a board was manually modified
1998              * to fix broken captcha code.
1999              *
2000              if ($db_tools->sql_layer == 'firebird')
2001              {
2002                  $changes = array(
2003                      'drop_tables'    => array(
2004                          $table_prefix . 'captcha_questions',
2005                          $table_prefix . 'captcha_answers',
2006                          $table_prefix . 'qa_confirm',
2007                      ),
2008                  );
2009                  $statements = $db_tools->perform_schema_changes($changes);
2010  
2011                  foreach ($statements as $sql)
2012                  {
2013                      _sql($sql, $errored, $error_ary);
2014                  }
2015              }
2016              */
2017  
2018              $no_updates = false;
2019          break;
2020  
2021          // No changes from 3.0.9-RC1 to 3.0.9-RC2
2022          case '3.0.9-RC1':
2023          break;
2024  
2025          // No changes from 3.0.9-RC2 to 3.0.9-RC3
2026          case '3.0.9-RC2':
2027          break;
2028  
2029          // No changes from 3.0.9-RC3 to 3.0.9-RC4
2030          case '3.0.9-RC3':
2031          break;
2032  
2033          // No changes from 3.0.9-RC4 to 3.0.9
2034          case '3.0.9-RC4':
2035          break;
2036  
2037          // Changes from 3.0.9 to 3.0.10-RC1
2038          case '3.0.9':
2039              if (!isset($config['email_max_chunk_size']))
2040              {
2041                  set_config('email_max_chunk_size', '50');
2042              }
2043  
2044              $no_updates = false;
2045          break;
2046  
2047          // No changes from 3.0.10-RC1 to 3.0.10-RC2
2048          case '3.0.10-RC1':
2049          break;
2050  
2051          // No changes from 3.0.10-RC2 to 3.0.10-RC3
2052          case '3.0.10-RC2':
2053          break;
2054  
2055          // No changes from 3.0.10-RC3 to 3.0.10
2056          case '3.0.10-RC3':
2057          break;
2058  
2059          // Changes from 3.0.10 to 3.0.11-RC1
2060          case '3.0.10':
2061              // Updates users having current style a deactivated one
2062              $sql = 'SELECT style_id
2063                  FROM ' . STYLES_TABLE . '
2064                  WHERE style_active = 0';
2065              $result = $db->sql_query($sql);
2066  
2067              $deactivated_style_ids = array();
2068              while ($style_id = $db->sql_fetchfield('style_id', false, $result))
2069              {
2070                  $deactivated_style_ids[] = (int) $style_id;
2071              }
2072              $db->sql_freeresult($result);
2073  
2074              if (!empty($deactivated_style_ids))
2075              {
2076                  $sql = 'UPDATE ' . USERS_TABLE . '
2077                      SET user_style = ' . (int) $config['default_style'] .'
2078                      WHERE ' . $db->sql_in_set('user_style', $deactivated_style_ids);
2079                  _sql($sql, $errored, $error_ary);
2080              }
2081  
2082              // Delete orphan private messages
2083              $batch_size = 500;
2084  
2085              $sql_array = array(
2086                  'SELECT'    => 'p.msg_id',
2087                  'FROM'        => array(
2088                      PRIVMSGS_TABLE    => 'p',
2089                  ),
2090                  'LEFT_JOIN'    => array(
2091                      array(
2092                          'FROM'    => array(PRIVMSGS_TO_TABLE => 't'),
2093                          'ON'    => 'p.msg_id = t.msg_id',
2094                      ),
2095                  ),
2096                  'WHERE'        => 't.user_id IS NULL',
2097              );
2098              $sql = $db->sql_build_query('SELECT', $sql_array);
2099  
2100              do
2101              {
2102                  $result = $db->sql_query_limit($sql, $batch_size);
2103  
2104                  $delete_pms = array();
2105                  while ($row = $db->sql_fetchrow($result))
2106                  {
2107                      $delete_pms[] = (int) $row['msg_id'];
2108                  }
2109                  $db->sql_freeresult($result);
2110  
2111                  if (!empty($delete_pms))
2112                  {
2113                      $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
2114                          WHERE ' . $db->sql_in_set('msg_id', $delete_pms);
2115                      _sql($sql, $errored, $error_ary);
2116                  }
2117              }
2118              while (sizeof($delete_pms) == $batch_size);
2119  
2120              $no_updates = false;
2121          break;
2122  
2123          // No changes from 3.0.11-RC1 to 3.0.11-RC2
2124          case '3.0.11-RC1':
2125          break;
2126  
2127          // No changes from 3.0.11-RC2 to 3.0.11
2128          case '3.0.11-RC2':
2129          break;
2130  
2131          // Changes from 3.0.11 to 3.0.12-RC1
2132          case '3.0.11':
2133              $sql = 'UPDATE ' . MODULES_TABLE . '
2134                  SET module_auth = \'acl_u_sig\'
2135                  WHERE module_class = \'ucp\'
2136                      AND module_basename = \'profile\'
2137                      AND module_mode = \'signature\'';
2138              _sql($sql, $errored, $error_ary);
2139  
2140              // Update bots
2141              if (!function_exists('user_delete'))
2142              {
2143                  include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
2144              }
2145  
2146              $bots_updates = array(
2147                  // Bot Deletions
2148                  'NG-Search [Bot]'        => false,
2149                  'Nutch/CVS [Bot]'        => false,
2150                  'OmniExplorer [Bot]'    => false,
2151                  'Seekport [Bot]'        => false,
2152                  'Synoo [Bot]'            => false,
2153                  'WiseNut [Bot]'            => false,
2154  
2155                  // Bot Updates
2156                  // Bot name to bot user agent map
2157                  'Baidu [Spider]'    => 'Baiduspider',
2158                  'Exabot [Bot]'        => 'Exabot',
2159                  'Voyager [Bot]'        => 'voyager/',
2160                  'W3C [Validator]'    => 'W3C_Validator',
2161              );
2162  
2163              foreach ($bots_updates as $bot_name => $bot_agent)
2164              {
2165                  $sql = 'SELECT user_id
2166                      FROM ' . USERS_TABLE . '
2167                      WHERE user_type = ' . USER_IGNORE . "
2168                          AND username_clean = '" . $db->sql_escape(utf8_clean_string($bot_name)) . "'";
2169                  $result = $db->sql_query($sql);
2170                  $bot_user_id = (int) $db->sql_fetchfield('user_id');
2171                  $db->sql_freeresult($result);
2172  
2173                  if ($bot_user_id)
2174                  {
2175                      if ($bot_agent === false)
2176                      {
2177                          $sql = 'DELETE FROM ' . BOTS_TABLE . "
2178                              WHERE user_id = $bot_user_id";
2179                          _sql($sql, $errored, $error_ary);
2180  
2181                          user_delete('remove', $bot_user_id);
2182                      }
2183                      else
2184                      {
2185                          $sql = 'UPDATE ' . BOTS_TABLE . "
2186                              SET bot_agent = '" .  $db->sql_escape($bot_agent) . "'
2187                              WHERE user_id = $bot_user_id";
2188                          _sql($sql, $errored, $error_ary);
2189                      }
2190                  }
2191              }
2192  
2193              // Disable receiving pms for bots
2194              $sql = 'SELECT user_id
2195                  FROM ' . BOTS_TABLE;
2196              $result = $db->sql_query($sql);
2197  
2198              $bot_user_ids = array();
2199              while ($row = $db->sql_fetchrow($result))
2200              {
2201                  $bot_user_ids[] = (int) $row['user_id'];
2202              }
2203              $db->sql_freeresult($result);
2204  
2205              if (!empty($bot_user_ids))
2206              {
2207                  $sql = 'UPDATE ' . USERS_TABLE . '
2208                      SET user_allow_pm = 0
2209                      WHERE ' . $db->sql_in_set('user_id', $bot_user_ids);
2210                  _sql($sql, $errored, $error_ary);
2211              }
2212  
2213              /**
2214              * Update BBCodes that currently use the LOCAL_URL tag
2215              *
2216              * To fix http://tracker.phpbb.com/browse/PHPBB3-8319 we changed
2217              * the second_pass_replace value, so that needs updating for existing ones
2218              */
2219              $sql = 'SELECT *
2220                  FROM ' . BBCODES_TABLE . '
2221                  WHERE bbcode_match ' . $db->sql_like_expression($db->any_char . 'LOCAL_URL' . $db->any_char);
2222              $result = $db->sql_query($sql);
2223  
2224              while ($row = $db->sql_fetchrow($result))
2225              {
2226                  if (!class_exists('acp_bbcodes'))
2227                  {
2228                      phpbb_require_updated('includes/acp/acp_bbcodes.' . $phpEx);
2229                  }
2230                  $bbcode_match = $row['bbcode_match'];
2231                  $bbcode_tpl = $row['bbcode_tpl'];
2232  
2233                  $acp_bbcodes = new acp_bbcodes();
2234                  $sql_ary = $acp_bbcodes->build_regexp($bbcode_match, $bbcode_tpl);
2235  
2236                  $sql = 'UPDATE ' . BBCODES_TABLE . '
2237                      SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
2238                      WHERE bbcode_id = ' . (int) $row['bbcode_id'];
2239                  $db->sql_query($sql);
2240              }
2241              $db->sql_freeresult($result);
2242  
2243              $no_updates = false;
2244          break;
2245  
2246          // No changes from 3.0.12-RC1 to 3.0.12-RC2
2247          case '3.0.12-RC1':
2248          break;
2249  
2250          // No changes from 3.0.12-RC2 to 3.0.12-RC3
2251          case '3.0.12-RC2':
2252          break;
2253  
2254          // No changes from 3.0.12-RC3 to 3.0.12
2255          case '3.0.12-RC3':
2256          break;
2257      }
2258  }
2259  
2260  ?>


Generated: Wed Oct 2 15:03:47 2013 Cross-referenced by PHPXref 0.7.1