[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/install/ -> install_convert.php (source)

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


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