[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/install/ -> install_convert.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  /**
  15  */
  16  
  17  if (!defined('IN_INSTALL'))
  18  {
  19      // Someone has tried to access the file direct. This is not a good idea, so exit
  20      exit;
  21  }
  22  
  23  if (!empty($setmodules))
  24  {
  25      $module[] = array(
  26          'module_type'        => 'install',
  27          'module_title'        => 'CONVERT',
  28          'module_filename'    => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
  29          'module_order'        => 20,
  30          'module_subs'        => '',
  31          'module_stages'        => array('INTRO', 'SETTINGS', 'IN_PROGRESS', 'FINAL'),
  32          'module_reqs'        => ''
  33      );
  34  }
  35  
  36  /**
  37  * Class holding all convertor-specific details.
  38  */
  39  class convert
  40  {
  41      var $options = array();
  42  
  43      var $convertor_tag = '';
  44      var $src_dbms = '';
  45      var $src_dbhost = '';
  46      var $src_dbport = '';
  47      var $src_dbuser = '';
  48      var $src_dbpasswd = '';
  49      var $src_dbname = '';
  50      var $src_table_prefix = '';
  51  
  52      var $convertor_data = array();
  53      var $tables = array();
  54      var $config_schema = array();
  55      var $convertor = array();
  56      var $src_truncate_statement = 'DELETE FROM ';
  57      var $truncate_statement = 'DELETE FROM ';
  58  
  59      var $fulltext_search;
  60  
  61      // Batch size, can be adjusted by the conversion file
  62      // For big boards a value of 6000 seems to be optimal
  63      var $batch_size = 2000;
  64      // Number of rows to be inserted at once (extended insert) if supported
  65      // For installations having enough memory a value of 60 may be good.
  66      var $num_wait_rows = 20;
  67  
  68      // Mysqls internal recoding engine messing up with our (better) functions? We at least support more encodings than mysql so should use it in favor.
  69      var $mysql_convert = false;
  70  
  71      var $p_master;
  72  
  73  	function convert(&$p_master)
  74      {
  75          $this->p_master = &$p_master;
  76      }
  77  }
  78  
  79  /**
  80  * Convert class for conversions
  81  */
  82  class install_convert extends module
  83  {
  84      /** @var array */
  85      protected $lang;
  86  
  87      /** @var string */
  88      protected $language;
  89  
  90      /** @var \phpbb\template\template */
  91      protected $template;
  92  
  93      /** @var string */
  94      protected $phpbb_root_path;
  95  
  96      /** @var string */
  97      protected $php_ext;
  98  
  99      /**
 100      * Variables used while converting, they are accessible from the global variable $convert
 101      */
 102  	function install_convert(&$p_master)
 103      {
 104          $this->p_master = &$p_master;
 105      }
 106  
 107  	function main($mode, $sub)
 108      {
 109          global $lang, $template, $phpbb_root_path, $phpEx, $cache, $config, $language, $table_prefix;
 110          global $convert, $request, $phpbb_container, $phpbb_config_php_file;
 111  
 112          $this->tpl_name = 'install_convert';
 113          $this->mode = $mode;
 114          $this->lang = $lang;
 115          $this->language = $language;
 116          $this->template = $template;
 117          $this->phpbb_root_path = $phpbb_root_path;
 118          $this->php_ext = $phpEx;
 119  
 120          if (!$this->check_phpbb_installed())
 121          {
 122              return;
 123          }
 124  
 125          $convert = new convert($this->p_master);
 126  
 127          // Enable super globals to prevent issues with the new \phpbb\request\request object
 128          $request->enable_super_globals();
 129          // Create a normal container now
 130          $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
 131          $phpbb_container = $phpbb_container_builder->get_container();
 132  
 133          // Create cache
 134          $cache = $phpbb_container->get('cache');
 135  
 136          switch ($sub)
 137          {
 138              case 'intro':
 139                  extract($phpbb_config_php_file->get_all());
 140  
 141                  require($phpbb_root_path . 'includes/constants.' . $phpEx);
 142                  require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
 143  
 144                  $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
 145  
 146                  $db = new $dbms();
 147                  $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
 148                  unset($dbpasswd);
 149  
 150                  // We need to fill the config to let internal functions correctly work
 151                  $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
 152                  set_config(null, null, null, $config);
 153                  set_config_count(null, null, null, $config);
 154  
 155                  // Detect if there is already a conversion in progress at this point and offer to resume
 156                  // It's quite possible that the user will get disconnected during a large conversion so they need to be able to resume it
 157                  $new_conversion = request_var('new_conv', 0);
 158  
 159                  if ($new_conversion)
 160                  {
 161                      $config['convert_progress'] = '';
 162                      $config['convert_db_server'] = '';
 163                      $config['convert_db_user'] = '';
 164                      $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
 165                          WHERE config_name = 'convert_progress'
 166                              OR config_name = 'convert_db_server'
 167                              OR config_name = 'convert_db_user'"
 168                      );
 169                  }
 170  
 171                  // Let's see if there is a conversion in the works...
 172                  $options = array();
 173                  if (!empty($config['convert_progress']) && !empty($config['convert_db_server']) && !empty($config['convert_db_user']) && !empty($config['convert_options']))
 174                  {
 175                      $options = unserialize($config['convert_progress']);
 176                      $options = array_merge($options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
 177                  }
 178  
 179                  // This information should have already been checked once, but do it again for safety
 180                  if (!empty($options) && !empty($options['tag']) &&
 181                      isset($options['dbms']) &&
 182                      isset($options['dbhost']) &&
 183                      isset($options['dbport']) &&
 184                      isset($options['dbuser']) &&
 185                      isset($options['dbpasswd']) &&
 186                      isset($options['dbname']) &&
 187                      isset($options['table_prefix']))
 188                  {
 189                      $this->page_title = $lang['CONTINUE_CONVERT'];
 190  
 191                      $template->assign_vars(array(
 192                          'TITLE'            => $lang['CONTINUE_CONVERT'],
 193                          'BODY'            => $lang['CONTINUE_CONVERT_BODY'],
 194                          'L_NEW'            => $lang['CONVERT_NEW_CONVERSION'],
 195                          'L_CONTINUE'    => $lang['CONTINUE_OLD_CONVERSION'],
 196                          'S_CONTINUE'    => true,
 197  
 198                          'U_NEW_ACTION'        => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=intro&amp;new_conv=1&amp;language=$language",
 199                          'U_CONTINUE_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$options['tag']}{$options['step']}&amp;language=$language",
 200                      ));
 201  
 202                      return;
 203                  }
 204  
 205                  $this->list_convertors($sub);
 206  
 207              break;
 208  
 209              case 'settings':
 210                  $this->get_convert_settings($sub);
 211              break;
 212  
 213              case 'in_progress':
 214                  $this->convert_data($sub);
 215              break;
 216  
 217              case 'final':
 218                  $this->page_title = $lang['CONVERT_COMPLETE'];
 219  
 220                  $template->assign_vars(array(
 221                      'TITLE'        => $lang['CONVERT_COMPLETE'],
 222                      'BODY'        => $lang['CONVERT_COMPLETE_EXPLAIN'],
 223                  ));
 224  
 225                  // If we reached this step (conversion completed) we want to purge the cache and log the user out.
 226                  // This is for making sure the session get not screwed due to the 3.0.x users table being completely new.
 227                  $cache->purge();
 228  
 229                  extract($phpbb_config_php_file->get_all());
 230  
 231                  require($phpbb_root_path . 'includes/constants.' . $phpEx);
 232                  require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
 233  
 234                  $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
 235  
 236                  $db = new $dbms();
 237                  $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
 238                  unset($dbpasswd);
 239  
 240                  $sql = 'SELECT config_value
 241                      FROM ' . CONFIG_TABLE . '
 242                      WHERE config_name = \'search_type\'';
 243                  $result = $db->sql_query($sql);
 244  
 245                  if ($db->sql_fetchfield('config_value') != 'fulltext_mysql')
 246                  {
 247                      $template->assign_vars(array(
 248                          'S_ERROR_BOX'    => true,
 249                          'ERROR_TITLE'    => $lang['SEARCH_INDEX_UNCONVERTED'],
 250                          'ERROR_MSG'        => $lang['SEARCH_INDEX_UNCONVERTED_EXPLAIN'],
 251                      ));
 252                  }
 253  
 254                  switch ($db->get_sql_layer())
 255                  {
 256                      case 'sqlite':
 257                      case 'sqlite3':
 258                          $db->sql_query('DELETE FROM ' . SESSIONS_KEYS_TABLE);
 259                          $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
 260                      break;
 261  
 262                      default:
 263                          $db->sql_query('TRUNCATE TABLE ' . SESSIONS_KEYS_TABLE);
 264                          $db->sql_query('TRUNCATE TABLE ' . SESSIONS_TABLE);
 265                      break;
 266                  }
 267  
 268              break;
 269          }
 270      }
 271  
 272      /**
 273      * Check whether phpBB is installed.
 274      * Assigns error template vars if not installed.
 275      *
 276      * @return bool Returns true if phpBB is installed.
 277      */
 278  	public function check_phpbb_installed()
 279      {
 280          if (phpbb_check_installation_exists($this->phpbb_root_path, $this->php_ext))
 281          {
 282              return true;
 283          }
 284  
 285          $this->page_title = 'BOARD_NOT_INSTALLED';
 286          $install_url = append_sid($this->phpbb_root_path . 'install/index.' . $this->php_ext, 'mode=install&amp;language=' . $this->language);
 287  
 288          $this->template->assign_vars(array(
 289              'S_NOT_INSTALLED'        => true,
 290              'BODY'                    => sprintf($this->lang['BOARD_NOT_INSTALLED_EXPLAIN'], $install_url),
 291          ));
 292  
 293          return false;
 294      }
 295  
 296      /**
 297      * Generate a list of all available conversion modules
 298      */
 299  	function list_convertors($sub)
 300      {
 301          global $lang, $language, $template, $phpbb_root_path, $phpEx;
 302  
 303          $this->page_title = $lang['SUB_INTRO'];
 304  
 305          $template->assign_vars(array(
 306              'TITLE'        => $lang['CONVERT_INTRO'],
 307              'BODY'        => $lang['CONVERT_INTRO_BODY'],
 308  
 309              'L_AUTHOR'                    => $lang['AUTHOR'],
 310              'L_AVAILABLE_CONVERTORS'    => $lang['AVAILABLE_CONVERTORS'],
 311              'L_CONVERT'                    => $lang['CONVERT'],
 312              'L_NO_CONVERTORS'            => $lang['NO_CONVERTORS'],
 313              'L_OPTIONS'                    => $lang['CONVERT_OPTIONS'],
 314              'L_SOFTWARE'                => $lang['SOFTWARE'],
 315              'L_VERSION'                    => $lang['VERSION'],
 316  
 317              'S_LIST'    => true,
 318          ));
 319  
 320          $convertors = $sort = array();
 321          $get_info = true;
 322  
 323          $handle = @opendir('./convertors/');
 324  
 325          if (!$handle)
 326          {
 327              $this->error('Unable to access the convertors directory', __LINE__, __FILE__);
 328          }
 329  
 330          while ($entry = readdir($handle))
 331          {
 332              if (preg_match('/^convert_([a-z0-9_]+).' . $phpEx . '$/i', $entry, $m))
 333              {
 334                  include('./convertors/' . $entry);
 335                  if (isset($convertor_data))
 336                  {
 337                      $sort[strtolower($convertor_data['forum_name'])] = sizeof($convertors);
 338  
 339                      $convertors[] = array(
 340                          'tag'            =>    $m[1],
 341                          'forum_name'    =>    $convertor_data['forum_name'],
 342                          'version'        =>    $convertor_data['version'],
 343                          'dbms'            =>    $convertor_data['dbms'],
 344                          'dbhost'        =>    $convertor_data['dbhost'],
 345                          'dbport'        =>    $convertor_data['dbport'],
 346                          'dbuser'        =>    $convertor_data['dbuser'],
 347                          'dbpasswd'        =>    $convertor_data['dbpasswd'],
 348                          'dbname'        =>    $convertor_data['dbname'],
 349                          'table_prefix'    =>    $convertor_data['table_prefix'],
 350                          'author'        =>    $convertor_data['author']
 351                      );
 352                  }
 353                  unset($convertor_data);
 354              }
 355          }
 356          closedir($handle);
 357  
 358          @ksort($sort);
 359  
 360          foreach ($sort as $void => $index)
 361          {
 362              $template->assign_block_vars('convertors', array(
 363                  'AUTHOR'    => $convertors[$index]['author'],
 364                  'SOFTWARE'    => $convertors[$index]['forum_name'],
 365                  'VERSION'    => $convertors[$index]['version'],
 366  
 367                  'U_CONVERT'    => $this->p_master->module_url . "?mode={$this->mode}&amp;language=$language&amp;sub=settings&amp;tag=" . $convertors[$index]['tag'],
 368              ));
 369          }
 370      }
 371  
 372      /**
 373      */
 374  	function get_convert_settings($sub)
 375      {
 376          global $lang, $language, $template, $db, $phpbb_root_path, $phpEx, $config, $cache, $phpbb_config_php_file;
 377  
 378          extract($phpbb_config_php_file->get_all());
 379  
 380          require($phpbb_root_path . 'includes/constants.' . $phpEx);
 381          require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
 382  
 383          $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
 384  
 385          $db = new $dbms();
 386          $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
 387          unset($dbpasswd);
 388  
 389          $this->page_title = $lang['STAGE_SETTINGS'];
 390  
 391          // We need to fill the config to let internal functions correctly work
 392          $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
 393          set_config(null, null, null, $config);
 394          set_config_count(null, null, null, $config);
 395  
 396          $convertor_tag = request_var('tag', '');
 397  
 398          if (empty($convertor_tag))
 399          {
 400              $this->p_master->error($lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
 401          }
 402          $get_info = true;
 403  
 404          // check security implications of direct inclusion
 405          $convertor_tag = basename($convertor_tag);
 406          if (!file_exists('./convertors/convert_' . $convertor_tag . '.' . $phpEx))
 407          {
 408              $this->p_master->error($lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
 409          }
 410  
 411          include('./convertors/convert_' . $convertor_tag . '.' . $phpEx);
 412  
 413          // The test_file is a file that should be present in the location of the old board.
 414          if (!isset($test_file))
 415          {
 416              $this->p_master->error($lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
 417          }
 418  
 419          $submit = (isset($_POST['submit'])) ? true : false;
 420  
 421          $src_dbms            = request_var('src_dbms', $convertor_data['dbms']);
 422          $src_dbhost            = request_var('src_dbhost', $convertor_data['dbhost']);
 423          $src_dbport            = request_var('src_dbport', $convertor_data['dbport']);
 424          $src_dbuser            = request_var('src_dbuser', $convertor_data['dbuser']);
 425          $src_dbpasswd        = request_var('src_dbpasswd', $convertor_data['dbpasswd']);
 426          $src_dbname            = request_var('src_dbname', $convertor_data['dbname']);
 427          $src_table_prefix    = request_var('src_table_prefix', $convertor_data['table_prefix']);
 428          $forum_path            = request_var('forum_path', $convertor_data['forum_path']);
 429          $refresh            = request_var('refresh', 1);
 430  
 431          // Default URL of the old board
 432          // @todo Are we going to use this for attempting to convert URL references in posts, or should we remove it?
 433          //        -> We should convert old urls to the new relative urls format
 434          // $src_url = request_var('src_url', 'Not in use at the moment');
 435  
 436          // strip trailing slash from old forum path
 437          $forum_path = (strlen($forum_path) && $forum_path[strlen($forum_path) - 1] == '/') ? substr($forum_path, 0, -1) : $forum_path;
 438  
 439          $error = array();
 440          if ($submit)
 441          {
 442              if (!@file_exists('./../' . $forum_path . '/' . $test_file))
 443              {
 444                  $error[] = sprintf($lang['COULD_NOT_FIND_PATH'], $forum_path);
 445              }
 446  
 447              $connect_test = false;
 448              $available_dbms = get_available_dbms(false, true, true);
 449  
 450              if (!isset($available_dbms[$src_dbms]) || !$available_dbms[$src_dbms]['AVAILABLE'])
 451              {
 452                  $error[] = $lang['INST_ERR_NO_DB'];
 453                  $connect_test = false;
 454              }
 455              else
 456              {
 457                  $connect_test = connect_check_db(true, $error, $available_dbms[$src_dbms], $src_table_prefix, $src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, true, ($src_dbms == $dbms) ? false : true, false);
 458              }
 459  
 460              // The forum prefix of the old and the new forum can only be the same if two different databases are used.
 461              if ($src_table_prefix == $table_prefix && $src_dbms == $dbms && $src_dbhost == $dbhost && $src_dbport == $dbport && $src_dbname == $dbname)
 462              {
 463                  $error[] = sprintf($lang['TABLE_PREFIX_SAME'], $src_table_prefix);
 464              }
 465  
 466              $src_dbms = $phpbb_config_php_file->convert_30_dbms_to_31($src_dbms);
 467  
 468              // Check table prefix
 469              if (!sizeof($error))
 470              {
 471                  // initiate database connection to old db if old and new db differ
 472                  global $src_db, $same_db;
 473                  $src_db = $same_db = false;
 474  
 475                  if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser)
 476                  {
 477                      $src_db = new $src_dbms();
 478                      $src_db->sql_connect($src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, false, true);
 479                      $same_db = false;
 480                  }
 481                  else
 482                  {
 483                      $src_db = $db;
 484                      $same_db = true;
 485                  }
 486  
 487                  $src_db->sql_return_on_error(true);
 488                  $db->sql_return_on_error(true);
 489  
 490                  // Try to select one row from the first table to see if the prefix is OK
 491                  $result = $src_db->sql_query_limit('SELECT * FROM ' . $src_table_prefix . $tables[0], 1);
 492  
 493                  if (!$result)
 494                  {
 495                      $prefixes = array();
 496  
 497                      $tables_existing = get_tables($src_db);
 498                      $tables_existing = array_map('strtolower', $tables_existing);
 499                      foreach ($tables_existing as $table_name)
 500                      {
 501                          compare_table($tables, $table_name, $prefixes);
 502                      }
 503                      unset($tables_existing);
 504  
 505                      foreach ($prefixes as $prefix => $count)
 506                      {
 507                          if ($count >= sizeof($tables))
 508                          {
 509                              $possible_prefix = $prefix;
 510                              break;
 511                          }
 512                      }
 513  
 514                      $msg = '';
 515                      if (!empty($convertor_data['table_prefix']))
 516                      {
 517                          $msg .= sprintf($lang['DEFAULT_PREFIX_IS'], $convertor_data['forum_name'], $convertor_data['table_prefix']);
 518                      }
 519  
 520                      if (!empty($possible_prefix))
 521                      {
 522                          $msg .= '<br />';
 523                          $msg .= ($possible_prefix == '*') ? $lang['BLANK_PREFIX_FOUND'] : sprintf($lang['PREFIX_FOUND'], $possible_prefix);
 524                          $src_table_prefix = ($possible_prefix == '*') ? '' : $possible_prefix;
 525                      }
 526  
 527                      $error[] = $msg;
 528                  }
 529                  $src_db->sql_freeresult($result);
 530                  $src_db->sql_return_on_error(false);
 531              }
 532  
 533              if (!sizeof($error))
 534              {
 535                  // Save convertor Status
 536                  set_config('convert_progress', serialize(array(
 537                      'step'            => '',
 538                      'table_prefix'    => $src_table_prefix,
 539                      'tag'            => $convertor_tag,
 540                  )), true);
 541                  set_config('convert_db_server', serialize(array(
 542                      'dbms'            => $src_dbms,
 543                      'dbhost'        => $src_dbhost,
 544                      'dbport'        => $src_dbport,
 545                      'dbname'        => $src_dbname,
 546                  )), true);
 547                  set_config('convert_db_user', serialize(array(
 548                      'dbuser'        => $src_dbuser,
 549                      'dbpasswd'        => $src_dbpasswd,
 550                  )), true);
 551  
 552                  // Save options
 553                  set_config('convert_options', serialize(array('forum_path' => './../' . $forum_path, 'refresh' => $refresh)), true);
 554  
 555                  $template->assign_block_vars('checks', array(
 556                      'TITLE'        => $lang['VERIFY_OPTIONS'],
 557                      'RESULT'    => $lang['CONVERT_SETTINGS_VERIFIED'],
 558                  ));
 559  
 560                  $template->assign_vars(array(
 561                      'L_SUBMIT'    => $lang['BEGIN_CONVERT'],
 562  //                    'S_HIDDEN'    => $s_hidden_fields,
 563                      'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag=$convertor_tag&amp;language=$language",
 564                  ));
 565  
 566                  return;
 567              }
 568              else
 569              {
 570                  $template->assign_block_vars('checks', array(
 571                      'TITLE'        => $lang['VERIFY_OPTIONS'],
 572                      'RESULT'    => '<b style="color:red">' . implode('<br />', $error) . '</b>',
 573                  ));
 574              }
 575          } // end submit
 576  
 577          foreach ($this->convert_options as $config_key => $vars)
 578          {
 579              if (!is_array($vars) && strpos($config_key, 'legend') === false)
 580              {
 581                  continue;
 582              }
 583  
 584              if (strpos($config_key, 'legend') !== false)
 585              {
 586                  $template->assign_block_vars('options', array(
 587                      'S_LEGEND'        => true,
 588                      'LEGEND'        => $lang[$vars])
 589                  );
 590  
 591                  continue;
 592              }
 593  
 594              $options = isset($vars['options']) ? $vars['options'] : '';
 595  
 596              $template->assign_block_vars('options', array(
 597                  'KEY'            => $config_key,
 598                  'TITLE'            => $lang[$vars['lang']],
 599                  'S_EXPLAIN'        => $vars['explain'],
 600                  'S_LEGEND'        => false,
 601                  'TITLE_EXPLAIN'    => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
 602                  'CONTENT'        => $this->p_master->input_field($config_key, $vars['type'], ${$config_key}, $options),
 603                  )
 604              );
 605          }
 606  
 607          $template->assign_vars(array(
 608              'TITLE'        => $lang['STAGE_SETTINGS'],
 609              'BODY'        => $lang['CONV_OPTIONS_BODY'],
 610              'L_SUBMIT'    => $lang['BEGIN_CONVERT'],
 611              'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=settings&amp;tag=$convertor_tag&amp;language=$language",
 612          ));
 613      }
 614  
 615      /**
 616      * The function which does the actual work (or dispatches it to the relevant places)
 617      */
 618  	function convert_data($sub)
 619      {
 620          global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache, $auth;
 621          global $convert, $convert_row, $message_parser, $skip_rows, $language;
 622          global $request, $phpbb_config_php_file, $phpbb_dispatcher;
 623  
 624          extract($phpbb_config_php_file->get_all());
 625  
 626          require($phpbb_root_path . 'includes/constants.' . $phpEx);
 627          require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
 628  
 629          $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
 630  
 631          $db = new $dbms();
 632          $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
 633          unset($dbpasswd);
 634  
 635          // We need to fill the config to let internal functions correctly work
 636          $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
 637          set_config(null, null, null, $config);
 638          set_config_count(null, null, null, $config);
 639  
 640          // Override a couple of config variables for the duration
 641          $config['max_quote_depth'] = 0;
 642  
 643          // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
 644          $config['max_post_chars'] = $config['min_post_chars'] = 0;
 645  
 646          // Set up a user as well. We _should_ have enough of a database here at this point to do this
 647          // and it helps for any core code we call
 648          $user->session_begin();
 649          $user->page = $user->extract_current_page($phpbb_root_path);
 650  
 651          // This is a little bit of a fudge, but it allows the language entries to be available to the
 652          // core code without us loading them again
 653          $user->lang = &$lang;
 654  
 655          $this->page_title = $user->lang['STAGE_IN_PROGRESS'];
 656  
 657          $convert->options = array();
 658          if (isset($config['convert_progress']))
 659          {
 660              $convert->options = unserialize($config['convert_progress']);
 661              $convert->options = array_merge($convert->options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
 662          }
 663  
 664          // This information should have already been checked once, but do it again for safety
 665          if (empty($convert->options) || empty($convert->options['tag']) ||
 666              !isset($convert->options['dbms']) ||
 667              !isset($convert->options['dbhost']) ||
 668              !isset($convert->options['dbport']) ||
 669              !isset($convert->options['dbuser']) ||
 670              !isset($convert->options['dbpasswd']) ||
 671              !isset($convert->options['dbname']) ||
 672              !isset($convert->options['table_prefix']))
 673          {
 674              $this->p_master->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
 675          }
 676  
 677          // Make some short variables accessible, for easier referencing
 678          $convert->convertor_tag = basename($convert->options['tag']);
 679          $convert->src_dbms = $convert->options['dbms'];
 680          $convert->src_dbhost = $convert->options['dbhost'];
 681          $convert->src_dbport = $convert->options['dbport'];
 682          $convert->src_dbuser = $convert->options['dbuser'];
 683          $convert->src_dbpasswd = $convert->options['dbpasswd'];
 684          $convert->src_dbname = $convert->options['dbname'];
 685          $convert->src_table_prefix = $convert->options['table_prefix'];
 686  
 687          // initiate database connection to old db if old and new db differ
 688          global $src_db, $same_db;
 689          $src_db = $same_db = null;
 690          if ($convert->src_dbms != $dbms || $convert->src_dbhost != $dbhost || $convert->src_dbport != $dbport || $convert->src_dbname != $dbname || $convert->src_dbuser != $dbuser)
 691          {
 692              $dbms = $convert->src_dbms;
 693              $src_db = new $dbms();
 694              $src_db->sql_connect($convert->src_dbhost, $convert->src_dbuser, htmlspecialchars_decode($convert->src_dbpasswd), $convert->src_dbname, $convert->src_dbport, false, true);
 695              $same_db = false;
 696          }
 697          else
 698          {
 699              $src_db = $db;
 700              $same_db = true;
 701          }
 702  
 703          $convert->mysql_convert = false;
 704          switch ($src_db->sql_layer)
 705          {
 706              case 'sqlite':
 707              case 'sqlite3':
 708                  $convert->src_truncate_statement = 'DELETE FROM ';
 709              break;
 710  
 711              // Thanks MySQL, for silently converting...
 712              case 'mysql':
 713              case 'mysql4':
 714                  if (version_compare($src_db->sql_server_info(true, false), '4.1.3', '>='))
 715                  {
 716                      $convert->mysql_convert = true;
 717                  }
 718                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
 719              break;
 720  
 721              case 'mysqli':
 722                  $convert->mysql_convert = true;
 723                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
 724              break;
 725  
 726              default:
 727                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
 728              break;
 729          }
 730  
 731          if ($convert->mysql_convert && !$same_db)
 732          {
 733              $src_db->sql_query("SET NAMES 'binary'");
 734          }
 735  
 736          switch ($db->get_sql_layer())
 737          {
 738              case 'sqlite':
 739              case 'sqlite3':
 740                  $convert->truncate_statement = 'DELETE FROM ';
 741              break;
 742  
 743              default:
 744                  $convert->truncate_statement = 'TRUNCATE TABLE ';
 745              break;
 746          }
 747  
 748          $get_info = false;
 749  
 750          // check security implications of direct inclusion
 751          if (!file_exists('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx))
 752          {
 753              $this->p_master->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
 754          }
 755  
 756          if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx))
 757          {
 758              include('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx);
 759          }
 760  
 761          $get_info = true;
 762          include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
 763  
 764          // Map some variables...
 765          $convert->convertor_data = $convertor_data;
 766          $convert->tables = $tables;
 767          $convert->config_schema = $config_schema;
 768  
 769          // Now include the real data
 770          $get_info = false;
 771          include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
 772  
 773          $convert->convertor_data = $convertor_data;
 774          $convert->tables = $tables;
 775          $convert->config_schema = $config_schema;
 776          $convert->convertor = $convertor;
 777  
 778          // The test_file is a file that should be present in the location of the old board.
 779          if (!file_exists($convert->options['forum_path'] . '/' . $test_file))
 780          {
 781              $this->p_master->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->options['forum_path']), __LINE__, __FILE__);
 782          }
 783  
 784          $search_type = $config['search_type'];
 785  
 786          // For conversions we are a bit less strict and set to a search backend we know exist...
 787          if (!class_exists($search_type))
 788          {
 789              $search_type = '\phpbb\search\fulltext_native';
 790              set_config('search_type', $search_type);
 791          }
 792  
 793          if (!class_exists($search_type))
 794          {
 795              trigger_error('NO_SUCH_SEARCH_MODULE');
 796          }
 797  
 798          $error = false;
 799          $convert->fulltext_search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
 800  
 801          if ($error)
 802          {
 803              trigger_error($error);
 804          }
 805  
 806          include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
 807          $message_parser = new parse_message();
 808  
 809          $jump = request_var('jump', 0);
 810          $final_jump = request_var('final_jump', 0);
 811          $sync_batch = request_var('sync_batch', -1);
 812          $last_statement = request_var('last', 0);
 813  
 814          // We are running sync...
 815          if ($sync_batch >= 0)
 816          {
 817              $this->sync_forums($sync_batch);
 818              return;
 819          }
 820  
 821          if ($jump)
 822          {
 823              $this->jump($jump, $last_statement);
 824              return;
 825          }
 826  
 827          if ($final_jump)
 828          {
 829              $this->final_jump($final_jump);
 830              return;
 831          }
 832  
 833          $current_table = request_var('current_table', 0);
 834          $old_current_table = min(-1, $current_table - 1);
 835          $skip_rows = request_var('skip_rows', 0);
 836  
 837          if (!$current_table && !$skip_rows)
 838          {
 839              if (!$request->variable('confirm', false))
 840              {
 841                  // If avatars / ranks / smilies folders are specified make sure they are writable
 842                  $bad_folders = array();
 843  
 844                  $local_paths = array(
 845                      'avatar_path'            => path($config['avatar_path']),
 846                      'avatar_gallery_path'    => path($config['avatar_gallery_path']),
 847                      'icons_path'            => path($config['icons_path']),
 848                      'ranks_path'            => path($config['ranks_path']),
 849                      'smilies_path'            => path($config['smilies_path'])
 850                  );
 851  
 852                  foreach ($local_paths as $folder => $local_path)
 853                  {
 854                      if (isset($convert->convertor[$folder]))
 855                      {
 856                          if (empty($convert->convertor['test_file']))
 857                          {
 858                              // test_file is mandantory at the moment so this should never be reached, but just in case...
 859                              $this->p_master->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
 860                          }
 861  
 862                          if (!$local_path || !phpbb_is_writable($phpbb_root_path . $local_path))
 863                          {
 864                              if (!$local_path)
 865                              {
 866                                  $bad_folders[] = sprintf($user->lang['CONFIG_PHPBB_EMPTY'], $folder);
 867                              }
 868                              else
 869                              {
 870                                  $bad_folders[] = $local_path;
 871                              }
 872                          }
 873                      }
 874                  }
 875  
 876                  if (sizeof($bad_folders))
 877                  {
 878                      $msg = (sizeof($bad_folders) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
 879                      sort($bad_folders);
 880                      $this->p_master->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true);
 881  
 882                      $template->assign_vars(array(
 883                          'L_SUBMIT'    => $user->lang['INSTALL_TEST'],
 884                          'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}&amp;language=$language",
 885                      ));
 886                      return;
 887                  }
 888  
 889                  // Grab all the tables used in convertor
 890                  $missing_tables = $tables_list = $aliases = array();
 891  
 892                  foreach ($convert->convertor['schema'] as $schema)
 893                  {
 894                      // Skip those not used (because of addons/plugins not detected)
 895                      if (!$schema['target'])
 896                      {
 897                          continue;
 898                      }
 899  
 900                      foreach ($schema as $key => $val)
 901                      {
 902                          // we're dealing with an array like:
 903                          // array('forum_status',            'forums.forum_status',                'is_item_locked')
 904                          if (is_int($key) && !empty($val[1]))
 905                          {
 906                              $temp_data = $val[1];
 907                              if (!is_array($temp_data))
 908                              {
 909                                  $temp_data = array($temp_data);
 910                              }
 911  
 912                              foreach ($temp_data as $val)
 913                              {
 914                                  if (preg_match('/([a-z0-9_]+)\.([a-z0-9_]+)\)* ?A?S? ?([a-z0-9_]*?)\.?([a-z0-9_]*)$/i', $val, $m))
 915                                  {
 916                                      $table = $convert->src_table_prefix . $m[1];
 917                                      $tables_list[$table] = $table;
 918  
 919                                      if (!empty($m[3]))
 920                                      {
 921                                          $aliases[] = $convert->src_table_prefix . $m[3];
 922                                      }
 923                                  }
 924                              }
 925                          }
 926                          // 'left_join'        => 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1'
 927                          else if ($key == 'left_join')
 928                          {
 929                              // Convert the value if it wasn't an array already.
 930                              if (!is_array($val))
 931                              {
 932                                  $val = array($val);
 933                              }
 934  
 935                              for ($j = 0, $size = sizeof($val); $j < $size; ++$j)
 936                              {
 937                                  if (preg_match('/LEFT JOIN ([a-z0-9_]+) AS ([a-z0-9_]+)/i', $val[$j], $m))
 938                                  {
 939                                      $table = $convert->src_table_prefix . $m[1];
 940                                      $tables_list[$table] = $table;
 941  
 942                                      if (!empty($m[2]))
 943                                      {
 944                                          $aliases[] = $convert->src_table_prefix . $m[2];
 945                                      }
 946                                  }
 947                              }
 948                          }
 949                      }
 950                  }
 951  
 952                  // Remove aliased tables from $tables_list
 953                  foreach ($aliases as $alias)
 954                  {
 955                      unset($tables_list[$alias]);
 956                  }
 957  
 958                  // Check if the tables that we need exist
 959                  $src_db->sql_return_on_error(true);
 960                  foreach ($tables_list as $table => $null)
 961                  {
 962                      $sql = 'SELECT 1 FROM ' . $table;
 963                      $_result = $src_db->sql_query_limit($sql, 1);
 964  
 965                      if (!$_result)
 966                      {
 967                          $missing_tables[] = $table;
 968                      }
 969                      $src_db->sql_freeresult($_result);
 970                  }
 971                  $src_db->sql_return_on_error(false);
 972  
 973                  // Throw an error if some tables are missing
 974                  // We used to do some guessing here, but since we have a suggestion of possible values earlier, I don't see it adding anything here to do it again
 975  
 976                  if (sizeof($missing_tables) == sizeof($tables_list))
 977                  {
 978                      $this->p_master->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
 979                  }
 980                  else if (sizeof($missing_tables))
 981                  {
 982                      $this->p_master->error(sprintf($user->lang['TABLES_MISSING'], implode($user->lang['COMMA_SEPARATOR'], $missing_tables)) . '<br /><br />' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
 983                  }
 984  
 985                  $url = $this->save_convert_progress('&amp;confirm=1');
 986                  $msg = $user->lang['PRE_CONVERT_COMPLETE'];
 987  
 988                  if ($convert->convertor_data['author_notes'])
 989                  {
 990                      $msg .= '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
 991                  }
 992  
 993                  $template->assign_vars(array(
 994                      'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
 995                      'L_MESSAGE'        => $msg,
 996                      'U_ACTION'        => $url,
 997                  ));
 998  
 999                  return;
1000              } // if (!$request->variable('confirm', false)))
1001  
1002              $template->assign_block_vars('checks', array(
1003                  'S_LEGEND'        => true,
1004                  'LEGEND'        => $user->lang['STARTING_CONVERT'],
1005              ));
1006  
1007              // Convert the config table and load the settings of the old board
1008              if (!empty($convert->config_schema))
1009              {
1010                  restore_config($convert->config_schema);
1011  
1012                  // Override a couple of config variables for the duration
1013                  $config['max_quote_depth'] = 0;
1014  
1015                  // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
1016                  $config['max_post_chars'] = $config['min_post_chars'] = 0;
1017              }
1018  
1019              $template->assign_block_vars('checks', array(
1020                  'TITLE'        => $user->lang['CONFIG_CONVERT'],
1021                  'RESULT'    => $user->lang['DONE'],
1022              ));
1023  
1024              // Now process queries and execute functions that have to be executed prior to the conversion
1025              if (!empty($convert->convertor['execute_first']))
1026              {
1027                  // @codingStandardsIgnoreStart
1028                  eval($convert->convertor['execute_first']);
1029                  // @codingStandardsIgnoreEnd
1030              }
1031  
1032              if (!empty($convert->convertor['query_first']))
1033              {
1034                  if (!is_array($convert->convertor['query_first']))
1035                  {
1036                      $convert->convertor['query_first'] = array('target', array($convert->convertor['query_first']));
1037                  }
1038                  else if (!is_array($convert->convertor['query_first'][0]))
1039                  {
1040                      $convert->convertor['query_first'] = array(array($convert->convertor['query_first'][0], $convert->convertor['query_first'][1]));
1041                  }
1042  
1043                  foreach ($convert->convertor['query_first'] as $query_first)
1044                  {
1045                      if ($query_first[0] == 'src')
1046                      {
1047                          if ($convert->mysql_convert && $same_db)
1048                          {
1049                              $src_db->sql_query("SET NAMES 'binary'");
1050                          }
1051  
1052                          $src_db->sql_query($query_first[1]);
1053  
1054                          if ($convert->mysql_convert && $same_db)
1055                          {
1056                              $src_db->sql_query("SET NAMES 'utf8'");
1057                          }
1058                      }
1059                      else
1060                      {
1061                          $db->sql_query($query_first[1]);
1062                      }
1063                  }
1064              }
1065  
1066              $template->assign_block_vars('checks', array(
1067                  'TITLE'        => $user->lang['PREPROCESS_STEP'],
1068                  'RESULT'    => $user->lang['DONE'],
1069              ));
1070          } // if (!$current_table && !$skip_rows)
1071  
1072          $template->assign_block_vars('checks', array(
1073              'S_LEGEND'        => true,
1074              'LEGEND'        => $user->lang['FILLING_TABLES'],
1075          ));
1076  
1077          // This loop takes one target table and processes it
1078          while ($current_table < sizeof($convert->convertor['schema']))
1079          {
1080              $schema = $convert->convertor['schema'][$current_table];
1081  
1082              // The target table isn't set, this can be because a module (for example the attachement mod) is taking care of this.
1083              if (empty($schema['target']))
1084              {
1085                  $current_table++;
1086                  continue;
1087              }
1088  
1089              $template->assign_block_vars('checks', array(
1090                  'TITLE'    => sprintf($user->lang['FILLING_TABLE'], $schema['target']),
1091              ));
1092  
1093              // This is only the case when we first start working on the tables.
1094              if (!$skip_rows)
1095              {
1096                  // process execute_first and query_first for this table...
1097                  if (!empty($schema['execute_first']))
1098                  {
1099                      // @codingStandardsIgnoreStart
1100                      eval($schema['execute_first']);
1101                      // @codingStandardsIgnoreEnd
1102                  }
1103  
1104                  if (!empty($schema['query_first']))
1105                  {
1106                      if (!is_array($schema['query_first']))
1107                      {
1108                          $schema['query_first'] = array('target', array($schema['query_first']));
1109                      }
1110                      else if (!is_array($schema['query_first'][0]))
1111                      {
1112                          $schema['query_first'] = array(array($schema['query_first'][0], $schema['query_first'][1]));
1113                      }
1114  
1115                      foreach ($schema['query_first'] as $query_first)
1116                      {
1117                          if ($query_first[0] == 'src')
1118                          {
1119                              if ($convert->mysql_convert && $same_db)
1120                              {
1121                                  $src_db->sql_query("SET NAMES 'binary'");
1122                              }
1123                              $src_db->sql_query($query_first[1]);
1124                              if ($convert->mysql_convert && $same_db)
1125                              {
1126                                  $src_db->sql_query("SET NAMES 'utf8'");
1127                              }
1128                          }
1129                          else
1130                          {
1131                              $db->sql_query($query_first[1]);
1132                          }
1133                      }
1134                  }
1135  
1136                  if (!empty($schema['autoincrement']))
1137                  {
1138                      switch ($db->get_sql_layer())
1139                      {
1140                          case 'postgres':
1141                              $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
1142                          break;
1143  
1144                          case 'oracle':
1145                              $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
1146                              $row = $db->sql_fetchrow($result);
1147                              $db->sql_freeresult($result);
1148  
1149                              $largest_id = (int) $row['max_id'];
1150  
1151                              if ($largest_id)
1152                              {
1153                                  $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
1154                                  $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
1155                              }
1156                          break;
1157                      }
1158                  }
1159              }
1160  
1161              // Process execute_always for this table
1162              // This is for code which needs to be executed on every pass of this table if
1163              // it gets split because of time restrictions
1164              if (!empty($schema['execute_always']))
1165              {
1166                  // @codingStandardsIgnoreStart
1167                  eval($schema['execute_always']);
1168                  // @codingStandardsIgnoreEnd
1169              }
1170  
1171              //
1172              // Set up some variables
1173              //
1174              // $waiting_rows    holds rows for multirows insertion (MySQL only)
1175              // $src_tables        holds unique tables with aliases to select from
1176              // $src_fields        will quickly refer source fields (or aliases) corresponding to the current index
1177              // $select_fields    holds the names of the fields to retrieve
1178              //
1179  
1180              $sql_data = array(
1181                  'source_fields'        => array(),
1182                  'target_fields'        => array(),
1183                  'source_tables'        => array(),
1184                  'select_fields'        => array(),
1185              );
1186  
1187              // This statement is building the keys for later insertion.
1188              $insert_query = $this->build_insert_query($schema, $sql_data, $current_table);
1189  
1190              // If no source table is affected, we skip the table
1191              if (empty($sql_data['source_tables']))
1192              {
1193                  $skip_rows = 0;
1194                  $current_table++;
1195                  continue;
1196              }
1197  
1198              $distinct = (!empty($schema['distinct'])) ? 'DISTINCT ' : '';
1199  
1200              $sql = 'SELECT ' . $distinct . implode(', ', $sql_data['select_fields']) . " \nFROM " . implode(', ', $sql_data['source_tables']);
1201  
1202              // Where
1203              $sql .= (!empty($schema['where'])) ? "\nWHERE (" . $schema['where'] . ')' : '';
1204  
1205              // Group By
1206              if (!empty($schema['group_by']))
1207              {
1208                  $schema['group_by'] = array($schema['group_by']);
1209                  foreach ($sql_data['select_fields'] as $select)
1210                  {
1211                      $alias = strpos(strtolower($select), ' as ');
1212                      $select = ($alias) ? substr($select, 0, $alias) : $select;
1213                      if (!in_array($select, $schema['group_by']))
1214                      {
1215                          $schema['group_by'][] = $select;
1216                      }
1217                  }
1218              }
1219              $sql .= (!empty($schema['group_by'])) ? "\nGROUP BY " . implode(', ', $schema['group_by']) : '';
1220  
1221              // Having
1222              $sql .= (!empty($schema['having'])) ? "\nHAVING " . $schema['having'] : '';
1223  
1224              // Order By
1225              if (empty($schema['order_by']) && !empty($schema['primary']))
1226              {
1227                  $schema['order_by'] = $schema['primary'];
1228              }
1229              $sql .= (!empty($schema['order_by'])) ? "\nORDER BY " . $schema['order_by'] : '';
1230  
1231              // Counting basically holds the amount of rows processed.
1232              $counting = -1;
1233              $batch_time = 0;
1234  
1235              while ($counting === -1 || ($counting >= $convert->batch_size && still_on_time()))
1236              {
1237                  $old_current_table = $current_table;
1238  
1239                  $rows = '';
1240                  $waiting_rows = array();
1241  
1242                  if (!empty($batch_time))
1243                  {
1244                      $mtime = explode(' ', microtime());
1245                      $mtime = $mtime[0] + $mtime[1];
1246                      $rows = ceil($counting/($mtime - $batch_time)) . " rows/s ($counting rows) | ";
1247                  }
1248  
1249                  $template->assign_block_vars('checks', array(
1250                      'TITLE'        => "skip_rows = $skip_rows",
1251                      'RESULT'    => $rows . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] : ''),
1252                  ));
1253  
1254                  $mtime = explode(' ', microtime());
1255                  $batch_time = $mtime[0] + $mtime[1];
1256  
1257                  if ($convert->mysql_convert && $same_db)
1258                  {
1259                      $src_db->sql_query("SET NAMES 'binary'");
1260                  }
1261  
1262                  // Take skip rows into account and only fetch batch_size amount of rows
1263                  $___result = $src_db->sql_query_limit($sql, $convert->batch_size, $skip_rows);
1264  
1265                  if ($convert->mysql_convert && $same_db)
1266                  {
1267                      $src_db->sql_query("SET NAMES 'utf8'");
1268                  }
1269  
1270                  // This loop processes each row
1271                  $counting = 0;
1272  
1273                  $convert->row = $convert_row = array();
1274  
1275                  if (!empty($schema['autoincrement']))
1276                  {
1277                      switch ($db->get_sql_layer())
1278                      {
1279                          case 'mssql':
1280                          case 'mssql_odbc':
1281                          case 'mssqlnative':
1282                              $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' ON');
1283                          break;
1284                      }
1285                  }
1286  
1287                  // Now handle the rows until time is over or no more rows to process...
1288                  while ($counting === 0 || still_on_time())
1289                  {
1290                      $convert_row = $src_db->sql_fetchrow($___result);
1291  
1292                      if (!$convert_row)
1293                      {
1294                          // move to the next batch or table
1295                          break;
1296                      }
1297  
1298                      // With this we are able to always save the last state
1299                      $convert->row = $convert_row;
1300  
1301                      // Increment the counting variable, it stores the number of rows we have processed
1302                      $counting++;
1303  
1304                      $insert_values = array();
1305  
1306                      $sql_flag = $this->process_row($schema, $sql_data, $insert_values);
1307  
1308                      if ($sql_flag === true)
1309                      {
1310                          switch ($db->get_sql_layer())
1311                          {
1312                              // If MySQL, we'll wait to have num_wait_rows rows to submit at once
1313                              case 'mysql':
1314                              case 'mysql4':
1315                              case 'mysqli':
1316                                  $waiting_rows[] = '(' . implode(', ', $insert_values) . ')';
1317  
1318                                  if (sizeof($waiting_rows) >= $convert->num_wait_rows)
1319                                  {
1320                                      $errored = false;
1321  
1322                                      $db->sql_return_on_error(true);
1323  
1324                                      if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
1325                                      {
1326                                          $errored = true;
1327                                      }
1328                                      $db->sql_return_on_error(false);
1329  
1330                                      if ($errored)
1331                                      {
1332                                          $db->sql_return_on_error(true);
1333  
1334                                          // Because it errored out we will try to insert the rows one by one... most of the time this
1335                                          // is caused by duplicate entries - but we also do not want to miss one...
1336                                          foreach ($waiting_rows as $waiting_sql)
1337                                          {
1338                                              if (!$db->sql_query($insert_query . $waiting_sql))
1339                                              {
1340                                                  $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
1341                                              }
1342                                          }
1343  
1344                                          $db->sql_return_on_error(false);
1345                                      }
1346  
1347                                      $waiting_rows = array();
1348                                  }
1349  
1350                              break;
1351  
1352                              default:
1353                                  $insert_sql = $insert_query . '(' . implode(', ', $insert_values) . ')';
1354  
1355                                  $db->sql_return_on_error(true);
1356  
1357                                  if (!$db->sql_query($insert_sql))
1358                                  {
1359                                      $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
1360                                  }
1361                                  $db->sql_return_on_error(false);
1362  
1363                                  $waiting_rows = array();
1364  
1365                              break;
1366                          }
1367                      }
1368  
1369                      $skip_rows++;
1370                  }
1371                  $src_db->sql_freeresult($___result);
1372  
1373                  // We might still have some rows waiting
1374                  if (sizeof($waiting_rows))
1375                  {
1376                      $errored = false;
1377                      $db->sql_return_on_error(true);
1378  
1379                      if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
1380                      {
1381                          $errored = true;
1382                      }
1383                      $db->sql_return_on_error(false);
1384  
1385                      if ($errored)
1386                      {
1387                          $db->sql_return_on_error(true);
1388  
1389                          // Because it errored out we will try to insert the rows one by one... most of the time this
1390                          // is caused by duplicate entries - but we also do not want to miss one...
1391                          foreach ($waiting_rows as $waiting_sql)
1392                          {
1393                              $db->sql_query($insert_query . $waiting_sql);
1394                              $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
1395                          }
1396  
1397                          $db->sql_return_on_error(false);
1398                      }
1399  
1400                      $waiting_rows = array();
1401                  }
1402  
1403                  if (!empty($schema['autoincrement']))
1404                  {
1405                      switch ($db->get_sql_layer())
1406                      {
1407                          case 'mssql':
1408                          case 'mssql_odbc':
1409                          case 'mssqlnative':
1410                              $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' OFF');
1411                          break;
1412  
1413                          case 'postgres':
1414                              $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
1415                          break;
1416  
1417                          case 'oracle':
1418                              $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
1419                              $row = $db->sql_fetchrow($result);
1420                              $db->sql_freeresult($result);
1421  
1422                              $largest_id = (int) $row['max_id'];
1423  
1424                              if ($largest_id)
1425                              {
1426                                  $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
1427                                  $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
1428                              }
1429                          break;
1430                      }
1431                  }
1432              }
1433  
1434              // When we reach this point, either the current table has been processed or we're running out of time.
1435              if (still_on_time() && $counting < $convert->batch_size/* && !defined('DEBUG')*/)
1436              {
1437                  $skip_rows = 0;
1438                  $current_table++;
1439              }
1440              else
1441              {/*
1442                  if (still_on_time() && $counting < $convert->batch_size)
1443                  {
1444                      $skip_rows = 0;
1445                      $current_table++;
1446                  }*/
1447  
1448                  // Looks like we ran out of time.
1449                  $url = $this->save_convert_progress('&amp;current_table=' . $current_table . '&amp;skip_rows=' . $skip_rows);
1450  
1451                  $current_table++;
1452  //                $percentage = ($skip_rows == 0) ? 0 : floor(100 / ($total_rows / $skip_rows));
1453  
1454                  $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $current_table, sizeof($convert->convertor['schema']));
1455  
1456                  $template->assign_vars(array(
1457                      'L_MESSAGE'        => $msg,
1458                      'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1459                      'U_ACTION'        => $url,
1460                  ));
1461  
1462                  $this->meta_refresh($url);
1463                  return;
1464              }
1465          }
1466  
1467          // Process execute_last then we'll be done
1468          $url = $this->save_convert_progress('&amp;jump=1');
1469  
1470          $template->assign_vars(array(
1471              'L_SUBMIT'        => $user->lang['FINAL_STEP'],
1472              'U_ACTION'        => $url,
1473          ));
1474  
1475          $this->meta_refresh($url);
1476          return;
1477      }
1478  
1479      /**
1480      * Sync function being executed at the middle, some functions need to be executed after a successful sync.
1481      */
1482  	function sync_forums($sync_batch)
1483      {
1484          global $template, $user, $db, $phpbb_root_path, $phpEx, $config, $cache;
1485          global $convert;
1486  
1487          $template->assign_block_vars('checks', array(
1488              'S_LEGEND'    => true,
1489              'LEGEND'    => $user->lang['SYNC_TOPICS'],
1490          ));
1491  
1492          $batch_size = $convert->batch_size;
1493  
1494          $sql = 'SELECT MIN(topic_id) as min_value, MAX(topic_id) AS max_value
1495              FROM ' . TOPICS_TABLE;
1496          $result = $db->sql_query($sql);
1497          $row = $db->sql_fetchrow($result);
1498          $db->sql_freeresult($result);
1499  
1500          // Set values of minimum/maximum primary value for this table.
1501          $primary_min = $row['min_value'];
1502          $primary_max = $row['max_value'];
1503  
1504          if ($sync_batch == 0)
1505          {
1506              $sync_batch = (int) $primary_min;
1507          }
1508  
1509          if ($sync_batch == 0)
1510          {
1511              $sync_batch = 1;
1512          }
1513  
1514          // Fetch a batch of rows, process and insert them.
1515          while ($sync_batch <= $primary_max && still_on_time())
1516          {
1517              $end = ($sync_batch + $batch_size - 1);
1518  
1519              // Sync all topics in batch mode...
1520              sync('topic', 'range', 'topic_id BETWEEN ' . $sync_batch . ' AND ' . $end, true, true);
1521  
1522              $template->assign_block_vars('checks', array(
1523                  'TITLE'        => sprintf($user->lang['SYNC_TOPIC_ID'], $sync_batch, ($sync_batch + $batch_size)) . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ' [' . ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] . ']' : ''),
1524                  'RESULT'    => $user->lang['DONE'],
1525              ));
1526  
1527              $sync_batch += $batch_size;
1528          }
1529  
1530          if ($sync_batch >= $primary_max)
1531          {
1532              $url = $this->save_convert_progress('&amp;final_jump=1');
1533  
1534              $template->assign_vars(array(
1535                  'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1536                  'U_ACTION'        => $url,
1537              ));
1538  
1539              $this->meta_refresh($url);
1540              return;
1541          }
1542          else
1543          {
1544              $sync_batch--;
1545          }
1546  
1547          $url = $this->save_convert_progress('&amp;sync_batch=' . $sync_batch);
1548  
1549          $template->assign_vars(array(
1550              'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1551              'U_ACTION'        => $url,
1552          ));
1553  
1554          $this->meta_refresh($url);
1555          return;
1556      }
1557  
1558      /**
1559      * Save the convertor status
1560      */
1561  	function save_convert_progress($step)
1562      {
1563          global $convert, $language;
1564  
1565          // Save convertor Status
1566          set_config('convert_progress', serialize(array(
1567              'step'            => $step,
1568              'table_prefix'    => $convert->src_table_prefix,
1569              'tag'            => $convert->convertor_tag,
1570          )), true);
1571  
1572          set_config('convert_db_server', serialize(array(
1573              'dbms'            => $convert->src_dbms,
1574              'dbhost'        => $convert->src_dbhost,
1575              'dbport'        => $convert->src_dbport,
1576              'dbname'        => $convert->src_dbname,
1577          )), true);
1578  
1579          set_config('convert_db_user', serialize(array(
1580              'dbuser'        => $convert->src_dbuser,
1581              'dbpasswd'        => $convert->src_dbpasswd,
1582          )), true);
1583  
1584          return $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step&amp;language=$language";
1585      }
1586  
1587      /**
1588      * Finish conversion, the last function to be called.
1589      */
1590  	function finish_conversion()
1591      {
1592          global $db, $phpbb_root_path, $phpEx, $convert, $config, $language, $user, $template;
1593          global $cache, $auth, $phpbb_container, $phpbb_log;
1594  
1595          $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
1596              WHERE config_name = 'convert_progress'
1597                  OR config_name = 'convert_options'
1598                  OR config_name = 'convert_db_server'
1599                  OR config_name = 'convert_db_user'");
1600          $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
1601  
1602          @unlink($phpbb_root_path . 'cache/data_global.' . $phpEx);
1603          phpbb_cache_moderators($db, $cache, $auth);
1604  
1605          // And finally, add a note to the log
1606          $phpbb_log = $phpbb_container->get('log');
1607          add_log('admin', 'LOG_INSTALL_CONVERTED', $convert->convertor_data['forum_name'], $config['version']);
1608  
1609          $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=final&amp;language=$language";
1610  
1611          $template->assign_vars(array(
1612              'L_SUBMIT'        => $user->lang['FINAL_STEP'],
1613              'U_ACTION'        => $url,
1614          ));
1615  
1616          $this->meta_refresh($url);
1617          return;
1618      }
1619  
1620      /**
1621      * This function marks the steps after syncing
1622      */
1623  	function final_jump($final_jump)
1624      {
1625          global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
1626          global $convert;
1627  
1628          $template->assign_block_vars('checks', array(
1629              'S_LEGEND'    => true,
1630              'LEGEND'    => $user->lang['PROCESS_LAST'],
1631          ));
1632  
1633          if ($final_jump == 1)
1634          {
1635              $db->sql_return_on_error(true);
1636  
1637              update_topics_posted();
1638  
1639              $template->assign_block_vars('checks', array(
1640                  'TITLE'        => $user->lang['UPDATE_TOPICS_POSTED'],
1641                  'RESULT'    => $user->lang['DONE'],
1642              ));
1643  
1644              if ($db->get_sql_error_triggered())
1645              {
1646                  $template->assign_vars(array(
1647                      'S_ERROR_BOX'    => true,
1648                      'ERROR_TITLE'    => $user->lang['UPDATE_TOPICS_POSTED'],
1649                      'ERROR_MSG'        => $user->lang['UPDATE_TOPICS_POSTED_ERR'],
1650                  ));
1651              }
1652              $db->sql_return_on_error(false);
1653  
1654              $this->finish_conversion();
1655              return;
1656          }
1657      }
1658  
1659      /**
1660      * This function marks the steps before syncing (jump=1)
1661      */
1662  	function jump($jump, $last_statement)
1663      {
1664          global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
1665          global $convert;
1666  
1667          $template->assign_block_vars('checks', array(
1668              'S_LEGEND'    => true,
1669              'LEGEND'    => $user->lang['PROCESS_LAST'],
1670          ));
1671  
1672          if ($jump == 1)
1673          {
1674              // Execute 'last' statements/queries
1675              if (!empty($convert->convertor['execute_last']))
1676              {
1677                  if (!is_array($convert->convertor['execute_last']))
1678                  {
1679                      // @codingStandardsIgnoreStart
1680                      eval($convert->convertor['execute_last']);
1681                      // @codingStandardsIgnoreEnd
1682                  }
1683                  else
1684                  {
1685                      while ($last_statement < sizeof($convert->convertor['execute_last']))
1686                      {
1687                          // @codingStandardsIgnoreStart
1688                          eval($convert->convertor['execute_last'][$last_statement]);
1689                          // @codingStandardsIgnoreEnd
1690  
1691                          $template->assign_block_vars('checks', array(
1692                              'TITLE'        => $convert->convertor['execute_last'][$last_statement],
1693                              'RESULT'    => $user->lang['DONE'],
1694                          ));
1695  
1696                          $last_statement++;
1697                          $url = $this->save_convert_progress('&amp;jump=1&amp;last=' . $last_statement);
1698  
1699                          $percentage = ($last_statement == 0) ? 0 : floor(100 / (sizeof($convert->convertor['execute_last']) / $last_statement));
1700                          $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $last_statement, sizeof($convert->convertor['execute_last']), $percentage);
1701  
1702                          $template->assign_vars(array(
1703                              'L_SUBMIT'        => $user->lang['CONTINUE_LAST'],
1704                              'L_MESSAGE'        => $msg,
1705                              'U_ACTION'        => $url,
1706                          ));
1707  
1708                          $this->meta_refresh($url);
1709                          return;
1710                      }
1711                  }
1712              }
1713  
1714              if (!empty($convert->convertor['query_last']))
1715              {
1716                  if (!is_array($convert->convertor['query_last']))
1717                  {
1718                      $convert->convertor['query_last'] = array('target', array($convert->convertor['query_last']));
1719                  }
1720                  else if (!is_array($convert->convertor['query_last'][0]))
1721                  {
1722                      $convert->convertor['query_last'] = array(array($convert->convertor['query_last'][0], $convert->convertor['query_last'][1]));
1723                  }
1724  
1725                  foreach ($convert->convertor['query_last'] as $query_last)
1726                  {
1727                      if ($query_last[0] == 'src')
1728                      {
1729                          if ($convert->mysql_convert && $same_db)
1730                          {
1731                              $src_db->sql_query("SET NAMES 'binary'");
1732                          }
1733  
1734                          $src_db->sql_query($query_last[1]);
1735  
1736                          if ($convert->mysql_convert && $same_db)
1737                          {
1738                              $src_db->sql_query("SET NAMES 'utf8'");
1739                          }
1740                      }
1741                      else
1742                      {
1743                          $db->sql_query($query_last[1]);
1744                      }
1745                  }
1746              }
1747  
1748              // Sanity check
1749              $db->sql_return_on_error(false);
1750              $src_db->sql_return_on_error(false);
1751  
1752              fix_empty_primary_groups();
1753  
1754              $sql = 'SELECT MIN(user_regdate) AS board_startdate
1755                  FROM ' . USERS_TABLE;
1756              $result = $db->sql_query($sql);
1757              $row = $db->sql_fetchrow($result);
1758              $db->sql_freeresult($result);
1759  
1760              if (!isset($config['board_startdate']) || ($row['board_startdate'] < $config['board_startdate'] && $row['board_startdate'] > 0))
1761              {
1762                  set_config('board_startdate', $row['board_startdate']);
1763                  $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_regdate = ' . $row['board_startdate'] . ' WHERE user_id = ' . ANONYMOUS);
1764              }
1765  
1766              update_dynamic_config();
1767  
1768              $template->assign_block_vars('checks', array(
1769                  'TITLE'        => $user->lang['CLEAN_VERIFY'],
1770                  'RESULT'    => $user->lang['DONE'],
1771              ));
1772  
1773              $url = $this->save_convert_progress('&amp;jump=2');
1774  
1775              $template->assign_vars(array(
1776                  'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1777                  'U_ACTION'        => $url,
1778              ));
1779  
1780              $this->meta_refresh($url);
1781              return;
1782          }
1783  
1784          if ($jump == 2)
1785          {
1786              $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_permissions = ''");
1787  
1788              // TODO: sync() is likely going to bomb out on forums with a considerable amount of topics.
1789              // TODO: the sync function is able to handle FROM-TO values, we should use them here (batch processing)
1790              sync('forum', '', '', false, true);
1791              $cache->destroy('sql', FORUMS_TABLE);
1792  
1793              $template->assign_block_vars('checks', array(
1794                  'TITLE'        => $user->lang['SYNC_FORUMS'],
1795                  'RESULT'    => $user->lang['DONE'],
1796              ));
1797  
1798              // Continue with synchronizing the forums...
1799              $url = $this->save_convert_progress('&amp;sync_batch=0');
1800  
1801              $template->assign_vars(array(
1802                  'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1803                  'U_ACTION'        => $url,
1804              ));
1805  
1806              $this->meta_refresh($url);
1807              return;
1808          }
1809      }
1810  
1811  	function build_insert_query(&$schema, &$sql_data, $current_table)
1812      {
1813          global $db, $user;
1814          global $convert;
1815  
1816          // Can we use IGNORE with this DBMS?
1817          $sql_ignore = (strpos($db->get_sql_layer(), 'mysql') === 0 && !defined('DEBUG')) ? 'IGNORE ' : '';
1818          $insert_query = 'INSERT ' . $sql_ignore . 'INTO ' . $schema['target'] . ' (';
1819  
1820          $aliases = array();
1821  
1822          $sql_data = array(
1823              'source_fields'        => array(),
1824              'target_fields'        => array(),
1825              'source_tables'        => array(),
1826              'select_fields'        => array(),
1827          );
1828  
1829          foreach ($schema as $key => $val)
1830          {
1831              // Example: array('group_name',                'extension_groups.group_name',        'htmlspecialchars'),
1832              if (is_int($key))
1833              {
1834                  if (!empty($val[0]))
1835                  {
1836                      // Target fields
1837                      $sql_data['target_fields'][$val[0]] = $key;
1838                      $insert_query .= $val[0] . ', ';
1839                  }
1840  
1841                  if (!is_array($val[1]))
1842                  {
1843                      $val[1] = array($val[1]);
1844                  }
1845  
1846                  foreach ($val[1] as $valkey => $value_1)
1847                  {
1848                      // This should cover about any case:
1849                      //
1850                      // table.field                    => SELECT table.field                FROM table
1851                      // table.field AS alias            => SELECT table.field    AS alias    FROM table
1852                      // table.field AS table2.alias    => SELECT table2.field    AS alias    FROM table table2
1853                      // table.field AS table2.field    => SELECT table2.field                FROM table table2
1854                      //
1855                      if (preg_match('/^([a-z0-9_]+)\.([a-z0-9_]+)( +AS +(([a-z0-9_]+?)\.)?([a-z0-9_]+))?$/i', $value_1, $m))
1856                      {
1857                          // There is 'AS ...' in the field names
1858                          if (!empty($m[3]))
1859                          {
1860                              $value_1 = ($m[2] == $m[6]) ? $m[1] . '.' . $m[2] : $m[1] . '.' . $m[2] . ' AS ' . $m[6];
1861  
1862                              // Table alias: store it then replace the source table with it
1863                              if (!empty($m[5]) && $m[5] != $m[1])
1864                              {
1865                                  $aliases[$m[5]] = $m[1];
1866                                  $value_1 = str_replace($m[1] . '.' . $m[2], $m[5] . '.' . $m[2], $value_1);
1867                              }
1868                          }
1869                          else
1870                          {
1871                              // No table alias
1872                              $sql_data['source_tables'][$m[1]] = (empty($convert->src_table_prefix)) ? $m[1] : $convert->src_table_prefix . $m[1] . ' ' . $m[1];
1873                          }
1874  
1875                          $sql_data['select_fields'][$value_1] = $value_1;
1876                          $sql_data['source_fields'][$key][$valkey] = (!empty($m[6])) ? $m[6] : $m[2];
1877                      }
1878                  }
1879              }
1880              else if ($key == 'where' || $key == 'group_by' || $key == 'order_by' || $key == 'having')
1881              {
1882                  if (@preg_match_all('/([a-z0-9_]+)\.([a-z0-9_]+)/i', $val, $m))
1883                  {
1884                      foreach ($m[1] as $value)
1885                      {
1886                          $sql_data['source_tables'][$value] = (empty($convert->src_table_prefix)) ? $value : $convert->src_table_prefix . $value . ' ' . $value;
1887                      }
1888                  }
1889              }
1890          }
1891  
1892          // Add the aliases to the list of tables
1893          foreach ($aliases as $alias => $table)
1894          {
1895              $sql_data['source_tables'][$alias] = $convert->src_table_prefix . $table . ' ' . $alias;
1896          }
1897  
1898          // 'left_join'        => 'forums LEFT JOIN forum_prune ON forums.forum_id = forum_prune.forum_id',
1899          if (!empty($schema['left_join']))
1900          {
1901              if (!is_array($schema['left_join']))
1902              {
1903                  $schema['left_join'] = array($schema['left_join']);
1904              }
1905  
1906              foreach ($schema['left_join'] as $left_join)
1907              {
1908                  // This won't handle concatened LEFT JOINs
1909                  if (!preg_match('/([a-z0-9_]+) LEFT JOIN ([a-z0-9_]+) A?S? ?([a-z0-9_]*?) ?(ON|USING)(.*)/i', $left_join, $m))
1910                  {
1911                      $this->p_master->error(sprintf($user->lang['NOT_UNDERSTAND'], 'LEFT JOIN', $left_join, $current_table, $schema['target']), __LINE__, __FILE__);
1912                  }
1913  
1914                  if (!empty($aliases[$m[2]]))
1915                  {
1916                      if (!empty($m[3]))
1917                      {
1918                          $this->p_master->error(sprintf($user->lang['NAMING_CONFLICT'], $m[2], $m[3], $schema['left_join']), __LINE__, __FILE__);
1919                      }
1920  
1921                      $m[2] = $aliases[$m[2]];
1922                      $m[3] = $m[2];
1923                  }
1924  
1925                  $right_table = $convert->src_table_prefix . $m[2];
1926                  if (!empty($m[3]))
1927                  {
1928                      unset($sql_data['source_tables'][$m[3]]);
1929                  }
1930                  else if ($m[2] != $m[1])
1931                  {
1932                      unset($sql_data['source_tables'][$m[2]]);
1933                  }
1934  
1935                  if (strpos($sql_data['source_tables'][$m[1]], "\nLEFT JOIN") !== false)
1936                  {
1937                      $sql_data['source_tables'][$m[1]] = '(' . $sql_data['source_tables'][$m[1]] . ")\nLEFT JOIN $right_table";
1938                  }
1939                  else
1940                  {
1941                      $sql_data['source_tables'][$m[1]] .= "\nLEFT JOIN $right_table";
1942                  }
1943  
1944                  if (!empty($m[3]))
1945                  {
1946                      unset($sql_data['source_tables'][$m[3]]);
1947                      $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[3];
1948                  }
1949                  else if (!empty($convert->src_table_prefix))
1950                  {
1951                      $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[2];
1952                  }
1953                  $sql_data['source_tables'][$m[1]] .= ' ' . $m[4] . $m[5];
1954              }
1955          }
1956  
1957          // Remove ", " from the end of the insert query
1958          $insert_query = substr($insert_query, 0, -2) . ') VALUES ';
1959  
1960          return $insert_query;
1961      }
1962  
1963      /**
1964      * Function for processing the currently handled row
1965      */
1966  	function process_row(&$schema, &$sql_data, &$insert_values)
1967      {
1968          global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache;
1969          global $convert, $convert_row;
1970  
1971          $sql_flag = false;
1972  
1973          foreach ($schema as $key => $fields)
1974          {
1975              // We are only interested in the lines with:
1976              // array('comment', 'attachments_desc.comment', 'htmlspecialchars'),
1977              if (is_int($key))
1978              {
1979                  if (!is_array($fields[1]))
1980                  {
1981                      $fields[1] = array($fields[1]);
1982                  }
1983  
1984                  $firstkey_set = false;
1985                  $firstkey = 0;
1986  
1987                  foreach ($fields[1] as $inner_key => $inner_value)
1988                  {
1989                      if (!$firstkey_set)
1990                      {
1991                          $firstkey = $inner_key;
1992                          $firstkey_set = true;
1993                      }
1994  
1995                      $src_field = isset($sql_data['source_fields'][$key][$inner_key]) ? $sql_data['source_fields'][$key][$inner_key] : '';
1996  
1997                      if (!empty($src_field))
1998                      {
1999                          $fields[1][$inner_key] = $convert->row[$src_field];
2000                      }
2001                  }
2002  
2003                  if (!empty($fields[0]))
2004                  {
2005                      // We have a target field, if we haven't set $sql_flag yet it will be set to TRUE.
2006                      // If a function has already set it to FALSE it won't change it.
2007                      if ($sql_flag === false)
2008                      {
2009                          $sql_flag = true;
2010                      }
2011  
2012                      // No function assigned?
2013                      if (empty($fields[2]))
2014                      {
2015                          $value = $fields[1][$firstkey];
2016                      }
2017                      else if (is_array($fields[2]) && !is_callable($fields[2]))
2018                      {
2019                          // Execute complex function/eval/typecast
2020                          $value = $fields[1];
2021  
2022                          foreach ($fields[2] as $type => $execution)
2023                          {
2024                              if (strpos($type, 'typecast') === 0)
2025                              {
2026                                  if (!is_array($value))
2027                                  {
2028                                      $value = array($value);
2029                                  }
2030                                  $value = $value[0];
2031                                  settype($value, $execution);
2032                              }
2033                              else if (strpos($type, 'function') === 0)
2034                              {
2035                                  if (!is_array($value))
2036                                  {
2037                                      $value = array($value);
2038                                  }
2039  
2040                                  $value = call_user_func_array($execution, $value);
2041                              }
2042                              else if (strpos($type, 'execute') === 0)
2043                              {
2044                                  if (!is_array($value))
2045                                  {
2046                                      $value = array($value);
2047                                  }
2048  
2049                                  $execution = str_replace('{RESULT}', '$value', $execution);
2050                                  $execution = str_replace('{VALUE}', '$value', $execution);
2051                                  // @codingStandardsIgnoreStart
2052                                  eval($execution);
2053                                  // @codingStandardsIgnoreEnd
2054                              }
2055                          }
2056                      }
2057                      else
2058                      {
2059                          $value = call_user_func_array($fields[2], $fields[1]);
2060                      }
2061  
2062                      if (is_null($value))
2063                      {
2064                          $value = '';
2065                      }
2066  
2067                      $insert_values[] = $db->_sql_validate_value($value);
2068                  }
2069                  else if (!empty($fields[2]))
2070                  {
2071                      if (is_array($fields[2]))
2072                      {
2073                          // Execute complex function/eval/typecast
2074                          $value = '';
2075  
2076                          foreach ($fields[2] as $type => $execution)
2077                          {
2078                              if (strpos($type, 'typecast') === 0)
2079                              {
2080                                  $value = settype($value, $execution);
2081                              }
2082                              else if (strpos($type, 'function') === 0)
2083                              {
2084                                  if (!is_array($value))
2085                                  {
2086                                      $value = array($value);
2087                                  }
2088  
2089                                  $value = call_user_func_array($execution, $value);
2090                              }
2091                              else if (strpos($type, 'execute') === 0)
2092                              {
2093                                  if (!is_array($value))
2094                                  {
2095                                      $value = array($value);
2096                                  }
2097  
2098                                  $execution = str_replace('{RESULT}', '$value', $execution);
2099                                  $execution = str_replace('{VALUE}', '$value', $execution);
2100                                  // @codingStandardsIgnoreStart
2101                                  eval($execution);
2102                                  // @codingStandardsIgnoreEnd
2103                              }
2104                          }
2105                      }
2106                      else
2107                      {
2108                          call_user_func_array($fields[2], $fields[1]);
2109                      }
2110                  }
2111              }
2112          }
2113  
2114          return $sql_flag;
2115      }
2116  
2117      /**
2118      * Own meta refresh function to be able to change the global time used
2119      */
2120  	function meta_refresh($url)
2121      {
2122          global $convert, $template;
2123  
2124          if ($convert->options['refresh'])
2125          {
2126              // Because we should not rely on correct settings, we simply use the relative path here directly.
2127              $template->assign_vars(array(
2128                  'S_REFRESH'    => true,
2129                  'META'        => '<meta http-equiv="refresh" content="5; url=' . $url . '" />')
2130              );
2131          }
2132      }
2133  
2134      /**
2135      * The information below will be used to build the input fields presented to the user
2136      */
2137      var $convert_options = array(
2138          'legend1'            => 'SPECIFY_OPTIONS',
2139          'src_dbms'            => array('lang' => 'DBMS',            'type' => 'select', 'options' => 'dbms_select(\'{VALUE}\', true)', 'explain' => false),
2140          'src_dbhost'        => array('lang' => 'DB_HOST',        'type' => 'text:25:100', 'explain' => true),
2141          'src_dbport'        => array('lang' => 'DB_PORT',        'type' => 'text:25:100', 'explain' => true),
2142          'src_dbname'        => array('lang' => 'DB_NAME',        'type' => 'text:25:100', 'explain' => false),
2143          'src_dbuser'        => array('lang' => 'DB_USERNAME',    'type' => 'text:25:100', 'explain' => false),
2144          'src_dbpasswd'        => array('lang' => 'DB_PASSWORD',    'type' => 'password:25:100', 'explain' => false),
2145          'src_table_prefix'    => array('lang' => 'TABLE_PREFIX',    'type' => 'text:25:100', 'explain' => false),
2146          //'src_url'            => array('lang' => 'FORUM_ADDRESS',    'type' => 'text:50:100', 'explain' => true),
2147          'forum_path'        => array('lang' => 'FORUM_PATH',    'type' => 'text:25:100', 'explain' => true),
2148          'refresh'            => array('lang' => 'REFRESH_PAGE',    'type' => 'radio:yes_no', 'explain' => true),
2149      );
2150  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1