Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

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:50 - Dateigröße: 61.47 KiB


0001  <?php
0002  /**
0003  *
0004  * @package install
0005  * @version $Id$
0006  * @copyright (c) 2006 phpBB Group
0007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
0008  *
0009  */
0010   
0011  /**
0012  */
0013   
0014  if (!defined('IN_INSTALL'))
0015  {
0016      // Someone has tried to access the file direct. This is not a good idea, so exit
0017      exit;
0018  }
0019   
0020  if (!empty($setmodules))
0021  {
0022      $module[] = array(
0023          'module_type'        => 'install',
0024          'module_title'        => 'CONVERT',
0025          'module_filename'    => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
0026          'module_order'        => 20,
0027          'module_subs'        => '',
0028          'module_stages'        => array('INTRO', 'SETTINGS', 'IN_PROGRESS', 'FINAL'),
0029          'module_reqs'        => ''
0030      );
0031  }
0032   
0033  /**
0034  * Class holding all convertor-specific details.
0035  * @package install
0036  */
0037  class convert
0038  {
0039      var $options = array();
0040   
0041      var $convertor_tag = '';
0042      var $src_dbms = '';
0043      var $src_dbhost = '';
0044      var $src_dbport = '';
0045      var $src_dbuser = '';
0046      var $src_dbpasswd = '';
0047      var $src_dbname = '';
0048      var $src_table_prefix = '';
0049   
0050      var $convertor_data = array();
0051      var $tables = array();
0052      var $config_schema = array();
0053      var $convertor = array();
0054      var $src_truncate_statement = 'DELETE FROM ';
0055      var $truncate_statement = 'DELETE FROM ';
0056   
0057      var $fulltext_search;
0058   
0059      // Batch size, can be adjusted by the conversion file
0060      // For big boards a value of 6000 seems to be optimal
0061      var $batch_size = 2000;
0062      // Number of rows to be inserted at once (extended insert) if supported
0063      // For installations having enough memory a value of 60 may be good.
0064      var $num_wait_rows = 20;
0065   
0066      // Mysqls internal recoding engine messing up with our (better) functions? We at least support more encodings than mysql so should use it in favor.
0067      var $mysql_convert = false;
0068   
0069      var $p_master;
0070   
0071      function convert(&$p_master)
0072      {
0073          $this->p_master = &$p_master;
0074      }
0075  }
0076   
0077  /**
0078  * Convert class for conversions
0079  * @package install
0080  */
0081  class install_convert extends module
0082  {
0083      /**
0084      * Variables used while converting, they are accessible from the global variable $convert
0085      */
0086      function install_convert(&$p_master)
0087      {
0088          $this->p_master = &$p_master;
0089      }
0090   
0091      function main($mode, $sub)
0092      {
0093          global $lang, $template, $phpbb_root_path, $phpEx, $cache, $config, $language, $table_prefix;
0094          global $convert;
0095   
0096          $this->tpl_name = 'install_convert';
0097          $this->mode = $mode;
0098   
0099          $convert = new convert($this->p_master);
0100   
0101          switch ($sub)
0102          {
0103              case 'intro':
0104                  // Try opening config file
0105                  // @todo If phpBB is not installed, we need to do a cut-down installation here
0106                  // For now, we redirect to the installation script instead
0107                  if (@file_exists($phpbb_root_path . 'config.' . $phpEx))
0108                  {
0109                      include($phpbb_root_path . 'config.' . $phpEx);
0110                  }
0111   
0112                  if (!defined('PHPBB_INSTALLED'))
0113                  {
0114                      $template->assign_vars(array(
0115                          'S_NOT_INSTALLED'        => true,
0116                          'TITLE'                    => $lang['BOARD_NOT_INSTALLED'],
0117                          'BODY'                    => sprintf($lang['BOARD_NOT_INSTALLED_EXPLAIN'], append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=install&amp;language=' . $language)),
0118                      ));
0119   
0120                      return;
0121                  }
0122   
0123                  require($phpbb_root_path . 'config.' . $phpEx);
0124                  require($phpbb_root_path . 'includes/constants.' . $phpEx);
0125                  require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
0126                  require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0127   
0128                  $db = new $sql_db();
0129                  $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0130                  unset($dbpasswd);
0131   
0132                  // We need to fill the config to let internal functions correctly work
0133                  $sql = 'SELECT *
0134                      FROM ' . CONFIG_TABLE;
0135                  $result = $db->sql_query($sql);
0136   
0137                  $config = array();
0138                  while ($row = $db->sql_fetchrow($result))
0139                  {
0140                      $config[$row['config_name']] = $row['config_value'];
0141                  }
0142                  $db->sql_freeresult($result);
0143   
0144                  // Detect if there is already a conversion in progress at this point and offer to resume
0145                  // It's quite possible that the user will get disconnected during a large conversion so they need to be able to resume it
0146                  $new_conversion = request_var('new_conv', 0);
0147   
0148                  if ($new_conversion)
0149                  {
0150                      $config['convert_progress'] = '';
0151                      $config['convert_db_server'] = '';
0152                      $config['convert_db_user'] = '';
0153                      $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
0154                          WHERE config_name = 'convert_progress'
0155                              OR config_name = 'convert_db_server'
0156                              OR config_name = 'convert_db_user'"
0157                      );
0158                  }
0159   
0160                  // Let's see if there is a conversion in the works...
0161                  $options = array();
0162                  if (!empty($config['convert_progress']) && !empty($config['convert_db_server']) && !empty($config['convert_db_user']) && !empty($config['convert_options']))
0163                  {
0164                      $options = unserialize($config['convert_progress']);
0165                      $options = array_merge($options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
0166                  }
0167   
0168                  // This information should have already been checked once, but do it again for safety
0169                  if (!empty($options) && !empty($options['tag']) &&
0170                      isset($options['dbms']) &&
0171                      isset($options['dbhost']) &&
0172                      isset($options['dbport']) &&
0173                      isset($options['dbuser']) &&
0174                      isset($options['dbpasswd']) &&
0175                      isset($options['dbname']) &&
0176                      isset($options['table_prefix']))
0177                  {
0178                      $this->page_title = $lang['CONTINUE_CONVERT'];
0179   
0180                      $template->assign_vars(array(
0181                          'TITLE'            => $lang['CONTINUE_CONVERT'],
0182                          'BODY'            => $lang['CONTINUE_CONVERT_BODY'],
0183                          'L_NEW'            => $lang['CONVERT_NEW_CONVERSION'],
0184                          'L_CONTINUE'    => $lang['CONTINUE_OLD_CONVERSION'],
0185                          'S_CONTINUE'    => true,
0186   
0187                          'U_NEW_ACTION'        => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=intro&amp;new_conv=1&amp;language=$language",
0188                          'U_CONTINUE_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$options['tag']}{$options['step']}&amp;language=$language",
0189                      ));
0190   
0191                      return;
0192                  }
0193   
0194                  $this->list_convertors($sub);
0195   
0196              break;
0197   
0198              case 'settings':
0199                  $this->get_convert_settings($sub);
0200              break;
0201   
0202              case 'in_progress':
0203                  $this->convert_data($sub);
0204              break;
0205   
0206              case 'final':
0207                  $this->page_title = $lang['CONVERT_COMPLETE'];
0208   
0209                  $template->assign_vars(array(
0210                      'TITLE'        => $lang['CONVERT_COMPLETE'],
0211                      'BODY'        => $lang['CONVERT_COMPLETE_EXPLAIN'],
0212                  ));
0213   
0214                  // If we reached this step (conversion completed) we want to purge the cache and log the user out.
0215                  // This is for making sure the session get not screwed due to the 3.0.x users table being completely new.
0216                  $cache->purge();
0217   
0218                  require($phpbb_root_path . 'config.' . $phpEx);
0219                  require($phpbb_root_path . 'includes/constants.' . $phpEx);
0220                  require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
0221                  require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0222   
0223                  $db = new $sql_db();
0224                  $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0225                  unset($dbpasswd);
0226   
0227                  $sql = 'SELECT config_value
0228                      FROM ' . CONFIG_TABLE . '
0229                      WHERE config_name = \'search_type\'';
0230                  $result = $db->sql_query($sql);
0231   
0232                  if ($db->sql_fetchfield('config_value') != 'fulltext_mysql')
0233                  {
0234                      $template->assign_vars(array(
0235                          'S_ERROR_BOX'    => true,
0236                          'ERROR_TITLE'    => $lang['SEARCH_INDEX_UNCONVERTED'],
0237                          'ERROR_MSG'        => $lang['SEARCH_INDEX_UNCONVERTED_EXPLAIN'],
0238                      ));
0239                  }
0240   
0241                  switch ($db->sql_layer)
0242                  {
0243                      case 'sqlite':
0244                      case 'firebird':
0245                          $db->sql_query('DELETE FROM ' . SESSIONS_KEYS_TABLE);
0246                          $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
0247                      break;
0248   
0249                      default:
0250                          $db->sql_query('TRUNCATE TABLE ' . SESSIONS_KEYS_TABLE);
0251                          $db->sql_query('TRUNCATE TABLE ' . SESSIONS_TABLE);
0252                      break;
0253                  }
0254   
0255              break;
0256          }
0257      }
0258   
0259      /**
0260      * Generate a list of all available conversion modules
0261      */
0262      function list_convertors($sub)
0263      {
0264          global $lang, $language, $template, $phpbb_root_path, $phpEx;
0265   
0266          $this->page_title = $lang['SUB_INTRO'];
0267   
0268          $template->assign_vars(array(
0269              'TITLE'        => $lang['CONVERT_INTRO'],
0270              'BODY'        => $lang['CONVERT_INTRO_BODY'],
0271   
0272              'L_AUTHOR'                    => $lang['AUTHOR'],
0273              'L_AVAILABLE_CONVERTORS'    => $lang['AVAILABLE_CONVERTORS'],
0274              'L_CONVERT'                    => $lang['CONVERT'],
0275              'L_NO_CONVERTORS'            => $lang['NO_CONVERTORS'],
0276              'L_OPTIONS'                    => $lang['CONVERT_OPTIONS'],
0277              'L_SOFTWARE'                => $lang['SOFTWARE'],
0278              'L_VERSION'                    => $lang['VERSION'],
0279   
0280              'S_LIST'    => true,
0281          ));
0282   
0283          $convertors = $sort = array();
0284          $get_info = true;
0285   
0286          $handle = @opendir('./convertors/');
0287   
0288          if (!$handle)
0289          {
0290              $this->error('Unable to access the convertors directory', __LINE__, __FILE__);
0291          }
0292   
0293          while ($entry = readdir($handle))
0294          {
0295              if (preg_match('/^convert_([a-z0-9_]+).' . $phpEx . '$/i', $entry, $m))
0296              {
0297                  include('./convertors/' . $entry);
0298                  if (isset($convertor_data))
0299                  {
0300                      $sort[strtolower($convertor_data['forum_name'])] = sizeof($convertors);
0301                      
0302                      $convertors[] = array(
0303                          'tag'            =>    $m[1],
0304                          'forum_name'    =>    $convertor_data['forum_name'],
0305                          'version'        =>    $convertor_data['version'],
0306                          'dbms'            =>    $convertor_data['dbms'],
0307                          'dbhost'        =>    $convertor_data['dbhost'],
0308                          'dbport'        =>    $convertor_data['dbport'],
0309                          'dbuser'        =>    $convertor_data['dbuser'],
0310                          'dbpasswd'        =>    $convertor_data['dbpasswd'],
0311                          'dbname'        =>    $convertor_data['dbname'],
0312                          'table_prefix'    =>    $convertor_data['table_prefix'],
0313                          'author'        =>    $convertor_data['author']
0314                      );
0315                  }
0316                  unset($convertor_data);
0317              }
0318          }
0319          closedir($handle);
0320   
0321          @ksort($sort);
0322   
0323          foreach ($sort as $void => $index)
0324          {
0325              $template->assign_block_vars('convertors', array(
0326                  'AUTHOR'    => $convertors[$index]['author'],
0327                  'SOFTWARE'    => $convertors[$index]['forum_name'],
0328                  'VERSION'    => $convertors[$index]['version'],
0329   
0330                  'U_CONVERT'    => $this->p_master->module_url . "?mode={$this->mode}&amp;language=$language&amp;sub=settings&amp;tag=" . $convertors[$index]['tag'],
0331              ));
0332          }
0333      }
0334   
0335      /**
0336      */
0337      function get_convert_settings($sub)
0338      {
0339          global $lang, $language, $template, $db, $phpbb_root_path, $phpEx, $config, $cache;
0340   
0341          require($phpbb_root_path . 'config.' . $phpEx);
0342          require($phpbb_root_path . 'includes/constants.' . $phpEx);
0343          require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
0344          require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0345   
0346          $db = new $sql_db();
0347          $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0348          unset($dbpasswd);
0349   
0350          $this->page_title = $lang['STAGE_SETTINGS'];
0351   
0352          // We need to fill the config to let internal functions correctly work
0353          $sql = 'SELECT *
0354              FROM ' . CONFIG_TABLE;
0355          $result = $db->sql_query($sql);
0356   
0357          $config = array();
0358          while ($row = $db->sql_fetchrow($result))
0359          {
0360              $config[$row['config_name']] = $row['config_value'];
0361          }
0362          $db->sql_freeresult($result);
0363   
0364          $convertor_tag = request_var('tag', '');
0365   
0366          if (empty($convertor_tag))
0367          {
0368              $this->p_master->error($lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
0369          }
0370          $get_info = true;
0371   
0372          // check security implications of direct inclusion
0373          $convertor_tag = basename($convertor_tag);
0374          if (!file_exists('./convertors/convert_' . $convertor_tag . '.' . $phpEx))
0375          {
0376              $this->p_master->error($lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
0377          }
0378   
0379          include('./convertors/convert_' . $convertor_tag . '.' . $phpEx);
0380   
0381          // The test_file is a file that should be present in the location of the old board.
0382          if (!isset($test_file))
0383          {
0384              $this->p_master->error($lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
0385          }
0386   
0387          $submit = (isset($_POST['submit'])) ? true : false;
0388   
0389          $src_dbms            = request_var('src_dbms', $convertor_data['dbms']);
0390          $src_dbhost            = request_var('src_dbhost', $convertor_data['dbhost']);
0391          $src_dbport            = request_var('src_dbport', $convertor_data['dbport']);
0392          $src_dbuser            = request_var('src_dbuser', $convertor_data['dbuser']);
0393          $src_dbpasswd        = request_var('src_dbpasswd', $convertor_data['dbpasswd']);
0394          $src_dbname            = request_var('src_dbname', $convertor_data['dbname']);
0395          $src_table_prefix    = request_var('src_table_prefix', $convertor_data['table_prefix']);
0396          $forum_path            = request_var('forum_path', $convertor_data['forum_path']);
0397          $refresh            = request_var('refresh', 1);
0398   
0399          // Default URL of the old board
0400          // @todo Are we going to use this for attempting to convert URL references in posts, or should we remove it?
0401          //        -> We should convert old urls to the new relative urls format
0402          // $src_url = request_var('src_url', 'Not in use at the moment');
0403   
0404          // strip trailing slash from old forum path
0405          $forum_path = (strlen($forum_path) && $forum_path[strlen($forum_path) - 1] == '/') ? substr($forum_path, 0, -1) : $forum_path;
0406   
0407          $error = array();
0408          if ($submit)
0409          {
0410              if (!file_exists('./../' . $forum_path . '/' . $test_file))
0411              {
0412                  $error[] = sprintf($lang['COULD_NOT_FIND_PATH'], $forum_path);
0413              }
0414   
0415              $connect_test = false;
0416              $available_dbms = get_available_dbms(false, true, true);
0417   
0418              if (!isset($available_dbms[$src_dbms]) || !$available_dbms[$src_dbms]['AVAILABLE'])
0419              {
0420                  $error['db'][] = $lang['INST_ERR_NO_DB'];
0421                  $connect_test = false;
0422              }
0423              else
0424              {
0425                  $src_dbpasswd = htmlspecialchars_decode($src_dbpasswd);
0426                  $connect_test = connect_check_db(true, $error, $available_dbms[$src_dbms], $src_table_prefix, $src_dbhost, $src_dbuser, $src_dbpasswd, $src_dbname, $src_dbport, true, ($src_dbms == $dbms) ? false : true, false);
0427              }
0428   
0429              // The forum prefix of the old and the new forum can only be the same if two different databases are used.
0430              if ($src_table_prefix == $table_prefix && $src_dbms == $dbms && $src_dbhost == $dbhost && $src_dbport == $dbport && $src_dbname == $dbname)
0431              {
0432                  $error[] = sprintf($lang['TABLE_PREFIX_SAME'], $src_table_prefix);
0433              }
0434   
0435              // Check table prefix
0436              if (!sizeof($error))
0437              {
0438                  // initiate database connection to old db if old and new db differ
0439                  global $src_db, $same_db;
0440                  $src_db = $same_db = false;
0441   
0442                  if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser)
0443                  {
0444                      $sql_db = 'dbal_' . $src_dbms;
0445                      $src_db = new $sql_db();
0446                      $src_db->sql_connect($src_dbhost, $src_dbuser, $src_dbpasswd, $src_dbname, $src_dbport, false, true);
0447                      $same_db = false;
0448                  }
0449                  else
0450                  {
0451                      $src_db = $db;
0452                      $same_db = true;
0453                  }
0454   
0455                  $src_db->sql_return_on_error(true);
0456                  $db->sql_return_on_error(true);
0457   
0458                  // Try to select one row from the first table to see if the prefix is OK
0459                  $result = $src_db->sql_query_limit('SELECT * FROM ' . $src_table_prefix . $tables[0], 1);
0460   
0461                  if (!$result)
0462                  {
0463                      $prefixes = array();
0464   
0465                      $tables_existing = get_tables($src_db);
0466                      $tables_existing = array_map('strtolower', $tables_existing);
0467                      foreach ($tables_existing as $table_name)
0468                      {
0469                          compare_table($tables, $table_name, $prefixes);
0470                      }
0471                      unset($tables_existing);
0472   
0473                      foreach ($prefixes as $prefix => $count)
0474                      {
0475                          if ($count >= sizeof($tables))
0476                          {
0477                              $possible_prefix = $prefix;
0478                              break;
0479                          }
0480                      }
0481   
0482                      $msg = '';
0483                      if (!empty($convertor_data['table_prefix']))
0484                      {
0485                          $msg .= sprintf($lang['DEFAULT_PREFIX_IS'], $convertor_data['forum_name'], $convertor_data['table_prefix']);
0486                      }
0487   
0488                      if (!empty($possible_prefix))
0489                      {
0490                          $msg .= '<br />';
0491                          $msg .= ($possible_prefix == '*') ? $lang['BLANK_PREFIX_FOUND'] : sprintf($lang['PREFIX_FOUND'], $possible_prefix);
0492                          $src_table_prefix = ($possible_prefix == '*') ? '' : $possible_prefix;
0493                      }
0494   
0495                      $error[] = $msg;
0496                  }
0497                  $src_db->sql_freeresult($result);
0498                  $src_db->sql_return_on_error(false);
0499              }
0500   
0501              if (!sizeof($error))
0502              {
0503                  // Save convertor Status
0504                  set_config('convert_progress', serialize(array(
0505                      'step'            => '',
0506                      'table_prefix'    => $src_table_prefix,
0507                      'tag'            => $convertor_tag,
0508                  )), true);
0509                  set_config('convert_db_server', serialize(array(
0510                      'dbms'            => $src_dbms,
0511                      'dbhost'        => $src_dbhost,
0512                      'dbport'        => $src_dbport,
0513                      'dbname'        => $src_dbname,
0514                  )), true);
0515                  set_config('convert_db_user', serialize(array(
0516                      'dbuser'        => $src_dbuser,
0517                      'dbpasswd'        => $src_dbpasswd,
0518                  )), true);
0519   
0520                  // Save options
0521                  set_config('convert_options', serialize(array('forum_path' => './../' . $forum_path, 'refresh' => $refresh)), true);
0522   
0523                  $template->assign_block_vars('checks', array(
0524                      'TITLE'        => $lang['VERIFY_OPTIONS'],
0525                      'RESULT'    => $lang['CONVERT_SETTINGS_VERIFIED'],
0526                  ));
0527   
0528                  $template->assign_vars(array(
0529                      'L_SUBMIT'    => $lang['BEGIN_CONVERT'],
0530  //                    'S_HIDDEN'    => $s_hidden_fields,
0531                      'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag=$convertor_tag&amp;language=$language",
0532                  ));
0533   
0534                  return;
0535              }
0536              else
0537              {
0538                  $template->assign_block_vars('checks', array(
0539                      'TITLE'        => $lang['VERIFY_OPTIONS'],
0540                      'RESULT'    => '<b style="color:red">' . implode('<br />', $error) . '</b>',
0541                  ));
0542              }
0543          } // end submit
0544   
0545          foreach ($this->convert_options as $config_key => $vars)
0546          {
0547              if (!is_array($vars) && strpos($config_key, 'legend') === false)
0548              {
0549                  continue;
0550              }
0551   
0552              if (strpos($config_key, 'legend') !== false)
0553              {
0554                  $template->assign_block_vars('options', array(
0555                      'S_LEGEND'        => true,
0556                      'LEGEND'        => $lang[$vars])
0557                  );
0558   
0559                  continue;
0560              }
0561   
0562              $options = isset($vars['options']) ? $vars['options'] : '';
0563   
0564              $template->assign_block_vars('options', array(
0565                  'KEY'            => $config_key,
0566                  'TITLE'            => $lang[$vars['lang']],
0567                  'S_EXPLAIN'        => $vars['explain'],
0568                  'S_LEGEND'        => false,
0569                  'TITLE_EXPLAIN'    => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
0570                  'CONTENT'        => $this->p_master->input_field($config_key, $vars['type'], $$config_key, $options),
0571                  )
0572              );
0573          }
0574   
0575          $template->assign_vars(array(
0576              'TITLE'        => $lang['STAGE_SETTINGS'],
0577              'BODY'        => $lang['CONV_OPTIONS_BODY'],
0578              'L_SUBMIT'    => $lang['BEGIN_CONVERT'],
0579              'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=settings&amp;tag=$convertor_tag&amp;language=$language",
0580          ));
0581      }
0582   
0583      /**
0584      * The function which does the actual work (or dispatches it to the relevant places)
0585      */
0586      function convert_data($sub)
0587      {
0588          global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache;
0589          global $convert, $convert_row, $message_parser, $skip_rows;
0590   
0591          require($phpbb_root_path . 'config.' . $phpEx);
0592          require($phpbb_root_path . 'includes/constants.' . $phpEx);
0593          require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
0594          require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
0595   
0596          $db = new $sql_db();
0597          $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
0598          unset($dbpasswd);
0599   
0600          $sql = 'SELECT *
0601              FROM ' . CONFIG_TABLE;
0602          $result = $db->sql_query($sql);
0603   
0604          $config = array();
0605          while ($row = $db->sql_fetchrow($result))
0606          {
0607              $config[$row['config_name']] = $row['config_value'];
0608          }
0609          $db->sql_freeresult($result);
0610   
0611          // Override a couple of config variables for the duration
0612          $config['max_quote_depth'] = 0;
0613   
0614          // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
0615          $config['max_post_chars'] = 0;
0616   
0617          // Set up a user as well. We _should_ have enough of a database here at this point to do this
0618          // and it helps for any core code we call
0619          $user->session_begin();
0620          $user->page = $user->extract_current_page($phpbb_root_path);
0621   
0622          // This is a little bit of a fudge, but it allows the language entries to be available to the
0623          // core code without us loading them again
0624          $user->lang = &$lang;
0625   
0626          $this->page_title = $user->lang['STAGE_IN_PROGRESS'];
0627   
0628          $convert->options = array();
0629          if (isset($config['convert_progress']))
0630          {
0631              $convert->options = unserialize($config['convert_progress']);
0632              $convert->options = array_merge($convert->options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
0633          }
0634   
0635          // This information should have already been checked once, but do it again for safety
0636          if (empty($convert->options) || empty($convert->options['tag']) ||
0637              !isset($convert->options['dbms']) ||
0638              !isset($convert->options['dbhost']) ||
0639              !isset($convert->options['dbport']) ||
0640              !isset($convert->options['dbuser']) ||
0641              !isset($convert->options['dbpasswd']) ||
0642              !isset($convert->options['dbname']) ||
0643              !isset($convert->options['table_prefix']))
0644          {
0645              $this->p_master->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
0646          }
0647   
0648          // Make some short variables accessible, for easier referencing
0649          $convert->convertor_tag = basename($convert->options['tag']);
0650          $convert->src_dbms = $convert->options['dbms'];
0651          $convert->src_dbhost = $convert->options['dbhost'];
0652          $convert->src_dbport = $convert->options['dbport'];
0653          $convert->src_dbuser = $convert->options['dbuser'];
0654          $convert->src_dbpasswd = $convert->options['dbpasswd'];
0655          $convert->src_dbname = $convert->options['dbname'];
0656          $convert->src_table_prefix = $convert->options['table_prefix'];
0657   
0658          // initiate database connection to old db if old and new db differ
0659          global $src_db, $same_db;
0660          $src_db = $same_db = null;
0661          if ($convert->src_dbms != $dbms || $convert->src_dbhost != $dbhost || $convert->src_dbport != $dbport || $convert->src_dbname != $dbname || $convert->src_dbuser != $dbuser)
0662          {
0663              if ($convert->src_dbms != $dbms)
0664              {
0665                  require($phpbb_root_path . 'includes/db/' . $convert->src_dbms . '.' . $phpEx);
0666              }
0667              $sql_db = 'dbal_' . $convert->src_dbms;
0668              $src_db = new $sql_db();
0669              $src_db->sql_connect($convert->src_dbhost, $convert->src_dbuser, $convert->src_dbpasswd, $convert->src_dbname, $convert->src_dbport, false, true);
0670              $same_db = false;
0671          }
0672          else
0673          {
0674              $src_db = $db;
0675              $same_db = true;
0676          }
0677   
0678          $convert->mysql_convert = false;
0679          switch ($src_db->sql_layer)
0680          {
0681              case 'sqlite':
0682              case 'firebird':
0683                  $convert->src_truncate_statement = 'DELETE FROM ';
0684              break;
0685   
0686              // Thanks MySQL, for silently converting...
0687              case 'mysql':
0688              case 'mysql4':
0689                  if (version_compare($src_db->mysql_version, '4.1.3', '>='))
0690                  {
0691                      $convert->mysql_convert = true;
0692                  }
0693                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
0694              break;
0695   
0696              case 'mysqli':
0697                  $convert->mysql_convert = true;
0698                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
0699              break;
0700   
0701              default:
0702                  $convert->src_truncate_statement = 'TRUNCATE TABLE ';
0703              break;
0704          }
0705   
0706          if ($convert->mysql_convert && !$same_db)
0707          {
0708              $src_db->sql_query("SET NAMES 'binary'");
0709          }
0710   
0711          switch ($db->sql_layer)
0712          {
0713              case 'sqlite':
0714              case 'firebird':
0715                  $convert->truncate_statement = 'DELETE FROM ';
0716              break;
0717   
0718              default:
0719                  $convert->truncate_statement = 'TRUNCATE TABLE ';
0720              break;
0721          }
0722   
0723          $get_info = false;
0724   
0725          // check security implications of direct inclusion
0726          if (!file_exists('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx))
0727          {
0728              $this->p_master->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
0729          }
0730   
0731          if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx))
0732          {
0733              include('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx);
0734          }
0735   
0736          $get_info = true;
0737          include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
0738   
0739          // Map some variables...
0740          $convert->convertor_data = $convertor_data;
0741          $convert->tables = $tables;
0742          $convert->config_schema = $config_schema;
0743   
0744          // Now include the real data
0745          $get_info = false;
0746          include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
0747   
0748          $convert->convertor_data = $convertor_data;
0749          $convert->tables = $tables;
0750          $convert->config_schema = $config_schema;
0751          $convert->convertor = $convertor;
0752   
0753          // The test_file is a file that should be present in the location of the old board.
0754          if (!file_exists($convert->options['forum_path'] . '/' . $test_file))
0755          {
0756              $this->p_master->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->options['forum_path']), __LINE__, __FILE__);
0757          }
0758   
0759          $search_type = basename(trim($config['search_type']));
0760   
0761          // For conversions we are a bit less strict and set to a search backend we know exist...
0762          if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx))
0763          {
0764              $search_type = 'fulltext_native';
0765              set_config('search_type', $search_type);
0766          }
0767   
0768          if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx))
0769          {
0770              trigger_error('NO_SUCH_SEARCH_MODULE');
0771          }
0772   
0773          require($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx);
0774   
0775          $error = false;
0776          $convert->fulltext_search = new $search_type($error);
0777   
0778          if ($error)
0779          {
0780              trigger_error($error);
0781          }
0782   
0783          include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
0784          $message_parser = new parse_message();
0785   
0786          $jump = request_var('jump', 0);
0787          $final_jump = request_var('final_jump', 0);
0788          $sync_batch = request_var('sync_batch', -1);
0789          $last_statement = request_var('last', 0);
0790   
0791          // We are running sync...
0792          if ($sync_batch >= 0)
0793          {
0794              $this->sync_forums($sync_batch);
0795              return;
0796          }
0797   
0798          if ($jump)
0799          {
0800              $this->jump($jump, $last_statement);
0801              return;
0802          }
0803   
0804          if ($final_jump)
0805          {
0806              $this->final_jump($final_jump);
0807              return;
0808          }
0809   
0810          $current_table = request_var('current_table', 0);
0811          $old_current_table = min(-1, $current_table - 1);
0812          $skip_rows = request_var('skip_rows', 0);
0813   
0814          if (!$current_table && !$skip_rows)
0815          {
0816              if (empty($_REQUEST['confirm']))
0817              {
0818                  // If avatars / ranks / smilies folders are specified make sure they are writable
0819                  $bad_folders = array();
0820   
0821                  $local_paths = array(
0822                      'avatar_path'            => path($config['avatar_path']),
0823                      'avatar_gallery_path'    => path($config['avatar_gallery_path']),
0824                      'icons_path'            => path($config['icons_path']),
0825                      'ranks_path'            => path($config['ranks_path']),
0826                      'smilies_path'            => path($config['smilies_path'])
0827                  );
0828   
0829                  foreach ($local_paths as $folder => $local_path)
0830                  {
0831                      if (isset($convert->convertor[$folder]))
0832                      {
0833                          if (empty($convert->convertor['test_file']))
0834                          {
0835                              // test_file is mandantory at the moment so this should never be reached, but just in case...
0836                              $this->p_master->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
0837                          }
0838   
0839                          if (!$local_path || !@is_writable($phpbb_root_path . $local_path))
0840                          {
0841                              if (!$local_path)
0842                              {
0843                                  $bad_folders[] = sprintf($user->lang['CONFIG_PHPBB_EMPTY'], $folder);
0844                              }
0845                              else
0846                              {
0847                                  $bad_folders[] = $local_path;
0848                              }
0849                          }
0850                      }
0851                  }
0852   
0853                  if (sizeof($bad_folders))
0854                  {
0855                      $msg = (sizeof($bad_folders) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
0856                      sort($bad_folders);
0857                      $this->p_master->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true);
0858   
0859                      $template->assign_vars(array(
0860                          'L_SUBMIT'    => $user->lang['INSTALL_TEST'],
0861                          'U_ACTION'    => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}&amp;language=$language",
0862                      ));
0863                      return;
0864                  }
0865   
0866                  // Grab all the tables used in convertor
0867                  $missing_tables = $tables_list = $aliases = array();
0868   
0869                  foreach ($convert->convertor['schema'] as $schema)
0870                  {
0871                      // Skip those not used (because of addons/plugins not detected)
0872                      if (!$schema['target'])
0873                      {
0874                          continue;
0875                      }
0876   
0877                      foreach ($schema as $key => $val)
0878                      {
0879                          // we're dealing with an array like:
0880                          // array('forum_status',            'forums.forum_status',                'is_item_locked')
0881                          if (is_int($key) && !empty($val[1]))
0882                          {
0883                              $temp_data = $val[1];
0884                              if (!is_array($temp_data))
0885                              {
0886                                  $temp_data = array($temp_data);
0887                              }
0888   
0889                              foreach ($temp_data as $val)
0890                              {
0891                                  if (preg_match('/([a-z0-9_]+)\.([a-z0-9_]+)\)* ?A?S? ?([a-z0-9_]*?)\.?([a-z0-9_]*)$/i', $val, $m))
0892                                  {
0893                                      $table = $convert->src_table_prefix . $m[1];
0894                                      $tables_list[$table] = $table;
0895          
0896                                      if (!empty($m[3]))
0897                                      {
0898                                          $aliases[] = $convert->src_table_prefix . $m[3];
0899                                      }
0900                                  }
0901                              }
0902                          }
0903                          // 'left_join'        => 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1'
0904                          else if ($key == 'left_join')
0905                          {
0906                              // Convert the value if it wasn't an array already.
0907                              if (!is_array($val))
0908                              {
0909                                  $val = array($val);
0910                              }
0911   
0912                              for ($j = 0; $j < sizeof($val); ++$j)
0913                              {
0914                                  if (preg_match('/LEFT JOIN ([a-z0-9_]+) AS ([a-z0-9_]+)/i', $val[$j], $m))
0915                                  {
0916                                      $table = $convert->src_table_prefix . $m[1];
0917                                      $tables_list[$table] = $table;
0918   
0919                                      if (!empty($m[2]))
0920                                      {
0921                                          $aliases[] = $convert->src_table_prefix . $m[2];
0922                                      }
0923                                  }
0924                              }
0925                          }
0926                      }
0927                  }
0928   
0929                  // Remove aliased tables from $tables_list
0930                  foreach ($aliases as $alias)
0931                  {
0932                      unset($tables_list[$alias]);
0933                  }
0934   
0935                  // Check if the tables that we need exist
0936                  $src_db->sql_return_on_error(true);
0937                  foreach ($tables_list as $table => $null)
0938                  {
0939                      $sql = 'SELECT 1 FROM ' . $table;
0940                      $_result = $src_db->sql_query_limit($sql, 1);
0941   
0942                      if (!$_result)
0943                      {
0944                          $missing_tables[] = $table;
0945                      }
0946                      $src_db->sql_freeresult($_result);
0947                  }
0948                  $src_db->sql_return_on_error(false);
0949   
0950                  // Throw an error if some tables are missing
0951                  // 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
0952                  
0953                  if (sizeof($missing_tables) == sizeof($tables_list))
0954                  {
0955                      $this->p_master->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
0956                  }
0957                  else if (sizeof($missing_tables))
0958                  {
0959                      $this->p_master->error(sprintf($user->lang['TABLES_MISSING'], implode(', ', $missing_tables)) . '<br /><br />' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
0960                  }
0961   
0962                  $url = $this->save_convert_progress('&amp;confirm=1');
0963                  $msg = $user->lang['PRE_CONVERT_COMPLETE'];
0964   
0965                  if ($convert->convertor_data['author_notes'])
0966                  {
0967                      $msg .= '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
0968                  }
0969   
0970                  $template->assign_vars(array(
0971                      'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
0972                      'L_MESSAGE'        => $msg,
0973                      'U_ACTION'        => $url,
0974                  ));
0975   
0976                  return;
0977              } // if (empty($_REQUEST['confirm']))
0978   
0979              $template->assign_block_vars('checks', array(
0980                  'S_LEGEND'        => true,
0981                  'LEGEND'        => $user->lang['STARTING_CONVERT'],
0982              ));
0983   
0984              // Convert the config table and load the settings of the old board
0985              if (!empty($convert->config_schema))
0986              {
0987                  restore_config($convert->config_schema);
0988   
0989                  // Override a couple of config variables for the duration
0990                  $config['max_quote_depth'] = 0;
0991   
0992                  // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
0993                  $config['max_post_chars'] = 0;
0994              }
0995   
0996              $template->assign_block_vars('checks', array(
0997                  'TITLE'        => $user->lang['CONFIG_CONVERT'],
0998                  'RESULT'    => $user->lang['DONE'],
0999              ));
1000   
1001              // Now process queries and execute functions that have to be executed prior to the conversion
1002              if (!empty($convert->convertor['execute_first']))
1003              {
1004                  eval($convert->convertor['execute_first']);
1005              }
1006   
1007              if (!empty($convert->convertor['query_first']))
1008              {
1009                  if (!is_array($convert->convertor['query_first']))
1010                  {
1011                      $convert->convertor['query_first'] = array('target', array($convert->convertor['query_first']));
1012                  }
1013                  else if (!is_array($convert->convertor['query_first'][0]))
1014                  {
1015                      $convert->convertor['query_first'] = array(array($convert->convertor['query_first'][0], $convert->convertor['query_first'][1]));
1016                  }
1017   
1018                  foreach ($convert->convertor['query_first'] as $query_first)
1019                  {
1020                      if ($query_first[0] == 'src')
1021                      {
1022                          if ($convert->mysql_convert && $same_db)
1023                          {
1024                              $src_db->sql_query("SET NAMES 'binary'");
1025                          }
1026   
1027                          $src_db->sql_query($query_first[1]);
1028   
1029                          if ($convert->mysql_convert && $same_db)
1030                          {
1031                              $src_db->sql_query("SET NAMES 'utf8'");
1032                          }
1033                      }
1034                      else
1035                      {
1036                          $db->sql_query($query_first[1]);
1037                      }
1038                  }
1039              }
1040   
1041              $template->assign_block_vars('checks', array(
1042                  'TITLE'        => $user->lang['PREPROCESS_STEP'],
1043                  'RESULT'    => $user->lang['DONE'],
1044              ));
1045          } // if (!$current_table && !$skip_rows)
1046   
1047          $template->assign_block_vars('checks', array(
1048              'S_LEGEND'        => true,
1049              'LEGEND'        => $user->lang['FILLING_TABLES'],
1050          ));
1051   
1052          // This loop takes one target table and processes it
1053          while ($current_table < sizeof($convert->convertor['schema']))
1054          {
1055              $schema = $convert->convertor['schema'][$current_table];
1056   
1057              // The target table isn't set, this can be because a module (for example the attachement mod) is taking care of this.
1058              if (empty($schema['target']))
1059              {
1060                  $current_table++;
1061                  continue;
1062              }
1063   
1064              $template->assign_block_vars('checks', array(
1065                  'TITLE'    => sprintf($user->lang['FILLING_TABLE'], $schema['target']),
1066              ));
1067   
1068              // This is only the case when we first start working on the tables.
1069              if (!$skip_rows)
1070              {
1071                  // process execute_first and query_first for this table...
1072                  if (!empty($schema['execute_first']))
1073                  {
1074                      eval($schema['execute_first']);
1075                  }
1076   
1077                  if (!empty($schema['query_first']))
1078                  {
1079                      if (!is_array($schema['query_first']))
1080                      {
1081                          $schema['query_first'] = array('target', array($schema['query_first']));
1082                      }
1083                      else if (!is_array($schema['query_first'][0]))
1084                      {
1085                          $schema['query_first'] = array(array($schema['query_first'][0], $schema['query_first'][1]));
1086                      }
1087   
1088                      foreach ($schema['query_first'] as $query_first)
1089                      {
1090                          if ($query_first[0] == 'src')
1091                          {
1092                              if ($convert->mysql_convert && $same_db)
1093                              {
1094                                  $src_db->sql_query("SET NAMES 'binary'");
1095                              }
1096                              $src_db->sql_query($query_first[1]);
1097                              if ($convert->mysql_convert && $same_db)
1098                              {
1099                                  $src_db->sql_query("SET NAMES 'utf8'");
1100                              }
1101                          }
1102                          else
1103                          {
1104                              $db->sql_query($query_first[1]);
1105                          }
1106                      }
1107                  }
1108   
1109                  if (!empty($schema['autoincrement']))
1110                  {
1111                      switch ($db->sql_layer)
1112                      {
1113                          case 'postgres':
1114                              $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'] . '));');
1115                          break;
1116   
1117                          case 'oracle':
1118                              $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
1119                              $row = $db->sql_fetchrow($result);
1120                              $db->sql_freeresult($result);
1121   
1122                              $largest_id = (int) $row['max_id'];
1123   
1124                              if ($largest_id)
1125                              {
1126                                  $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
1127                                  $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
1128                              }
1129                          break;
1130                      }
1131                  }
1132              }
1133   
1134              // Process execute_always for this table
1135              // This is for code which needs to be executed on every pass of this table if
1136              // it gets split because of time restrictions
1137              if (!empty($schema['execute_always']))
1138              {
1139                  eval($schema['execute_always']);
1140              }
1141   
1142              //
1143              // Set up some variables
1144              //
1145              // $waiting_rows    holds rows for multirows insertion (MySQL only)
1146              // $src_tables        holds unique tables with aliases to select from
1147              // $src_fields        will quickly refer source fields (or aliases) corresponding to the current index
1148              // $select_fields    holds the names of the fields to retrieve
1149              //
1150   
1151              $sql_data = array(
1152                  'source_fields'        => array(),
1153                  'target_fields'        => array(),
1154                  'source_tables'        => array(),
1155                  'select_fields'        => array(),
1156              );
1157   
1158              // This statement is building the keys for later insertion.
1159              $insert_query = $this->build_insert_query($schema, $sql_data, $current_table);
1160   
1161              // If no source table is affected, we skip the table
1162              if (empty($sql_data['source_tables']))
1163              {
1164                  $skip_rows = 0;
1165                  $current_table++;
1166                  continue;
1167              }
1168   
1169              $distinct = (!empty($schema['distinct'])) ? 'DISTINCT ' : '';
1170   
1171              $sql = 'SELECT ' . $distinct . implode(', ', $sql_data['select_fields']) . " \nFROM " . implode(', ', $sql_data['source_tables']);
1172   
1173              // Where
1174              $sql .= (!empty($schema['where'])) ? "\nWHERE (" . $schema['where'] . ')' : '';
1175   
1176              // Group By
1177              if (!empty($schema['group_by']))
1178              {
1179                  $schema['group_by'] = array($schema['group_by']);
1180                  foreach ($sql_data['select_fields'] as $select)
1181                  {
1182                      $alias = strpos(strtolower($select), ' as ');
1183                      $select = ($alias) ? substr($select, 0, $alias) : $select;
1184                      if (!in_array($select, $schema['group_by']))
1185                      {
1186                          $schema['group_by'][] = $select;
1187                      }
1188                  }
1189              }
1190              $sql .= (!empty($schema['group_by'])) ? "\nGROUP BY " . implode(', ', $schema['group_by']) : '';
1191   
1192              // Having
1193              $sql .= (!empty($schema['having'])) ? "\nHAVING " . $schema['having'] : '';
1194   
1195              // Order By
1196              if (empty($schema['order_by']) && !empty($schema['primary']))
1197              {
1198                  $schema['order_by'] = $schema['primary'];
1199              }
1200              $sql .= (!empty($schema['order_by'])) ? "\nORDER BY " . $schema['order_by'] : '';
1201   
1202              // Counting basically holds the amount of rows processed.
1203              $counting = -1;
1204              $batch_time = 0;
1205   
1206              while ($counting === -1 || ($counting >= $convert->batch_size && still_on_time()))
1207              {
1208                  $old_current_table = $current_table;
1209   
1210                  $rows = '';
1211                  $waiting_rows = array();
1212   
1213                  if (!empty($batch_time))
1214                  {
1215                      $mtime = explode(' ', microtime());
1216                      $mtime = $mtime[0] + $mtime[1];
1217                      $rows = ceil($counting/($mtime - $batch_time)) . " rows/s ($counting rows) | ";
1218                  }
1219   
1220                  $template->assign_block_vars('checks', array(
1221                      'TITLE'        => "skip_rows = $skip_rows",
1222                      'RESULT'    => $rows . ((defined('DEBUG_EXTRA') && function_exists('memory_get_usage')) ? ceil(memory_get_usage()/1024) . ' KB' : ''),
1223                  ));
1224   
1225                  $mtime = explode(' ', microtime());
1226                  $batch_time = $mtime[0] + $mtime[1];
1227   
1228                  if ($convert->mysql_convert && $same_db)
1229                  {
1230                      $src_db->sql_query("SET NAMES 'binary'");
1231                  }
1232   
1233                  // Take skip rows into account and only fetch batch_size amount of rows
1234                  $___result = $src_db->sql_query_limit($sql, $convert->batch_size, $skip_rows);
1235   
1236                  if ($convert->mysql_convert && $same_db)
1237                  {
1238                      $src_db->sql_query("SET NAMES 'utf8'");
1239                  }
1240   
1241                  // This loop processes each row
1242                  $counting = 0;
1243   
1244                  $convert->row = $convert_row = array();
1245   
1246                  if (!empty($schema['autoincrement']))
1247                  {
1248                      switch ($db->sql_layer)
1249                      {
1250                          case 'mssql':
1251                          case 'mssql_odbc':
1252                              $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' ON');
1253                          break;
1254                      }
1255                  }
1256   
1257                  // Now handle the rows until time is over or no more rows to process...
1258                  while ($counting === 0 || still_on_time())
1259                  {
1260                      $convert_row = $src_db->sql_fetchrow($___result);
1261   
1262                      if (!$convert_row)
1263                      {
1264                          // move to the next batch or table
1265                          break;
1266                      }
1267   
1268                      // With this we are able to always save the last state
1269                      $convert->row = $convert_row;
1270   
1271                      // Increment the counting variable, it stores the number of rows we have processed
1272                      $counting++;
1273   
1274                      $insert_values = array();
1275   
1276                      $sql_flag = $this->process_row($schema, $sql_data, $insert_values);
1277   
1278                      if ($sql_flag === true)
1279                      {
1280                          switch ($db->sql_layer)
1281                          {
1282                              // If MySQL, we'll wait to have num_wait_rows rows to submit at once
1283                              case 'mysql':
1284                              case 'mysql4':
1285                              case 'mysqli':
1286                                  $waiting_rows[] = '(' . implode(', ', $insert_values) . ')';
1287   
1288                                  if (sizeof($waiting_rows) >= $convert->num_wait_rows)
1289                                  {
1290                                      $errored = false;
1291   
1292                                      $db->sql_return_on_error(true);
1293   
1294                                      if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
1295                                      {
1296                                          $errored = true;
1297                                      }
1298                                      $db->sql_return_on_error(false);
1299   
1300                                      if ($errored)
1301                                      {
1302                                          $db->sql_return_on_error(true);
1303      
1304                                          // Because it errored out we will try to insert the rows one by one... most of the time this
1305                                          // is caused by duplicate entries - but we also do not want to miss one...
1306                                          foreach ($waiting_rows as $waiting_sql)
1307                                          {
1308                                              if (!$db->sql_query($insert_query . $waiting_sql))
1309                                              {
1310                                                  $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);
1311                                              }
1312                                          }
1313   
1314                                          $db->sql_return_on_error(false);
1315                                      }
1316   
1317                                      $waiting_rows = array();
1318                                  }
1319   
1320                              break;
1321   
1322                              default:
1323                                  $insert_sql = $insert_query . '(' . implode(', ', $insert_values) . ')';
1324   
1325                                  $db->sql_return_on_error(true);
1326   
1327                                  if (!$db->sql_query($insert_sql))
1328                                  {
1329                                      $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);
1330                                  }
1331                                  $db->sql_return_on_error(false);
1332   
1333                                  $waiting_rows = array();
1334   
1335                              break;
1336                          }
1337                      }
1338   
1339                      $skip_rows++;
1340                  }
1341                  $src_db->sql_freeresult($___result);
1342   
1343                  // We might still have some rows waiting
1344                  if (sizeof($waiting_rows))
1345                  {
1346                      $errored = false;
1347                      $db->sql_return_on_error(true);
1348   
1349                      if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
1350                      {
1351                          $errored = true;
1352                      }
1353                      $db->sql_return_on_error(false);
1354   
1355                      if ($errored)
1356                      {
1357                          $db->sql_return_on_error(true);
1358   
1359                          // Because it errored out we will try to insert the rows one by one... most of the time this
1360                          // is caused by duplicate entries - but we also do not want to miss one...
1361                          foreach ($waiting_rows as $waiting_sql)
1362                          {
1363                              $db->sql_query($insert_query . $waiting_sql);
1364                              $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);
1365                          }
1366   
1367                          $db->sql_return_on_error(false);
1368                      }
1369   
1370                      $waiting_rows = array();
1371                  }
1372   
1373                  if (!empty($schema['autoincrement']))
1374                  {
1375                      switch ($db->sql_layer)
1376                      {
1377                          case 'mssql':
1378                          case 'mssql_odbc':
1379                              $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' OFF');
1380                          break;
1381   
1382                          case 'postgres':
1383                              $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'] . '));');
1384                          break;
1385   
1386                          case 'oracle':
1387                              $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
1388                              $row = $db->sql_fetchrow($result);
1389                              $db->sql_freeresult($result);
1390   
1391                              $largest_id = (int) $row['max_id'];
1392   
1393                              if ($largest_id)
1394                              {
1395                                  $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
1396                                  $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
1397                              }
1398                          break;
1399                      }
1400                  }
1401              }
1402   
1403              // When we reach this point, either the current table has been processed or we're running out of time.
1404              if (still_on_time() && $counting < $convert->batch_size/* && !defined('DEBUG_EXTRA')*/)
1405              {
1406                  $skip_rows = 0;
1407                  $current_table++;
1408              }
1409              else
1410              {/*
1411                  if (still_on_time() && $counting < $convert->batch_size)
1412                  {
1413                      $skip_rows = 0;
1414                      $current_table++;
1415                  }*/
1416   
1417                  // Looks like we ran out of time.
1418                  $url = $this->save_convert_progress('&amp;current_table=' . $current_table . '&amp;skip_rows=' . $skip_rows);
1419   
1420                  $current_table++;
1421  //                $percentage = ($skip_rows == 0) ? 0 : floor(100 / ($total_rows / $skip_rows));
1422   
1423                  $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $current_table, sizeof($convert->convertor['schema']));
1424   
1425                  $template->assign_vars(array(
1426                      'L_MESSAGE'        => $msg,
1427                      'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1428                      'U_ACTION'        => $url,
1429                  ));
1430   
1431                  $this->meta_refresh($url);
1432                  return;
1433              }
1434          }
1435   
1436          // Process execute_last then we'll be done
1437          $url = $this->save_convert_progress('&amp;jump=1');
1438   
1439          $template->assign_vars(array(
1440              'L_SUBMIT'        => $user->lang['FINAL_STEP'],
1441              'U_ACTION'        => $url,
1442          ));
1443   
1444          $this->meta_refresh($url);
1445          return;
1446      }
1447   
1448      /**
1449      * Sync function being executed at the middle, some functions need to be executed after a successful sync.
1450      */
1451      function sync_forums($sync_batch)
1452      {
1453          global $template, $user, $db, $phpbb_root_path, $phpEx, $config, $cache;
1454          global $convert;
1455   
1456          $template->assign_block_vars('checks', array(
1457              'S_LEGEND'    => true,
1458              'LEGEND'    => $user->lang['SYNC_TOPICS'],
1459          ));
1460   
1461          $batch_size = $convert->batch_size;
1462   
1463          $sql = 'SELECT MIN(topic_id) as min_value, MAX(topic_id) AS max_value
1464              FROM ' . TOPICS_TABLE;
1465          $result = $db->sql_query($sql);
1466          $row = $db->sql_fetchrow($result);
1467          $db->sql_freeresult($result);
1468   
1469          // Set values of minimum/maximum primary value for this table.
1470          $primary_min = $row['min_value'];
1471          $primary_max = $row['max_value'];
1472   
1473          if ($sync_batch == 0)
1474          {
1475              $sync_batch = (int) $primary_min;
1476          }
1477   
1478          if ($sync_batch == 0)
1479          {
1480              $sync_batch = 1;
1481          }
1482   
1483          // Fetch a batch of rows, process and insert them.
1484          while ($sync_batch <= $primary_max && still_on_time())
1485          {
1486              $end = ($sync_batch + $batch_size - 1);
1487   
1488              // Sync all topics in batch mode...
1489              sync('topic_approved', 'range', 'topic_id BETWEEN ' . $sync_batch . ' AND ' . $end, true, false);
1490              sync('topic', 'range', 'topic_id BETWEEN ' . $sync_batch . ' AND ' . $end, true, true);
1491   
1492              $template->assign_block_vars('checks', array(
1493                  'TITLE'        => sprintf($user->lang['SYNC_TOPIC_ID'], $sync_batch, ($sync_batch + $batch_size)) . ((defined('DEBUG_EXTRA') && function_exists('memory_get_usage')) ? ' [' . ceil(memory_get_usage()/1024) . ' KB]' : ''),
1494                  'RESULT'    => $user->lang['DONE'],
1495              ));
1496   
1497              $sync_batch += $batch_size;
1498          }
1499   
1500          if ($sync_batch >= $primary_max)
1501          {
1502              $url = $this->save_convert_progress('&amp;final_jump=1');
1503   
1504              $template->assign_vars(array(
1505                  'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1506                  'U_ACTION'        => $url,
1507              ));
1508   
1509              $this->meta_refresh($url);
1510              return;
1511          }
1512          else
1513          {
1514              $sync_batch--;
1515          }
1516   
1517          $url = $this->save_convert_progress('&amp;sync_batch=' . $sync_batch);
1518   
1519          $template->assign_vars(array(
1520              'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1521              'U_ACTION'        => $url,
1522          ));
1523   
1524          $this->meta_refresh($url);
1525          return;
1526      }
1527   
1528      /**
1529      * Save the convertor status
1530      */
1531      function save_convert_progress($step)
1532      {
1533          global $convert, $language;
1534   
1535          // Save convertor Status
1536          set_config('convert_progress', serialize(array(
1537              'step'            => $step,
1538              'table_prefix'    => $convert->src_table_prefix,
1539              'tag'            => $convert->convertor_tag,
1540          )), true);
1541   
1542          set_config('convert_db_server', serialize(array(
1543              'dbms'            => $convert->src_dbms,
1544              'dbhost'        => $convert->src_dbhost,
1545              'dbport'        => $convert->src_dbport,
1546              'dbname'        => $convert->src_dbname,
1547          )), true);
1548   
1549          set_config('convert_db_user', serialize(array(
1550              'dbuser'        => $convert->src_dbuser,
1551              'dbpasswd'        => $convert->src_dbpasswd,
1552          )), true);
1553   
1554          return $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step&amp;language=$language";
1555      }
1556   
1557      /**
1558      * Finish conversion, the last function to be called.
1559      */
1560      function finish_conversion()
1561      {
1562          global $db, $phpbb_root_path, $convert, $config, $language, $user, $template;
1563   
1564          $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
1565              WHERE config_name = 'convert_progress'
1566                  OR config_name = 'convert_options'
1567                  OR config_name = 'convert_db_server'
1568                  OR config_name = 'convert_db_user'");
1569          $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
1570   
1571          @unlink($phpbb_root_path . 'cache/data_global.php');
1572          cache_moderators();
1573   
1574          // And finally, add a note to the log
1575          add_log('admin', 'LOG_INSTALL_CONVERTED', $convert->convertor_data['forum_name'], $config['version']);
1576   
1577          $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=final&amp;language=$language";
1578   
1579          $template->assign_vars(array(
1580              'L_SUBMIT'        => $user->lang['FINAL_STEP'],
1581              'U_ACTION'        => $url,
1582          ));
1583   
1584          $this->meta_refresh($url);
1585          return;
1586      }
1587   
1588      /**
1589      * This function marks the steps after syncing
1590      */
1591      function final_jump($final_jump)
1592      {
1593          global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
1594          global $convert;
1595   
1596          $template->assign_block_vars('checks', array(
1597              'S_LEGEND'    => true,
1598              'LEGEND'    => $user->lang['PROCESS_LAST'],
1599          ));
1600   
1601          if ($final_jump == 1)
1602          {
1603              $db->sql_return_on_error(true);
1604   
1605              update_topics_posted();
1606   
1607              $template->assign_block_vars('checks', array(
1608                  'TITLE'        => $user->lang['UPDATE_TOPICS_POSTED'],
1609                  'RESULT'    => $user->lang['DONE'],
1610              ));
1611              
1612              if ($db->sql_error_triggered)
1613              {
1614                  $template->assign_vars(array(
1615                      'S_ERROR_BOX'    => true,
1616                      'ERROR_TITLE'    => $user->lang['UPDATE_TOPICS_POSTED'],
1617                      'ERROR_MSG'        => $user->lang['UPDATE_TOPICS_POSTED_ERR'],
1618                  ));
1619              }
1620              $db->sql_return_on_error(false);
1621              
1622              $this->finish_conversion();
1623              return;
1624          }
1625      }
1626   
1627      /**
1628      * This function marks the steps before syncing (jump=1)
1629      */
1630      function jump($jump, $last_statement)
1631      {
1632          global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
1633          global $convert;
1634   
1635          $template->assign_block_vars('checks', array(
1636              'S_LEGEND'    => true,
1637              'LEGEND'    => $user->lang['PROCESS_LAST'],
1638          ));
1639   
1640          if ($jump == 1)
1641          {
1642              // Execute 'last' statements/queries
1643              if (!empty($convert->convertor['execute_last']))
1644              {
1645                  if (!is_array($convert->convertor['execute_last']))
1646                  {
1647                      eval($convert->convertor['execute_last']);
1648                  }
1649                  else
1650                  {
1651                      while ($last_statement < sizeof($convert->convertor['execute_last']))
1652                      {
1653                          eval($convert->convertor['execute_last'][$last_statement]);
1654   
1655                          $template->assign_block_vars('checks', array(
1656                              'TITLE'        => $convert->convertor['execute_last'][$last_statement],
1657                              'RESULT'    => $user->lang['DONE'],
1658                          ));
1659   
1660                          $last_statement++;
1661                          $url = $this->save_convert_progress('&amp;jump=1&amp;last=' . $last_statement);
1662   
1663                          $percentage = ($last_statement == 0) ? 0 : floor(100 / (sizeof($convert->convertor['execute_last']) / $last_statement));
1664                          $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $last_statement, sizeof($convert->convertor['execute_last']), $percentage);
1665   
1666                          $template->assign_vars(array(
1667                              'L_SUBMIT'        => $user->lang['CONTINUE_LAST'],
1668                              'L_MESSAGE'        => $msg,
1669                              'U_ACTION'        => $url,
1670                          ));
1671   
1672                          $this->meta_refresh($url);
1673                          return;
1674                      }
1675                  }
1676              }
1677   
1678              if (!empty($convert->convertor['query_last']))
1679              {
1680                  if (!is_array($convert->convertor['query_last']))
1681                  {
1682                      $convert->convertor['query_last'] = array('target', array($convert->convertor['query_last']));
1683                  }
1684                  else if (!is_array($convert->convertor['query_last'][0]))
1685                  {
1686                      $convert->convertor['query_last'] = array(array($convert->convertor['query_last'][0], $convert->convertor['query_last'][1]));
1687                  }
1688   
1689                  foreach ($convert->convertor['query_last'] as $query_last)
1690                  {
1691                      if ($query_last[0] == 'src')
1692                      {
1693                          if ($convert->mysql_convert && $same_db)
1694                          {
1695                              $src_db->sql_query("SET NAMES 'binary'");
1696                          }
1697   
1698                          $src_db->sql_query($query_last[1]);
1699   
1700                          if ($convert->mysql_convert && $same_db)
1701                          {
1702                              $src_db->sql_query("SET NAMES 'utf8'");
1703                          }
1704                      }
1705                      else
1706                      {
1707                          $db->sql_query($query_last[1]);
1708                      }
1709                  }
1710              }
1711   
1712              // Sanity check
1713              $db->sql_return_on_error(false);
1714              $src_db->sql_return_on_error(false);
1715   
1716              fix_empty_primary_groups();
1717   
1718              if (!isset($config['board_startdate']))
1719              {
1720                  $sql = 'SELECT MIN(user_regdate) AS board_startdate
1721                      FROM ' . USERS_TABLE;
1722                  $result = $db->sql_query($sql);
1723                  $row = $db->sql_fetchrow($result);
1724                  $db->sql_freeresult($result);
1725   
1726                  if (($row['board_startdate'] < $config['board_startdate'] && $row['board_startdate'] > 0) || !isset($config['board_startdate']))
1727                  {
1728                      set_config('board_startdate', $row['board_startdate']);
1729                      $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_regdate = ' . $row['board_startdate'] . ' WHERE user_id = ' . ANONYMOUS);
1730                  }
1731              }
1732   
1733              update_dynamic_config();
1734   
1735              $template->assign_block_vars('checks', array(
1736                  'TITLE'        => $user->lang['CLEAN_VERIFY'],
1737                  'RESULT'    => $user->lang['DONE'],
1738              ));
1739   
1740              $url = $this->save_convert_progress('&amp;jump=2');
1741   
1742              $template->assign_vars(array(
1743                  'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1744                  'U_ACTION'        => $url,
1745              ));
1746   
1747              $this->meta_refresh($url);
1748              return;
1749          }
1750   
1751          if ($jump == 2)
1752          {
1753              $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_permissions = ''");
1754   
1755              // TODO: sync() is likely going to bomb out on forums with a considerable amount of topics.
1756              // TODO: the sync function is able to handle FROM-TO values, we should use them here (batch processing)
1757              sync('forum', '', '', false, true);
1758              $cache->destroy('sql', FORUMS_TABLE);
1759   
1760              $template->assign_block_vars('checks', array(
1761                  'TITLE'        => $user->lang['SYNC_FORUMS'],
1762                  'RESULT'    => $user->lang['DONE'],
1763              ));
1764   
1765              // Continue with synchronizing the forums...
1766              $url = $this->save_convert_progress('&amp;sync_batch=0');
1767   
1768              $template->assign_vars(array(
1769                  'L_SUBMIT'        => $user->lang['CONTINUE_CONVERT'],
1770                  'U_ACTION'        => $url,
1771              ));
1772   
1773              $this->meta_refresh($url);
1774              return;
1775          }
1776      }
1777   
1778      function build_insert_query(&$schema, &$sql_data, $current_table)
1779      {
1780          global $db, $user;
1781          global $convert;
1782   
1783          // Can we use IGNORE with this DBMS?
1784          $sql_ignore = (strpos($db->sql_layer, 'mysql') === 0 && !defined('DEBUG_EXTRA')) ? 'IGNORE ' : '';
1785          $insert_query = 'INSERT ' . $sql_ignore . 'INTO ' . $schema['target'] . ' (';
1786   
1787          $aliases = array();
1788   
1789          $sql_data = array(
1790              'source_fields'        => array(),
1791              'target_fields'        => array(),
1792              'source_tables'        => array(),
1793              'select_fields'        => array(),
1794          );
1795   
1796          foreach ($schema as $key => $val)
1797          {
1798              // Example: array('group_name',                'extension_groups.group_name',        'htmlspecialchars'),
1799              if (is_int($key))
1800              {
1801                  if (!empty($val[0]))
1802                  {
1803                      // Target fields
1804                      $sql_data['target_fields'][$val[0]] = $key;
1805                      $insert_query .= $val[0] . ', ';
1806                  }
1807   
1808                  if (!is_array($val[1]))
1809                  {
1810                      $val[1] = array($val[1]);
1811                  }
1812   
1813                  foreach ($val[1] as $valkey => $value_1)
1814                  {
1815                      // This should cover about any case:
1816                      //
1817                      // table.field                    => SELECT table.field                FROM table
1818                      // table.field AS alias            => SELECT table.field    AS alias    FROM table
1819                      // table.field AS table2.alias    => SELECT table2.field    AS alias    FROM table table2
1820                      // table.field AS table2.field    => SELECT table2.field                FROM table table2
1821                      //
1822                      if (preg_match('/^([a-z0-9_]+)\.([a-z0-9_]+)( +AS +(([a-z0-9_]+?)\.)?([a-z0-9_]+))?$/i', $value_1, $m))
1823                      {
1824                          // There is 'AS ...' in the field names
1825                          if (!empty($m[3]))
1826                          {
1827                              $value_1 = ($m[2] == $m[6]) ? $m[1] . '.' . $m[2] : $m[1] . '.' . $m[2] . ' AS ' . $m[6];
1828   
1829                              // Table alias: store it then replace the source table with it
1830                              if (!empty($m[5]) && $m[5] != $m[1])
1831                              {
1832                                  $aliases[$m[5]] = $m[1];
1833                                  $value_1 = str_replace($m[1] . '.' . $m[2], $m[5] . '.' . $m[2], $value_1);
1834                              }
1835                          }
1836                          else
1837                          {
1838                              // No table alias
1839                              $sql_data['source_tables'][$m[1]] = (empty($convert->src_table_prefix)) ? $m[1] : $convert->src_table_prefix . $m[1] . ' ' . $m[1];
1840                          }
1841   
1842                          $sql_data['select_fields'][$value_1] = $value_1;
1843                          $sql_data['source_fields'][$key][$valkey] = (!empty($m[6])) ? $m[6] : $m[2];
1844                      }
1845                  }
1846              }
1847              else if ($key == 'where' || $key == 'group_by' || $key == 'order_by' || $key == 'having')
1848              {
1849                  if (@preg_match_all('/([a-z0-9_]+)\.([a-z0-9_]+)/i', $val, $m))
1850                  {
1851                      foreach ($m[1] as $value)
1852                      {
1853                          $sql_data['source_tables'][$value] = (empty($convert->src_table_prefix)) ? $value : $convert->src_table_prefix . $value . ' ' . $value;
1854                      }
1855                  }
1856              }
1857          }
1858   
1859          // Add the aliases to the list of tables
1860          foreach ($aliases as $alias => $table)
1861          {
1862              $sql_data['source_tables'][$alias] = $convert->src_table_prefix . $table . ' ' . $alias;
1863          }
1864   
1865          // 'left_join'        => 'forums LEFT JOIN forum_prune ON forums.forum_id = forum_prune.forum_id',
1866          if (!empty($schema['left_join']))
1867          {
1868              if (!is_array($schema['left_join']))
1869              {
1870                  $schema['left_join'] = array($schema['left_join']);
1871              }
1872   
1873              foreach ($schema['left_join'] as $left_join)
1874              {
1875                  // This won't handle concatened LEFT JOINs
1876                  if (!preg_match('/([a-z0-9_]+) LEFT JOIN ([a-z0-9_]+) A?S? ?([a-z0-9_]*?) ?(ON|USING)(.*)/i', $left_join, $m))
1877                  {
1878                      $this->p_master->error(sprintf($user->lang['NOT_UNDERSTAND'], 'LEFT JOIN', $left_join, $current_table, $schema['target']), __LINE__, __FILE__);
1879                  }
1880   
1881                  if (!empty($aliases[$m[2]]))
1882                  {
1883                      if (!empty($m[3]))
1884                      {
1885                          $this->p_master->error(sprintf($user->lang['NAMING_CONFLICT'], $m[2], $m[3], $schema['left_join']), __LINE__, __FILE__);
1886                      }
1887   
1888                      $m[2] = $aliases[$m[2]];
1889                      $m[3] = $m[2];
1890                  }
1891   
1892                  $right_table = $convert->src_table_prefix . $m[2];
1893                  if (!empty($m[3]))
1894                  {
1895                      unset($sql_data['source_tables'][$m[3]]);
1896                  }
1897                  else if ($m[2] != $m[1])
1898                  {
1899                      unset($sql_data['source_tables'][$m[2]]);
1900                  }
1901   
1902                  if (strpos($sql_data['source_tables'][$m[1]], "\nLEFT JOIN") !== false)
1903                  {
1904                      $sql_data['source_tables'][$m[1]] = '(' . $sql_data['source_tables'][$m[1]] . ")\nLEFT JOIN $right_table";
1905                  }
1906                  else
1907                  {
1908                      $sql_data['source_tables'][$m[1]] .= "\nLEFT JOIN $right_table";
1909                  }
1910   
1911                  if (!empty($m[3]))
1912                  {
1913                      unset($sql_data['source_tables'][$m[3]]);
1914                      $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[3];
1915                  }
1916                  else if (!empty($convert->src_table_prefix))
1917                  {
1918                      $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[2];
1919                  }
1920                  $sql_data['source_tables'][$m[1]] .= ' ' . $m[4] . $m[5];
1921              }
1922          }
1923   
1924          // Remove ", " from the end of the insert query
1925          $insert_query = substr($insert_query, 0, -2) . ') VALUES ';
1926   
1927          return $insert_query;
1928      }
1929   
1930      /**
1931      * Function for processing the currently handled row
1932      */
1933      function process_row(&$schema, &$sql_data, &$insert_values)
1934      {
1935          global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache;
1936          global $convert, $convert_row;
1937   
1938          $sql_flag = false;
1939   
1940          foreach ($schema as $key => $fields)
1941          {
1942              // We are only interested in the lines with:
1943              // array('comment', 'attachments_desc.comment', 'htmlspecialchars'),
1944              if (is_int($key))
1945              {
1946                  if (!is_array($fields[1]))
1947                  {
1948                      $fields[1] = array($fields[1]);
1949                  }
1950   
1951                  $firstkey_set = false;
1952                  $firstkey = 0;
1953      
1954                  foreach ($fields[1] as $inner_key => $inner_value)
1955                  {
1956                      if (!$firstkey_set)
1957                      {
1958                          $firstkey = $inner_key;
1959                          $firstkey_set = true;
1960                      }
1961   
1962                      $src_field = isset($sql_data['source_fields'][$key][$inner_key]) ? $sql_data['source_fields'][$key][$inner_key] : '';
1963   
1964                      if (!empty($src_field))
1965                      {
1966                          $fields[1][$inner_key] = $convert->row[$src_field];
1967                      }
1968                  }
1969   
1970                  if (!empty($fields[0]))
1971                  {
1972                      // We have a target field, if we haven't set $sql_flag yet it will be set to TRUE.
1973                      // If a function has already set it to FALSE it won't change it.
1974                      if ($sql_flag === false)
1975                      {
1976                          $sql_flag = true;
1977                      }
1978          
1979                      // No function assigned?
1980                      if (empty($fields[2]))
1981                      {
1982                          $value = $fields[1][$firstkey];
1983                      }
1984                      else if (is_array($fields[2]))
1985                      {
1986                          // Execute complex function/eval/typecast
1987                          $value = $fields[1];
1988   
1989                          foreach ($fields[2] as $type => $execution)
1990                          {
1991                              if (strpos($type, 'typecast') === 0)
1992                              {
1993                                  if (!is_array($value))
1994                                  {
1995                                      $value = array($value);
1996                                  }
1997                                  $value = $value[0];
1998                                  settype($value, $execution);
1999                              }
2000                              else if (strpos($type, 'function') === 0)
2001                              {
2002                                  if (!is_array($value))
2003                                  {
2004                                      $value = array($value);
2005                                  }
2006   
2007                                  $value = call_user_func_array($execution, $value);
2008                              }
2009                              else if (strpos($type, 'execute') === 0)
2010                              {
2011                                  if (!is_array($value))
2012                                  {
2013                                      $value = array($value);
2014                                  }
2015   
2016                                  $execution = str_replace('{RESULT}', '$value', $execution);
2017                                  $execution = str_replace('{VALUE}', '$value', $execution);
2018                                  eval($execution);
2019                              }
2020                          }
2021                      }
2022                      else
2023                      {
2024                          $value = call_user_func_array($fields[2], $fields[1]);
2025                      }
2026   
2027                      if (is_null($value))
2028                      {
2029                          $value = '';
2030                      }
2031   
2032                      $insert_values[] = $db->_sql_validate_value($value);
2033                  }
2034                  else if (!empty($fields[2]))
2035                  {
2036                      if (is_array($fields[2]))
2037                      {
2038                          // Execute complex function/eval/typecast
2039                          $value = '';
2040   
2041                          foreach ($fields[2] as $type => $execution)
2042                          {
2043                              if (strpos($type, 'typecast') === 0)
2044                              {
2045                                  $value = settype($value, $execution);
2046                              }
2047                              else if (strpos($type, 'function') === 0)
2048                              {
2049                                  if (!is_array($value))
2050                                  {
2051                                      $value = array($value);
2052                                  }
2053   
2054                                  $value = call_user_func_array($execution, $value);
2055                              }
2056                              else if (strpos($type, 'execute') === 0)
2057                              {
2058                                  if (!is_array($value))
2059                                  {
2060                                      $value = array($value);
2061                                  }
2062   
2063                                  $execution = str_replace('{RESULT}', '$value', $execution);
2064                                  $execution = str_replace('{VALUE}', '$value', $execution);
2065                                  eval($execution);
2066                              }
2067                          }
2068                      }
2069                      else
2070                      {
2071                          call_user_func_array($fields[2], $fields[1]);
2072                      }
2073                  }
2074              }
2075          }
2076   
2077          return $sql_flag;
2078      }
2079   
2080      /**
2081      * Own meta refresh function to be able to change the global time used
2082      */
2083      function meta_refresh($url)
2084      {
2085          global $convert, $template;
2086   
2087          if ($convert->options['refresh'])
2088          {
2089              // Because we should not rely on correct settings, we simply use the relative path here directly.
2090              $template->assign_vars(array(
2091                  'S_REFRESH'    => true,
2092                  'META'        => '<meta http-equiv="refresh" content="5;url=' . $url . '" />')
2093              );
2094          }
2095      }
2096   
2097      /**
2098      * The information below will be used to build the input fields presented to the user
2099      */
2100      var $convert_options = array(
2101          'legend1'            => 'SPECIFY_OPTIONS',
2102          'src_dbms'            => array('lang' => 'DBMS',            'type' => 'select', 'options' => 'dbms_select(\'{VALUE}\', true)', 'explain' => false),
2103          'src_dbhost'        => array('lang' => 'DB_HOST',        'type' => 'text:25:100', 'explain' => true),
2104          'src_dbport'        => array('lang' => 'DB_PORT',        'type' => 'text:25:100', 'explain' => true),
2105          'src_dbname'        => array('lang' => 'DB_NAME',        'type' => 'text:25:100', 'explain' => false),
2106          'src_dbuser'        => array('lang' => 'DB_USERNAME',    'type' => 'text:25:100', 'explain' => false),
2107          'src_dbpasswd'        => array('lang' => 'DB_PASSWORD',    'type' => 'password:25:100', 'explain' => false),
2108          'src_table_prefix'    => array('lang' => 'TABLE_PREFIX',    'type' => 'text:25:100', 'explain' => false),
2109          //'src_url'            => array('lang' => 'FORUM_ADDRESS',    'type' => 'text:50:100', 'explain' => true),
2110          'forum_path'        => array('lang' => 'FORUM_PATH',    'type' => 'text:25:100', 'explain' => true),
2111          'refresh'            => array('lang' => 'REFRESH_PAGE',    'type' => 'radio:yes_no', 'explain' => true),
2112      );
2113  }
2114   
2115  ?>