Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

install_convert.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 62.77 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  /**
0015  */
0016   
0017  if (!defined('IN_INSTALL'))
0018  {
0019      // Someone has tried to access the file direct. This is not a good idea, so exit
0020      exit;
0021  }
0022   
0023  if (!empty($setmodules))
0024  {
0025      $module[] = array(
0026          'module_type'        => 'install',
0027          'module_title'        => 'CONVERT',
0028          'module_filename'    => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
0029          'module_order'        => 20,
0030          'module_subs'        => '',
0031          'module_stages'        => array('INTRO', 'SETTINGS', 'IN_PROGRESS', 'FINAL'),
0032          'module_reqs'        => ''
0033      );
0034  }
0035   
0036  /**
0037  * Class holding all convertor-specific details.
0038  */
0039  class convert
0040  {
0041      var $options = array();
0042   
0043      var $convertor_tag = '';
0044      var $src_dbms = '';
0045      var $src_dbhost = '';
0046      var $src_dbport = '';
0047      var $src_dbuser = '';
0048      var $src_dbpasswd = '';
0049      var $src_dbname = '';
0050      var $src_table_prefix = '';
0051   
0052      var $convertor_data = array();
0053      var $tables = array();
0054      var $config_schema = array();
0055      var $convertor = array();
0056      var $src_truncate_statement = 'DELETE FROM ';
0057      var $truncate_statement = 'DELETE FROM ';
0058   
0059      var $fulltext_search;
0060   
0061      // Batch size, can be adjusted by the conversion file
0062      // For big boards a value of 6000 seems to be optimal
0063      var $batch_size = 2000;
0064      // Number of rows to be inserted at once (extended insert) if supported
0065      // For installations having enough memory a value of 60 may be good.
0066      var $num_wait_rows = 20;
0067   
0068      // Mysqls internal recoding engine messing up with our (better) functions? We at least support more encodings than mysql so should use it in favor.
0069      var $mysql_convert = false;
0070   
0071      var $p_master;
0072   
0073      function convert(&$p_master)
0074      {
0075          $this->p_master = &$p_master;
0076      }
0077  }
0078   
0079  /**
0080  * Convert class for conversions
0081  */
0082  class install_convert extends module
0083  {
0084      /** @var array */
0085      protected $lang;
0086   
0087      /** @var string */
0088      protected $language;
0089   
0090      /** @var \phpbb\template\template */
0091      protected $template;
0092   
0093      /** @var string */
0094      protected $phpbb_root_path;
0095   
0096      /** @var string */
0097      protected $php_ext;
0098   
0099      /**
0100      * Variables used while converting, they are accessible from the global variable $convert
0101      */
0102      function install_convert(&$p_master)
0103      {
0104          $this->p_master = &$p_master;
0105      }
0106   
0107      function main($mode, $sub)
0108      {
0109          global $lang, $template, $phpbb_root_path, $phpEx, $cache, $config, $language, $table_prefix;
0110          global $convert, $request, $phpbb_container, $phpbb_config_php_file;
0111   
0112          $this->tpl_name = 'install_convert';
0113          $this->mode = $mode;
0114          $this->lang = $lang;
0115          $this->language = $language;
0116          $this->template = $template;
0117          $this->phpbb_root_path = $phpbb_root_path;
0118          $this->php_ext = $phpEx;
0119   
0120          if (!$this->check_phpbb_installed())
0121          {
0122              return;
0123          }
0124   
0125          $convert = new convert($this->p_master);
0126   
0127          // Enable super globals to prevent issues with the new \phpbb\request\request object
0128          $request->enable_super_globals();
0129          // Create a normal container now
0130          $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
0131          $phpbb_container = $phpbb_container_builder->get_container();
0132   
0133          // Create cache
0134          $cache = $phpbb_container->get('cache');
0135   
0136          switch ($sub)
0137          {
0138              case 'intro':
0139                  extract($phpbb_config_php_file->get_all());
0140   
0141                  require($phpbb_root_path . 'includes/constants.' . $phpEx);
0142                  require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0143   
0144                  $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
0145   
0146                  $db = new $dbms();
0147                  $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0148                  unset($dbpasswd);
0149   
0150                  // We need to fill the config to let internal functions correctly work
0151                  $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
0152                  set_config(null, null, null, $config);
0153                  set_config_count(null, null, null, $config);
0154   
0155                  // Detect if there is already a conversion in progress at this point and offer to resume
0156                  // It's quite possible that the user will get disconnected during a large conversion so they need to be able to resume it
0157                  $new_conversion = request_var('new_conv', 0);
0158   
0159                  if ($new_conversion)
0160                  {
0161                      $config['convert_progress'] = '';
0162                      $config['convert_db_server'] = '';
0163                      $config['convert_db_user'] = '';
0164                      $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
0165                          WHERE config_name = 'convert_progress'
0166                              OR config_name = 'convert_db_server'
0167                              OR config_name = 'convert_db_user'"
0168                      );
0169                  }
0170   
0171                  // Let's see if there is a conversion in the works...
0172                  $options = array();
0173                  if (!empty($config['convert_progress']) && !empty($config['convert_db_server']) && !empty($config['convert_db_user']) && !empty($config['convert_options']))
0174                  {
0175                      $options = unserialize($config['convert_progress']);
0176                      $options = array_merge($options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
0177                  }
0178   
0179                  // This information should have already been checked once, but do it again for safety
0180                  if (!empty($options) && !empty($options['tag']) &&
0181                      isset($options['dbms']) &&
0182                      isset($options['dbhost']) &&
0183                      isset($options['dbport']) &&
0184                      isset($options['dbuser']) &&
0185                      isset($options['dbpasswd']) &&
0186                      isset($options['dbname']) &&
0187                      isset($options['table_prefix']))
0188                  {
0189                      $this->page_title = $lang['CONTINUE_CONVERT'];
0190   
0191                      $template->assign_vars(array(
0192                          'TITLE'            => $lang['CONTINUE_CONVERT'],
0193                          'BODY'            => $lang['CONTINUE_CONVERT_BODY'],
0194                          'L_NEW'            => $lang['CONVERT_NEW_CONVERSION'],
0195                          'L_CONTINUE'    => $lang['CONTINUE_OLD_CONVERSION'],
0196                          'S_CONTINUE'    => true,
0197   
0198                          'U_NEW_ACTION'        => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=intro&amp;new_conv=1&amp;language=$language",
0199                          'U_CONTINUE_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$options['tag']}{$options['step']}&amp;language=$language",
0200                      ));
0201   
0202                      return;
0203                  }
0204   
0205                  $this->list_convertors($sub);
0206   
0207              break;
0208   
0209              case 'settings':
0210                  $this->get_convert_settings($sub);
0211              break;
0212   
0213              case 'in_progress':
0214                  $this->convert_data($sub);
0215              break;
0216   
0217              case 'final':
0218                  $this->page_title = $lang['CONVERT_COMPLETE'];
0219   
0220                  $template->assign_vars(array(
0221                      'TITLE'        => $lang['CONVERT_COMPLETE'],
0222                      'BODY'        => $lang['CONVERT_COMPLETE_EXPLAIN'],
0223                  ));
0224   
0225                  // If we reached this step (conversion completed) we want to purge the cache and log the user out.
0226                  // This is for making sure the session get not screwed due to the 3.0.x users table being completely new.
0227                  $cache->purge();
0228   
0229                  extract($phpbb_config_php_file->get_all());
0230   
0231                  require($phpbb_root_path . 'includes/constants.' . $phpEx);
0232                  require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0233   
0234                  $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
0235   
0236                  $db = new $dbms();
0237                  $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0238                  unset($dbpasswd);
0239   
0240                  $sql = 'SELECT config_value
0241                      FROM ' . CONFIG_TABLE . '
0242                      WHERE config_name = \'search_type\'';
0243                  $result = $db->sql_query($sql);
0244   
0245                  if ($db->sql_fetchfield('config_value') != 'fulltext_mysql')
0246                  {
0247                      $template->assign_vars(array(
0248                          'S_ERROR_BOX'    => true,
0249                          'ERROR_TITLE'    => $lang['SEARCH_INDEX_UNCONVERTED'],
0250                          'ERROR_MSG'        => $lang['SEARCH_INDEX_UNCONVERTED_EXPLAIN'],
0251                      ));
0252                  }
0253   
0254                  switch ($db->get_sql_layer())
0255                  {
0256                      case 'sqlite':
0257                      case 'sqlite3':
0258                          $db->sql_query('DELETE FROM ' . SESSIONS_KEYS_TABLE);
0259                          $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
0260                      break;
0261   
0262                      default:
0263                          $db->sql_query('TRUNCATE TABLE ' . SESSIONS_KEYS_TABLE);
0264                          $db->sql_query('TRUNCATE TABLE ' . SESSIONS_TABLE);
0265                      break;
0266                  }
0267   
0268              break;
0269          }
0270      }
0271   
0272      /**
0273      * Check whether phpBB is installed.
0274      * Assigns error template vars if not installed.
0275      *
0276      * @return bool Returns true if phpBB is installed.
0277      */
0278      public function check_phpbb_installed()
0279      {
0280          if (phpbb_check_installation_exists($this->phpbb_root_path, $this->php_ext))
0281          {
0282              return true;
0283          }
0284   
0285          $this->page_title = 'BOARD_NOT_INSTALLED';
0286          $install_url = append_sid($this->phpbb_root_path . 'install/index.' . $this->php_ext, 'mode=install&amp;language=' . $this->language);
0287   
0288          $this->template->assign_vars(array(
0289              'S_NOT_INSTALLED'        => true,
0290              'BODY'                    => sprintf($this->lang['BOARD_NOT_INSTALLED_EXPLAIN'], $install_url),
0291          ));
0292   
0293          return false;
0294      }
0295   
0296      /**
0297      * Generate a list of all available conversion modules
0298      */
0299      function list_convertors($sub)
0300      {
0301          global $lang, $language, $template, $phpbb_root_path, $phpEx;
0302   
0303          $this->page_title = $lang['SUB_INTRO'];
0304   
0305          $template->assign_vars(array(
0306              'TITLE'        => $lang['CONVERT_INTRO'],
0307              'BODY'        => $lang['CONVERT_INTRO_BODY'],
0308   
0309              'L_AUTHOR'                    => $lang['AUTHOR'],
0310              'L_AVAILABLE_CONVERTORS'    => $lang['AVAILABLE_CONVERTORS'],
0311              'L_CONVERT'                    => $lang['CONVERT'],
0312              'L_NO_CONVERTORS'            => $lang['NO_CONVERTORS'],
0313              'L_OPTIONS'                    => $lang['CONVERT_OPTIONS'],
0314              'L_SOFTWARE'                => $lang['SOFTWARE'],
0315              'L_VERSION'                    => $lang['VERSION'],
0316   
0317              'S_LIST'    => true,
0318          ));
0319   
0320          $convertors = $sort = array();
0321          $get_info = true;
0322   
0323          $handle = @opendir('./convertors/');
0324   
0325          if (!$handle)
0326          {
0327              $this->error('Unable to access the convertors directory', __LINE__, __FILE__);
0328          }
0329   
0330          while ($entry = readdir($handle))
0331          {
0332              if (preg_match('/^convert_([a-z0-9_]+).' . $phpEx . '$/i', $entry, $m))
0333              {
0334                  include('./convertors/' . $entry);
0335                  if (isset($convertor_data))
0336                  {
0337                      $sort[strtolower($convertor_data['forum_name'])] = sizeof($convertors);
0338   
0339                      $convertors[] = array(
0340                          'tag'            =>    $m[1],
0341                          'forum_name'    =>    $convertor_data['forum_name'],
0342                          'version'        =>    $convertor_data['version'],
0343                          'dbms'            =>    $convertor_data['dbms'],
0344                          'dbhost'        =>    $convertor_data['dbhost'],
0345                          'dbport'        =>    $convertor_data['dbport'],
0346                          'dbuser'        =>    $convertor_data['dbuser'],
0347                          'dbpasswd'        =>    $convertor_data['dbpasswd'],
0348                          'dbname'        =>    $convertor_data['dbname'],
0349                          'table_prefix'    =>    $convertor_data['table_prefix'],
0350                          'author'        =>    $convertor_data['author']
0351                      );
0352                  }
0353                  unset($convertor_data);
0354              }
0355          }
0356          closedir($handle);
0357   
0358          @ksort($sort);
0359   
0360          foreach ($sort as $void => $index)
0361          {
0362              $template->assign_block_vars('convertors', array(
0363                  'AUTHOR'    => $convertors[$index]['author'],
0364                  'SOFTWARE'    => $convertors[$index]['forum_name'],
0365                  'VERSION'    => $convertors[$index]['version'],
0366   
0367                  'U_CONVERT'    => $this->p_master->module_url . "?mode={$this->mode}&amp;language=$language&amp;sub=settings&amp;tag=" . $convertors[$index]['tag'],
0368              ));
0369          }
0370      }
0371   
0372      /**
0373      */
0374      function get_convert_settings($sub)
0375      {
0376          global $lang, $language, $template, $db, $phpbb_root_path, $phpEx, $config, $cache, $phpbb_config_php_file;
0377   
0378          extract($phpbb_config_php_file->get_all());
0379   
0380          require($phpbb_root_path . 'includes/constants.' . $phpEx);
0381          require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0382   
0383          $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
0384   
0385          $db = new $dbms();
0386          $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0387          unset($dbpasswd);
0388   
0389          $this->page_title = $lang['STAGE_SETTINGS'];
0390   
0391          // We need to fill the config to let internal functions correctly work
0392          $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
0393          set_config(null, null, null, $config);
0394          set_config_count(null, null, null, $config);
0395   
0396          $convertor_tag = request_var('tag', '');
0397   
0398          if (empty($convertor_tag))
0399          {
0400              $this->p_master->error($lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
0401          }
0402          $get_info = true;
0403   
0404          // check security implications of direct inclusion
0405          $convertor_tag = basename($convertor_tag);
0406          if (!file_exists('./convertors/convert_' . $convertor_tag . '.' . $phpEx))
0407          {
0408              $this->p_master->error($lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
0409          }
0410   
0411          include('./convertors/convert_' . $convertor_tag . '.' . $phpEx);
0412   
0413          // The test_file is a file that should be present in the location of the old board.
0414          if (!isset($test_file))
0415          {
0416              $this->p_master->error($lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
0417          }
0418   
0419          $submit = (isset($_POST['submit'])) ? true : false;
0420   
0421          $src_dbms            = request_var('src_dbms', $convertor_data['dbms']);
0422          $src_dbhost            = request_var('src_dbhost', $convertor_data['dbhost']);
0423          $src_dbport            = request_var('src_dbport', $convertor_data['dbport']);
0424          $src_dbuser            = request_var('src_dbuser', $convertor_data['dbuser']);
0425          $src_dbpasswd        = request_var('src_dbpasswd', $convertor_data['dbpasswd']);
0426          $src_dbname            = request_var('src_dbname', $convertor_data['dbname']);
0427          $src_table_prefix    = request_var('src_table_prefix', $convertor_data['table_prefix']);
0428          $forum_path            = request_var('forum_path', $convertor_data['forum_path']);
0429          $refresh            = request_var('refresh', 1);
0430   
0431          // Default URL of the old board
0432          // @todo Are we going to use this for attempting to convert URL references in posts, or should we remove it?
0433          //        -> We should convert old urls to the new relative urls format
0434          // $src_url = request_var('src_url', 'Not in use at the moment');
0435   
0436          // strip trailing slash from old forum path
0437          $forum_path = (strlen($forum_path) && $forum_path[strlen($forum_path) - 1] == '/') ? substr($forum_path, 0, -1) : $forum_path;
0438   
0439          $error = array();
0440          if ($submit)
0441          {
0442              if (!@file_exists('./../' . $forum_path . '/' . $test_file))
0443              {
0444                  $error[] = sprintf($lang['COULD_NOT_FIND_PATH'], $forum_path);
0445              }
0446   
0447              $connect_test = false;
0448              $available_dbms = get_available_dbms(false, true, true);
0449   
0450              if (!isset($available_dbms[$src_dbms]) || !$available_dbms[$src_dbms]['AVAILABLE'])
0451              {
0452                  $error[] = $lang['INST_ERR_NO_DB'];
0453                  $connect_test = false;
0454              }
0455              else
0456              {
0457                  $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);
0458              }
0459   
0460              // The forum prefix of the old and the new forum can only be the same if two different databases are used.
0461              if ($src_table_prefix == $table_prefix && $src_dbms == $dbms && $src_dbhost == $dbhost && $src_dbport == $dbport && $src_dbname == $dbname)
0462              {
0463                  $error[] = sprintf($lang['TABLE_PREFIX_SAME'], $src_table_prefix);
0464              }
0465   
0466              $src_dbms = $phpbb_config_php_file->convert_30_dbms_to_31($src_dbms);
0467   
0468              // Check table prefix
0469              if (!sizeof($error))
0470              {
0471                  // initiate database connection to old db if old and new db differ
0472                  global $src_db, $same_db;
0473                  $src_db = $same_db = false;
0474   
0475                  if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser)
0476                  {
0477                      $src_db = new $src_dbms();
0478                      $src_db->sql_connect($src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, false, true);
0479                      $same_db = false;
0480                  }
0481                  else
0482                  {
0483                      $src_db = $db;
0484                      $same_db = true;
0485                  }
0486   
0487                  $src_db->sql_return_on_error(true);
0488                  $db->sql_return_on_error(true);
0489   
0490                  // Try to select one row from the first table to see if the prefix is OK
0491                  $result = $src_db->sql_query_limit('SELECT * FROM ' . $src_table_prefix . $tables[0], 1);
0492   
0493                  if (!$result)
0494                  {
0495                      $prefixes = array();
0496   
0497                      $tables_existing = get_tables($src_db);
0498                      $tables_existing = array_map('strtolower', $tables_existing);
0499                      foreach ($tables_existing as $table_name)
0500                      {
0501                          compare_table($tables, $table_name, $prefixes);
0502                      }
0503                      unset($tables_existing);
0504   
0505                      foreach ($prefixes as $prefix => $count)
0506                      {
0507                          if ($count >= sizeof($tables))
0508                          {
0509                              $possible_prefix = $prefix;
0510                              break;
0511                          }
0512                      }
0513   
0514                      $msg = '';
0515                      if (!empty($convertor_data['table_prefix']))
0516                      {
0517                          $msg .= sprintf($lang['DEFAULT_PREFIX_IS'], $convertor_data['forum_name'], $convertor_data['table_prefix']);
0518                      }
0519   
0520                      if (!empty($possible_prefix))
0521                      {
0522                          $msg .= '<br />';
0523                          $msg .= ($possible_prefix == '*') ? $lang['BLANK_PREFIX_FOUND'] : sprintf($lang['PREFIX_FOUND'], $possible_prefix);
0524                          $src_table_prefix = ($possible_prefix == '*') ? '' : $possible_prefix;
0525                      }
0526   
0527                      $error[] = $msg;
0528                  }
0529                  $src_db->sql_freeresult($result);
0530                  $src_db->sql_return_on_error(false);
0531              }
0532   
0533              if (!sizeof($error))
0534              {
0535                  // Save convertor Status
0536                  set_config('convert_progress', serialize(array(
0537                      'step'            => '',
0538                      'table_prefix'    => $src_table_prefix,
0539                      'tag'            => $convertor_tag,
0540                  )), true);
0541                  set_config('convert_db_server', serialize(array(
0542                      'dbms'            => $src_dbms,
0543                      'dbhost'        => $src_dbhost,
0544                      'dbport'        => $src_dbport,
0545                      'dbname'        => $src_dbname,
0546                  )), true);
0547                  set_config('convert_db_user', serialize(array(
0548                      'dbuser'        => $src_dbuser,
0549                      'dbpasswd'        => $src_dbpasswd,
0550                  )), true);
0551   
0552                  // Save options
0553                  set_config('convert_options', serialize(array('forum_path' => './../' . $forum_path, 'refresh' => $refresh)), true);
0554   
0555                  $template->assign_block_vars('checks', array(
0556                      'TITLE'        => $lang['VERIFY_OPTIONS'],
0557                      'RESULT'    => $lang['CONVERT_SETTINGS_VERIFIED'],
0558                  ));
0559   
0560                  $template->assign_vars(array(
0561                      'L_SUBMIT'    => $lang['BEGIN_CONVERT'],
0562  //                    'S_HIDDEN'    => $s_hidden_fields,
0563                      'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag=$convertor_tag&amp;language=$language",
0564                  ));
0565   
0566                  return;
0567              }
0568              else
0569              {
0570                  $template->assign_block_vars('checks', array(
0571                      'TITLE'        => $lang['VERIFY_OPTIONS'],
0572                      'RESULT'    => '<b style="color:red">' . implode('<br />', $error) . '</b>',
0573                  ));
0574              }
0575          } // end submit
0576   
0577          foreach ($this->convert_options as $config_key => $vars)
0578          {
0579              if (!is_array($vars) && strpos($config_key, 'legend') === false)
0580              {
0581                  continue;
0582              }
0583   
0584              if (strpos($config_key, 'legend') !== false)
0585              {
0586                  $template->assign_block_vars('options', array(
0587                      'S_LEGEND'        => true,
0588                      'LEGEND'        => $lang[$vars])
0589                  );
0590   
0591                  continue;
0592              }
0593   
0594              $options = isset($vars['options']) ? $vars['options'] : '';
0595   
0596              $template->assign_block_vars('options', array(
0597                  'KEY'            => $config_key,
0598                  'TITLE'            => $lang[$vars['lang']],
0599                  'S_EXPLAIN'        => $vars['explain'],
0600                  'S_LEGEND'        => false,
0601                  'TITLE_EXPLAIN'    => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
0602                  'CONTENT'        => $this->p_master->input_field($config_key, $vars['type'], $$config_key, $options),
0603                  )
0604              );
0605          }
0606   
0607          $template->assign_vars(array(
0608              'TITLE'        => $lang['STAGE_SETTINGS'],
0609              'BODY'        => $lang['CONV_OPTIONS_BODY'],
0610              'L_SUBMIT'    => $lang['BEGIN_CONVERT'],
0611              'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=settings&amp;tag=$convertor_tag&amp;language=$language",
0612          ));
0613      }
0614   
0615      /**
0616      * The function which does the actual work (or dispatches it to the relevant places)
0617      */
0618      function convert_data($sub)
0619      {
0620          global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache, $auth;
0621          global $convert, $convert_row, $message_parser, $skip_rows, $language;
0622          global $request, $phpbb_config_php_file;
0623   
0624          extract($phpbb_config_php_file->get_all());
0625   
0626          require($phpbb_root_path . 'includes/constants.' . $phpEx);
0627          require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0628   
0629          $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
0630   
0631          $db = new $dbms();
0632          $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0633          unset($dbpasswd);
0634   
0635          // We need to fill the config to let internal functions correctly work
0636          $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
0637          set_config(null, null, null, $config);
0638          set_config_count(null, null, null, $config);
0639   
0640          // Override a couple of config variables for the duration
0641          $config['max_quote_depth'] = 0;
0642   
0643          // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
0644          $config['max_post_chars'] = $config['min_post_chars'] = 0;
0645   
0646          // Set up a user as well. We _should_ have enough of a database here at this point to do this
0647          // and it helps for any core code we call
0648          $user->session_begin();
0649          $user->page = $user->extract_current_page($phpbb_root_path);
0650   
0651          // This is a little bit of a fudge, but it allows the language entries to be available to the
0652          // core code without us loading them again
0653          $user->lang = &$lang;
0654   
0655          $this->page_title = $user->lang['STAGE_IN_PROGRESS'];
0656   
0657          $convert->options = array();
0658          if (isset($config['convert_progress']))
0659          {
0660              $convert->options = unserialize($config['convert_progress']);
0661              $convert->options = array_merge($convert->options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
0662          }
0663   
0664          // This information should have already been checked once, but do it again for safety
0665          if (empty($convert->options) || empty($convert->options['tag']) ||
0666              !isset($convert->options['dbms']) ||
0667              !isset($convert->options['dbhost']) ||
0668              !isset($convert->options['dbport']) ||
0669              !isset($convert->options['dbuser']) ||
0670              !isset($convert->options['dbpasswd']) ||
0671              !isset($convert->options['dbname']) ||
0672              !isset($convert->options['table_prefix']))
0673          {
0674              $this->p_master->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
0675          }
0676   
0677          // Make some short variables accessible, for easier referencing
0678          $convert->convertor_tag = basename($convert->options['tag']);
0679          $convert->src_dbms = $convert->options['dbms'];
0680          $convert->src_dbhost = $convert->options['dbhost'];
0681          $convert->src_dbport = $convert->options['dbport'];
0682          $convert->src_dbuser = $convert->options['dbuser'];
0683          $convert->src_dbpasswd = $convert->options['dbpasswd'];
0684          $convert->src_dbname = $convert->options['dbname'];
0685          $convert->src_table_prefix = $convert->options['table_prefix'];
0686   
0687          // initiate database connection to old db if old and new db differ
0688          global $src_db, $same_db;
0689          $src_db = $same_db = null;
0690          if ($convert->src_dbms != $dbms || $convert->src_dbhost != $dbhost || $convert->src_dbport != $dbport || $convert->src_dbname != $dbname || $convert->src_dbuser != $dbuser)
0691          {
0692              $dbms = $convert->src_dbms;
0693              $src_db = new $dbms();
0694              $src_db->sql_connect($convert->src_dbhost, $convert->src_dbuser, htmlspecialchars_decode($convert->src_dbpasswd), $convert->src_dbname, $convert->src_dbport, false, true);
0695              $same_db = false;
0696          }
0697          else
0698          {
0699              $src_db = $db;
0700              $same_db = true;
0701          }
0702   
0703          $convert->mysql_convert = false;
0704          switch ($src_db->sql_layer)
0705          {
0706              case 'sqlite':
0707              case 'sqlite3':
0708                  $convert->src_truncate_statement = 'DELETE FROM ';
0709              break;
0710   
0711              // Thanks MySQL, for silently converting...
0712              case 'mysql':
0713              case 'mysql4':
0714                  if (version_compare($src_db->sql_server_info(true, false), '4.1.3', '>='))
0715                  {
0716                      $convert->mysql_convert = true;
0717                  }
0718                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
0719              break;
0720   
0721              case 'mysqli':
0722                  $convert->mysql_convert = true;
0723                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
0724              break;
0725   
0726              default:
0727                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
0728              break;
0729          }
0730   
0731          if ($convert->mysql_convert && !$same_db)
0732          {
0733              $src_db->sql_query("SET NAMES 'binary'");
0734          }
0735   
0736          switch ($db->get_sql_layer())
0737          {
0738              case 'sqlite':
0739              case 'sqlite3':
0740                  $convert->truncate_statement = 'DELETE FROM ';
0741              break;
0742   
0743              default:
0744                  $convert->truncate_statement = 'TRUNCATE TABLE ';
0745              break;
0746          }
0747   
0748          $get_info = false;
0749   
0750          // check security implications of direct inclusion
0751          if (!file_exists('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx))
0752          {
0753              $this->p_master->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
0754          }
0755   
0756          if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx))
0757          {
0758              include('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx);
0759          }
0760   
0761          $get_info = true;
0762          include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
0763   
0764          // Map some variables...
0765          $convert->convertor_data = $convertor_data;
0766          $convert->tables = $tables;
0767          $convert->config_schema = $config_schema;
0768   
0769          // Now include the real data
0770          $get_info = false;
0771          include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
0772   
0773          $convert->convertor_data = $convertor_data;
0774          $convert->tables = $tables;
0775          $convert->config_schema = $config_schema;
0776          $convert->convertor = $convertor;
0777   
0778          // The test_file is a file that should be present in the location of the old board.
0779          if (!file_exists($convert->options['forum_path'] . '/' . $test_file))
0780          {
0781              $this->p_master->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->options['forum_path']), __LINE__, __FILE__);
0782          }
0783   
0784          $search_type = $config['search_type'];
0785   
0786          // For conversions we are a bit less strict and set to a search backend we know exist...
0787          if (!class_exists($search_type))
0788          {
0789              $search_type = '\phpbb\search\fulltext_native';
0790              set_config('search_type', $search_type);
0791          }
0792   
0793          if (!class_exists($search_type))
0794          {
0795              trigger_error('NO_SUCH_SEARCH_MODULE');
0796          }
0797   
0798          $error = false;
0799          $convert->fulltext_search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user);
0800   
0801          if ($error)
0802          {
0803              trigger_error($error);
0804          }
0805   
0806          include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
0807          $message_parser = new parse_message();
0808   
0809          $jump = request_var('jump', 0);
0810          $final_jump = request_var('final_jump', 0);
0811          $sync_batch = request_var('sync_batch', -1);
0812          $last_statement = request_var('last', 0);
0813   
0814          // We are running sync...
0815          if ($sync_batch >= 0)
0816          {
0817              $this->sync_forums($sync_batch);
0818              return;
0819          }
0820   
0821          if ($jump)
0822          {
0823              $this->jump($jump, $last_statement);
0824              return;
0825          }
0826   
0827          if ($final_jump)
0828          {
0829              $this->final_jump($final_jump);
0830              return;
0831          }
0832   
0833          $current_table = request_var('current_table', 0);
0834          $old_current_table = min(-1, $current_table - 1);
0835          $skip_rows = request_var('skip_rows', 0);
0836   
0837          if (!$current_table && !$skip_rows)
0838          {
0839              if (!$request->variable('confirm', false))
0840              {
0841                  // If avatars / ranks / smilies folders are specified make sure they are writable
0842                  $bad_folders = array();
0843   
0844                  $local_paths = array(
0845                      'avatar_path'            => path($config['avatar_path']),
0846                      'avatar_gallery_path'    => path($config['avatar_gallery_path']),
0847                      'icons_path'            => path($config['icons_path']),
0848                      'ranks_path'            => path($config['ranks_path']),
0849                      'smilies_path'            => path($config['smilies_path'])
0850                  );
0851   
0852                  foreach ($local_paths as $folder => $local_path)
0853                  {
0854                      if (isset($convert->convertor[$folder]))
0855                      {
0856                          if (empty($convert->convertor['test_file']))
0857                          {
0858                              // test_file is mandantory at the moment so this should never be reached, but just in case...
0859                              $this->p_master->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
0860                          }
0861   
0862                          if (!$local_path || !phpbb_is_writable($phpbb_root_path . $local_path))
0863                          {
0864                              if (!$local_path)
0865                              {
0866                                  $bad_folders[] = sprintf($user->lang['CONFIG_PHPBB_EMPTY'], $folder);
0867                              }
0868                              else
0869                              {
0870                                  $bad_folders[] = $local_path;
0871                              }
0872                          }
0873                      }
0874                  }
0875   
0876                  if (sizeof($bad_folders))
0877                  {
0878                      $msg = (sizeof($bad_folders) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
0879                      sort($bad_folders);
0880                      $this->p_master->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true);
0881   
0882                      $template->assign_vars(array(
0883                          'L_SUBMIT'    => $user->lang['INSTALL_TEST'],
0884                          'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}&amp;language=$language",
0885                      ));
0886                      return;
0887                  }
0888   
0889                  // Grab all the tables used in convertor
0890                  $missing_tables = $tables_list = $aliases = array();
0891   
0892                  foreach ($convert->convertor['schema'] as $schema)
0893                  {
0894                      // Skip those not used (because of addons/plugins not detected)
0895                      if (!$schema['target'])
0896                      {
0897                          continue;
0898                      }
0899   
0900                      foreach ($schema as $key => $val)
0901                      {
0902                          // we're dealing with an array like:
0903                          // array('forum_status',            'forums.forum_status',                'is_item_locked')
0904                          if (is_int($key) && !empty($val[1]))
0905                          {
0906                              $temp_data = $val[1];
0907                              if (!is_array($temp_data))
0908                              {
0909                                  $temp_data = array($temp_data);
0910                              }
0911   
0912                              foreach ($temp_data as $val)
0913                              {
0914                                  if (preg_match('/([a-z0-9_]+)\.([a-z0-9_]+)\)* ?A?S? ?([a-z0-9_]*?)\.?([a-z0-9_]*)$/i', $val, $m))
0915                                  {
0916                                      $table = $convert->src_table_prefix . $m[1];
0917                                      $tables_list[$table] = $table;
0918   
0919                                      if (!empty($m[3]))
0920                                      {
0921                                          $aliases[] = $convert->src_table_prefix . $m[3];
0922                                      }
0923                                  }
0924                              }
0925                          }
0926                          // 'left_join'        => 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1'
0927                          else if ($key == 'left_join')
0928                          {
0929                              // Convert the value if it wasn't an array already.
0930                              if (!is_array($val))
0931                              {
0932                                  $val = array($val);
0933                              }
0934   
0935                              for ($j = 0; $j < sizeof($val); ++$j)
0936                              {
0937                                  if (preg_match('/LEFT JOIN ([a-z0-9_]+) AS ([a-z0-9_]+)/i', $val[$j], $m))
0938                                  {
0939                                      $table = $convert->src_table_prefix . $m[1];
0940                                      $tables_list[$table] = $table;
0941   
0942                                      if (!empty($m[2]))
0943                                      {
0944                                          $aliases[] = $convert->src_table_prefix . $m[2];
0945                                      }
0946                                  }
0947                              }
0948                          }
0949                      }
0950                  }
0951   
0952                  // Remove aliased tables from $tables_list
0953                  foreach ($aliases as $alias)
0954                  {
0955                      unset($tables_list[$alias]);
0956                  }
0957   
0958                  // Check if the tables that we need exist
0959                  $src_db->sql_return_on_error(true);
0960                  foreach ($tables_list as $table => $null)
0961                  {
0962                      $sql = 'SELECT 1 FROM ' . $table;
0963                      $_result = $src_db->sql_query_limit($sql, 1);
0964   
0965                      if (!$_result)
0966                      {
0967                          $missing_tables[] = $table;
0968                      }
0969                      $src_db->sql_freeresult($_result);
0970                  }
0971                  $src_db->sql_return_on_error(false);
0972   
0973                  // Throw an error if some tables are missing
0974                  // 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
0975   
0976                  if (sizeof($missing_tables) == sizeof($tables_list))
0977                  {
0978                      $this->p_master->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
0979                  }
0980                  else if (sizeof($missing_tables))
0981                  {
0982                      $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__);
0983                  }
0984   
0985                  $url = $this->save_convert_progress('&amp;confirm=1');
0986                  $msg = $user->lang['PRE_CONVERT_COMPLETE'];
0987   
0988                  if ($convert->convertor_data['author_notes'])
0989                  {
0990                      $msg .= '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
0991                  }
0992   
0993                  $template->assign_vars(array(
0994                      'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
0995                      'L_MESSAGE'        => $msg,
0996                      'U_ACTION'        => $url,
0997                  ));
0998   
0999                  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]))
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  }
2151