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