Beispiel #1
0
 /**
  * @dataProvider data_attachment_unlink
  */
 public function test_attachment_delete_success($remove_success, $exists_success, $expected, $throw_exception = false)
 {
     $this->filesystem = $this->getMock('\\phpbb\\filesystem\\filesystem', array('remove', 'exists'));
     if ($throw_exception) {
         $this->filesystem->expects($this->any())->method('remove')->willThrowException(new \phpbb\filesystem\exception\filesystem_exception());
     } else {
         $this->filesystem->expects($this->any())->method('remove')->willReturn($remove_success);
     }
     $this->filesystem->expects($this->any())->method('exists')->willReturn($exists_success);
     $this->attachment_delete = new \phpbb\attachment\delete($this->config, $this->db, $this->dispatcher, $this->filesystem, $this->resync, $this->phpbb_root_path);
     $this->assertSame($expected, $this->attachment_delete->unlink_attachment('foobar'));
 }
Beispiel #2
0
 /**
  * proxy_instantiator constructor
  * @param string $cache_dir Cache dir for fall back when using open_basedir
  */
 public function __construct($cache_dir)
 {
     $config = new Configuration();
     // Prevent trying to write to system temp dir in case of open_basedir
     // restrictions being in effect
     $ini_wrapper = new IniGetWrapper();
     $filesystem = new filesystem();
     $tmp_dir = function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : '';
     if (empty($tmp_dir) || $ini_wrapper->getString('open_basedir') && (!$filesystem->exists($tmp_dir) || !$filesystem->is_writable($tmp_dir))) {
         $config->setProxiesTargetDir($cache_dir);
     }
     $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy());
     $this->factory = new LazyLoadingValueHolderFactory($config);
 }
Beispiel #3
0
 /**
  * {@inheritdoc}
  */
 public function run()
 {
     if (!$this->iohandler->get_input('submit_continue_file_update', false)) {
         // Handle merge conflicts
         $merge_conflicts = $this->installer_config->get('merge_conflict_list', array());
         // Create archive for merge conflicts
         if (!empty($merge_conflicts)) {
             foreach ($merge_conflicts as $filename) {
                 $this->file_updater->create_new_file($filename, base64_decode($this->cache->get('_file_' . md5($filename))), true);
             }
             // Render download box
             $this->iohandler->add_download_link('phpbb_installer_update_conflict_download', 'DOWNLOAD_CONFLICTS', 'DOWNLOAD_CONFLICTS_EXPLAIN');
         }
         $this->file_updater->close();
         // Render update file statuses
         $file_update_info = $this->installer_config->get('update_files', array());
         $file_status = array('deleted' => !isset($file_update_info['delete']) ? array() : $file_update_info['delete'], 'new' => !isset($file_update_info['new']) ? array() : $file_update_info['new'], 'conflict' => $this->installer_config->get('merge_conflict_list', array()), 'modified' => !isset($file_update_info['update_with_diff']) ? array() : $file_update_info['update_with_diff'], 'not_modified' => !isset($file_update_info['update_without_diff']) ? array() : $file_update_info['update_without_diff']);
         $this->iohandler->render_update_file_status($file_status);
         // Add form to continue update
         $this->iohandler->add_user_form_group('UPDATE_CONTINUE_FILE_UPDATE', array('submit_continue_file_update' => array('label' => 'UPDATE_CONTINUE_FILE_UPDATE', 'type' => 'submit')));
         // Show results to the user
         $this->iohandler->send_response();
         throw new user_interaction_required_exception();
     } else {
         // Remove archive
         $this->filesystem->remove($this->installer_config->get('update_file_conflict_archive', null));
         $this->installer_config->set('update_file_conflict_archive', null);
     }
 }
Beispiel #4
0
 /**
  * {@inheritdoc}
  */
 public function run()
 {
     if (!$this->installer_config->has_restart_point('check_update_files')) {
         $this->installer_config->create_progress_restart_point('check_update_files');
     }
     $old_path = $this->update_helper->get_path_to_old_update_files();
     $new_path = $this->update_helper->get_path_to_new_update_files();
     $update_info = $this->installer_config->get('update_info', array());
     $file_update_info = $this->installer_config->get('update_files', array());
     if (empty($update_info)) {
         $root_path = $this->phpbb_root_path;
         $update_info = $this->installer_config->get('update_info_unprocessed', array());
         $file_update_info = array();
         $file_update_info['update_without_diff'] = array_diff($update_info['binary'], $update_info['deleted']);
         // Filter out files that are already deleted
         $file_update_info['delete'] = array_filter($update_info['deleted'], function ($filename) use($root_path) {
             return file_exists($root_path . $filename);
         });
     }
     $progress_count = $this->installer_config->get('file_check_progress_count', 0);
     $task_count = count($update_info['files']);
     $this->iohandler->set_task_count($task_count);
     $this->iohandler->set_progress('UPDATE_CHECK_FILES', 0);
     foreach ($update_info['files'] as $key => $filename) {
         $old_file = $old_path . $filename;
         $new_file = $new_path . $filename;
         $file = $this->phpbb_root_path . $filename;
         if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0) {
             // Save progress
             $this->installer_config->set('update_info', $update_info);
             $this->installer_config->set('file_check_progress_count', $progress_count);
             $this->installer_config->set('update_files', $file_update_info);
             // Request refresh
             throw new resource_limit_reached_exception();
         }
         $progress_count++;
         $this->iohandler->set_progress('UPDATE_CHECK_FILES', $progress_count);
         if (!$this->filesystem->exists($file)) {
             $file_update_info['new'][] = $filename;
         } else {
             $file_checksum = md5_file($file);
             if ($file_checksum === md5_file($new_file)) {
                 // File already up to date
                 continue;
             } else {
                 if ($this->filesystem->exists($old_file) && $file_checksum === md5_file($old_file)) {
                     // No need to diff the file
                     $file_update_info['update_without_diff'][] = $filename;
                 } else {
                     $file_update_info['update_with_diff'][] = $filename;
                 }
             }
         }
         unset($update_info['files'][$key]);
     }
     $this->installer_config->set('update_files', $file_update_info);
     $this->installer_config->set('update_info', array());
 }
Beispiel #5
0
 /**
  * Creates directory structure
  *
  * @param string	$path	Path to the directory where the file should be placed (and non-existent)
  */
 private function make_dir($path)
 {
     if (is_dir($path)) {
         return;
     }
     $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
     $this->filesystem->mkdir($path, 493);
     // 493 === 0755
 }
 /**
  * {@inheritdoc}
  */
 public function run()
 {
     if ($this->iohandler->get_input('database_update_submit', false)) {
         // Remove archive
         $this->filesystem->remove($this->installer_config->get('update_file_archive', null));
         $this->installer_config->set('update_file_archive', null);
     } else {
         if ($this->iohandler->get_input('update_recheck_files_submit', false)) {
             throw new jump_to_restart_point_exception('check_update_files');
         } else {
             // Render download box
             $this->iohandler->add_download_link('phpbb_installer_update_file_download', 'DOWNLOAD_UPDATE_METHOD', 'DOWNLOAD_UPDATE_METHOD_EXPLAIN');
             // Add form to continue update
             $this->iohandler->add_user_form_group('UPDATE_CONTINUE_UPDATE_PROCESS', array('update_recheck_files_submit' => array('label' => 'UPDATE_RECHECK_UPDATE_FILES', 'type' => 'submit'), 'database_update_submit' => array('label' => 'UPDATE_CONTINUE_UPDATE_PROCESS', 'type' => 'submit')));
             throw new user_interaction_required_exception();
         }
     }
 }
Beispiel #7
0
 /**
  * {@inheritdoc}
  */
 public function run()
 {
     // Array of update files
     $update_files = array($this->phpbb_root_path . 'install/update', $this->phpbb_root_path . 'install/update/index.' . $this->php_ext);
     // Check for a valid update directory
     if (!$this->filesystem->exists($update_files) || !$this->filesystem->is_readable($update_files)) {
         $this->iohandler->add_warning_message('UPDATE_FILES_NOT_FOUND');
         $this->set_test_passed(false);
         // If there are no update files, we can't check the version etc
         // However, we can let the users run migrations if they really want to...
         $this->installer_config->set('disable_filesystem_update', true);
         return true;
     }
     // Recover version numbers
     $update_info = array();
     @(include $this->phpbb_root_path . 'install/update/index.' . $this->php_ext);
     $info = empty($update_info) || !is_array($update_info) ? false : $update_info;
     $update_version = false;
     if ($info !== false) {
         $update_version = !empty($info['version']['to']) ? trim($info['version']['to']) : false;
     }
     // Get current and latest version
     try {
         $latest_version = $this->version_helper->get_latest_on_current_branch(true);
     } catch (\RuntimeException $e) {
         $latest_version = $update_version;
     }
     $current_version = !empty($this->config['version_update_from']) ? $this->config['version_update_from'] : $this->config['version'];
     // Check if the update package
     if (!$this->update_helper->phpbb_version_compare($current_version, $update_version, '<')) {
         $this->iohandler->add_error_message('NO_UPDATE_FILES_UP_TO_DATE');
         $this->tests_passed = false;
     }
     // Check if the update package works with the installed version
     if (empty($info['version']['from']) || $info['version']['from'] !== $current_version) {
         $this->iohandler->add_error_message(array('INCOMPATIBLE_UPDATE_FILES', $current_version, $info['version']['from'], $update_version));
         $this->tests_passed = false;
     }
     // check if this is the latest update package
     if ($this->update_helper->phpbb_version_compare($update_version, $latest_version, '<')) {
         $this->iohandler->add_warning_message(array('OLD_UPDATE_FILES', $info['version']['from'], $update_version, $latest_version));
     }
     return $this->tests_passed;
 }
Beispiel #8
0
 /**
  * Set path component
  *
  * @param string $path Path component
  * @param boolean $urlencode If true, parts of path should be encoded with rawurlencode()
  */
 public function set_path($path, $urlencode = false)
 {
     // Since 1.7.0 Twig returns the real path of the file. We need it to be relative.
     $real_root_path = $this->filesystem->realpath($this->path_helper->get_phpbb_root_path()) . DIRECTORY_SEPARATOR;
     // If the asset is under the phpBB root path we need to remove its path and then prepend $phpbb_root_path
     if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path) {
         $path = $this->path_helper->get_phpbb_root_path() . str_replace('\\', '/', substr($path, strlen($real_root_path)));
     } else {
         // Else we make the path relative to the current working directory
         $real_root_path = $this->filesystem->realpath('.') . DIRECTORY_SEPARATOR;
         if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path) {
             $path = str_replace('\\', '/', substr($path, strlen($real_root_path)));
         }
     }
     if ($urlencode) {
         $paths = explode('/', $path);
         foreach ($paths as &$dir) {
             $dir = rawurlencode($dir);
         }
         $path = implode('/', $paths);
     }
     $this->components['path'] = $path;
 }
Beispiel #9
0
    /**
     * Delete attachment from filesystem
     *
     * @param string $filename Filename of attachment
     * @param string $mode Delete mode
     * @param bool $entry_removed Whether entry was removed. Defaults to false
     * @return bool True if file was removed, false if not
     */
    public function unlink_attachment($filename, $mode = 'file', $entry_removed = false)
    {
        // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
        $sql = 'SELECT COUNT(attach_id) AS num_entries
		FROM ' . ATTACHMENTS_TABLE . "\n\t\tWHERE physical_filename = '" . $this->db->sql_escape(utf8_basename($filename)) . "'";
        $result = $this->db->sql_query($sql);
        $num_entries = (int) $this->db->sql_fetchfield('num_entries');
        $this->db->sql_freeresult($result);
        // Do not remove file if at least one additional entry with the same name exist.
        if ($entry_removed && $num_entries > 0 || !$entry_removed && $num_entries > 1) {
            return false;
        }
        $filename = $mode == 'thumbnail' ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
        $filepath = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename;
        try {
            if ($this->filesystem->exists($filepath)) {
                $this->filesystem->remove($this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename);
                return true;
            }
        } catch (\phpbb\filesystem\exception\filesystem_exception $exception) {
            // Fail is covered by return statement below
        }
        return false;
    }
Beispiel #10
0
 /**
  * Build and return a new Container respecting the current configuration
  *
  * @return \phpbb_cache_container|ContainerBuilder
  */
 public function get_container()
 {
     $container_filename = $this->get_container_filename();
     $config_cache = new ConfigCache($container_filename, defined('DEBUG'));
     if ($this->use_cache && $config_cache->isFresh()) {
         require $config_cache->getPath();
         $this->container = new \phpbb_cache_container();
     } else {
         $this->container_extensions = array(new extension\core($this->get_config_path()));
         if ($this->use_extensions) {
             $this->load_extensions();
         }
         // Inject the config
         if ($this->config_php_file) {
             $this->container_extensions[] = new extension\config($this->config_php_file);
         }
         $this->container = $this->create_container($this->container_extensions);
         // Easy collections through tags
         $this->container->addCompilerPass(new pass\collection_pass());
         // Event listeners "phpBB style"
         $this->container->addCompilerPass(new RegisterListenersPass('dispatcher', 'event.listener_listener', 'event.listener'));
         // Event listeners "Symfony style"
         $this->container->addCompilerPass(new RegisterListenersPass('dispatcher'));
         $filesystem = new filesystem();
         $loader = new YamlFileLoader($this->container, new FileLocator($filesystem->realpath($this->get_config_path())));
         $loader->load($this->container->getParameter('core.environment') . '/config.yml');
         $this->inject_custom_parameters();
         if ($this->compile_container) {
             $this->container->compile();
             if ($this->use_cache) {
                 $this->dump_container($config_cache);
             }
         }
     }
     if ($this->compile_container && $this->config_php_file) {
         $this->container->set('config.php', $this->config_php_file);
     }
     return $this->container;
 }
 /**
  * Build and return a new Container respecting the current configuration
  *
  * @return \phpbb_cache_container|ContainerBuilder
  */
 public function get_container()
 {
     try {
         $container_filename = $this->get_container_filename();
         $config_cache = new ConfigCache($container_filename, defined('DEBUG'));
         if ($this->use_cache && $config_cache->isFresh()) {
             if ($this->use_extensions) {
                 require $this->get_autoload_filename();
             }
             require $config_cache->getPath();
             $this->container = new \phpbb_cache_container();
         } else {
             $this->container_extensions = array(new extension\core($this->get_config_path()));
             if ($this->use_extensions) {
                 $this->load_extensions();
             }
             // Inject the config
             if ($this->config_php_file) {
                 $this->container_extensions[] = new extension\config($this->config_php_file);
             }
             $this->container = $this->create_container($this->container_extensions);
             // Easy collections through tags
             $this->container->addCompilerPass(new pass\collection_pass());
             // Event listeners "phpBB style"
             $this->container->addCompilerPass(new RegisterListenersPass('dispatcher', 'event.listener_listener', 'event.listener'));
             // Event listeners "Symfony style"
             $this->container->addCompilerPass(new RegisterListenersPass('dispatcher'));
             if ($this->use_extensions) {
                 $this->register_ext_compiler_pass();
             }
             $filesystem = new filesystem();
             $loader = new YamlFileLoader($this->container, new FileLocator($filesystem->realpath($this->get_config_path())));
             $loader->load($this->container->getParameter('core.environment') . '/config.yml');
             $this->inject_custom_parameters();
             if ($this->compile_container) {
                 $this->container->compile();
                 if ($this->use_cache) {
                     $this->dump_container($config_cache);
                 }
             }
         }
         if ($this->compile_container && $this->config_php_file) {
             $this->container->set('config.php', $this->config_php_file);
         }
         return $this->container;
     } catch (\Exception $e) {
         // Don't try to recover if we are in the development environment
         if ($this->get_environment() === 'development') {
             throw $e;
         }
         if ($this->build_exception === null) {
             $this->build_exception = $e;
             return $this->without_extensions()->without_cache()->with_custom_parameters(array_merge($this->custom_parameters, ['container_exception' => $e]))->get_container();
         } else {
             // Rethrow the original exception if it's still failing
             throw $this->build_exception;
         }
     }
 }
Beispiel #12
0
 /**
  * {@inheritdoc}
  */
 public function run()
 {
     if (!$this->installer_config->has_restart_point('check_update_files')) {
         $this->installer_config->create_progress_restart_point('check_update_files');
     }
     $old_path = $this->update_helper->get_path_to_old_update_files();
     $new_path = $this->update_helper->get_path_to_new_update_files();
     $update_info = $this->installer_config->get('update_info', array());
     $file_update_info = $this->installer_config->get('update_files', array());
     if (empty($update_info)) {
         $root_path = $this->phpbb_root_path;
         $update_info = $this->installer_config->get('update_info_unprocessed', array());
         $file_update_info = array();
         $file_update_info['update_without_diff'] = array_diff($update_info['binary'], $update_info['deleted']);
         // Filter out files that are already deleted
         $file_update_info['delete'] = array_filter($update_info['deleted'], function ($filename) use($root_path) {
             return file_exists($root_path . $filename);
         });
     }
     $progress_count = $this->installer_config->get('file_check_progress_count', 0);
     $task_count = count($update_info['files']);
     $this->iohandler->set_task_count($task_count);
     $this->iohandler->set_progress('UPDATE_CHECK_FILES', 0);
     // Create list of default extensions that should have been added prior
     // to this update
     $default_update_extensions = [];
     foreach (\phpbb\install\module\update_database\task\update_extensions::$default_extensions_update as $version => $extensions) {
         if ($this->update_helper->phpbb_version_compare($update_info['version']['from'], $version, '>')) {
             $default_update_extensions = array_merge($default_update_extensions, $extensions);
         }
     }
     foreach ($update_info['files'] as $key => $filename) {
         $old_file = $old_path . $filename;
         $new_file = $new_path . $filename;
         $file = $this->phpbb_root_path . $filename;
         if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0) {
             // Save progress
             $this->installer_config->set('update_info', $update_info);
             $this->installer_config->set('file_check_progress_count', $progress_count);
             $this->installer_config->set('update_files', $file_update_info);
             // Request refresh
             throw new resource_limit_reached_exception();
         }
         $progress_count++;
         $this->iohandler->set_progress('UPDATE_CHECK_FILES', $progress_count);
         // Do not copy default extension again if the previous version was
         // packaged with it but it does not exist (e.g. deleted by admin)
         if (strpos($file, $this->phpbb_root_path . 'ext/') !== false) {
             $skip_file = false;
             foreach ($default_update_extensions as $ext_name) {
                 if (strpos($file, $this->phpbb_root_path . 'ext/' . $ext_name) !== false && !$this->filesystem->exists($this->phpbb_root_path . 'ext/' . $ext_name . '/composer.json')) {
                     $skip_file = true;
                     break;
                 }
             }
             if ($skip_file) {
                 continue;
             }
         }
         if (!$this->filesystem->exists($file)) {
             $file_update_info['new'][] = $filename;
         } else {
             $file_checksum = md5_file($file);
             if ($file_checksum === md5_file($new_file)) {
                 // File already up to date
                 continue;
             } else {
                 if ($this->filesystem->exists($old_file) && $file_checksum === md5_file($old_file)) {
                     // No need to diff the file
                     $file_update_info['update_without_diff'][] = $filename;
                 } else {
                     $file_update_info['update_with_diff'][] = $filename;
                 }
             }
         }
         unset($update_info['files'][$key]);
     }
     $this->installer_config->set('update_files', $file_update_info);
     $this->installer_config->set('update_info', array());
 }
Beispiel #13
0
 /**
  * The function which does the actual work (or dispatches it to the relevant places)
  */
 function convert_data($converter)
 {
     global $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache, $auth;
     global $convert, $convert_row, $message_parser, $skip_rows, $language;
     global $request, $phpbb_dispatcher;
     $phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
     extract($phpbb_config_php_file->get_all());
     require_once $phpbb_root_path . 'includes/constants.' . $phpEx;
     require_once $phpbb_root_path . 'includes/functions_convert.' . $phpEx;
     $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
     /** @var \phpbb\db\driver\driver_interface $db */
     $db = new $dbms();
     $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
     unset($dbpasswd);
     // We need to fill the config to let internal functions correctly work
     $config = new \phpbb\config\db($db, new \phpbb\cache\driver\dummy(), CONFIG_TABLE);
     // Override a couple of config variables for the duration
     $config['max_quote_depth'] = 0;
     // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
     $config['max_post_chars'] = $config['min_post_chars'] = 0;
     // Set up a user as well. We _should_ have enough of a database here at this point to do this
     // and it helps for any core code we call
     $user->session_begin();
     $user->page = $user->extract_current_page($phpbb_root_path);
     $convert->options = array();
     if (isset($config['convert_progress'])) {
         $convert->options = unserialize($config['convert_progress']);
         $convert->options = array_merge($convert->options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
     }
     // This information should have already been checked once, but do it again for safety
     if (empty($convert->options) || empty($convert->options['tag']) || !isset($convert->options['dbms']) || !isset($convert->options['dbhost']) || !isset($convert->options['dbport']) || !isset($convert->options['dbuser']) || !isset($convert->options['dbpasswd']) || !isset($convert->options['dbname']) || !isset($convert->options['table_prefix'])) {
         $this->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
     }
     $this->template->assign_var('S_CONV_IN_PROGRESS', true);
     // Make some short variables accessible, for easier referencing
     $convert->convertor_tag = basename($convert->options['tag']);
     $convert->src_dbms = $convert->options['dbms'];
     $convert->src_dbhost = $convert->options['dbhost'];
     $convert->src_dbport = $convert->options['dbport'];
     $convert->src_dbuser = $convert->options['dbuser'];
     $convert->src_dbpasswd = $convert->options['dbpasswd'];
     $convert->src_dbname = $convert->options['dbname'];
     $convert->src_table_prefix = $convert->options['table_prefix'];
     // initiate database connection to old db if old and new db differ
     global $src_db, $same_db;
     $src_db = $same_db = null;
     if ($convert->src_dbms != $dbms || $convert->src_dbhost != $dbhost || $convert->src_dbport != $dbport || $convert->src_dbname != $dbname || $convert->src_dbuser != $dbuser) {
         $dbms = $convert->src_dbms;
         /** @var \phpbb\db\driver\driver $src_db */
         $src_db = new $dbms();
         $src_db->sql_connect($convert->src_dbhost, $convert->src_dbuser, htmlspecialchars_decode($convert->src_dbpasswd), $convert->src_dbname, $convert->src_dbport, false, true);
         $same_db = false;
     } else {
         $src_db = $db;
         $same_db = true;
     }
     $convert->mysql_convert = false;
     switch ($src_db->sql_layer) {
         case 'sqlite':
         case 'sqlite3':
             $convert->src_truncate_statement = 'DELETE FROM ';
             break;
             // Thanks MySQL, for silently converting...
         // Thanks MySQL, for silently converting...
         case 'mysql':
         case 'mysql4':
             if (version_compare($src_db->sql_server_info(true, false), '4.1.3', '>=')) {
                 $convert->mysql_convert = true;
             }
             $convert->src_truncate_statement = 'TRUNCATE TABLE ';
             break;
         case 'mysqli':
             $convert->mysql_convert = true;
             $convert->src_truncate_statement = 'TRUNCATE TABLE ';
             break;
         default:
             $convert->src_truncate_statement = 'TRUNCATE TABLE ';
             break;
     }
     if ($convert->mysql_convert && !$same_db) {
         $src_db->sql_query("SET NAMES 'binary'");
     }
     switch ($db->get_sql_layer()) {
         case 'sqlite':
         case 'sqlite3':
             $convert->truncate_statement = 'DELETE FROM ';
             break;
         default:
             $convert->truncate_statement = 'TRUNCATE TABLE ';
             break;
     }
     $get_info = false;
     // check security implications of direct inclusion
     if (!file_exists('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx)) {
         $this->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
     }
     if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx)) {
         include_once './convertors/functions_' . $convert->convertor_tag . '.' . $phpEx;
     }
     $get_info = true;
     include './convertors/convert_' . $convert->convertor_tag . '.' . $phpEx;
     // Map some variables...
     $convert->convertor_data = $convertor_data;
     $convert->tables = $tables;
     $convert->config_schema = $config_schema;
     // Now include the real data
     $get_info = false;
     include './convertors/convert_' . $convert->convertor_tag . '.' . $phpEx;
     $convert->convertor_data = $convertor_data;
     $convert->tables = $tables;
     $convert->config_schema = $config_schema;
     $convert->convertor = $convertor;
     // The test_file is a file that should be present in the location of the old board.
     if (!file_exists($convert->options['forum_path'] . '/' . $test_file)) {
         $this->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->options['forum_path']), __LINE__, __FILE__);
     }
     $search_type = $config['search_type'];
     // For conversions we are a bit less strict and set to a search backend we know exist...
     if (!class_exists($search_type)) {
         $search_type = '\\phpbb\\search\\fulltext_native';
         $config->set('search_type', $search_type);
     }
     if (!class_exists($search_type)) {
         trigger_error('NO_SUCH_SEARCH_MODULE');
     }
     $error = false;
     $convert->fulltext_search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
     if ($error) {
         trigger_error($error);
     }
     include_once $phpbb_root_path . 'includes/message_parser.' . $phpEx;
     $message_parser = new \parse_message();
     $jump = $request->variable('jump', 0);
     $final_jump = $request->variable('final_jump', 0);
     $sync_batch = $request->variable('sync_batch', -1);
     $last_statement = $request->variable('last', 0);
     // We are running sync...
     if ($sync_batch >= 0) {
         $this->sync_forums($converter, $sync_batch);
         return;
     }
     if ($jump) {
         $this->jump($converter, $jump, $last_statement);
         return;
     }
     if ($final_jump) {
         $this->final_jump($final_jump);
         return;
     }
     $current_table = $request->variable('current_table', 0);
     $old_current_table = min(-1, $current_table - 1);
     $skip_rows = $request->variable('skip_rows', 0);
     if (!$current_table && !$skip_rows) {
         if (!$request->variable('confirm', false)) {
             // If avatars / ranks / smilies folders are specified make sure they are writable
             $bad_folders = array();
             $local_paths = array('avatar_path' => path($config['avatar_path']), 'avatar_gallery_path' => path($config['avatar_gallery_path']), 'icons_path' => path($config['icons_path']), 'ranks_path' => path($config['ranks_path']), 'smilies_path' => path($config['smilies_path']));
             foreach ($local_paths as $folder => $local_path) {
                 if (isset($convert->convertor[$folder])) {
                     if (empty($convert->convertor['test_file'])) {
                         // test_file is mandantory at the moment so this should never be reached, but just in case...
                         $this->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
                     }
                     if (!$local_path || !$this->filesystem->is_writable($phpbb_root_path . $local_path)) {
                         if (!$local_path) {
                             $bad_folders[] = sprintf($user->lang['CONFIG_PHPBB_EMPTY'], $folder);
                         } else {
                             $bad_folders[] = $local_path;
                         }
                     }
                 }
             }
             if (sizeof($bad_folders)) {
                 $msg = sizeof($bad_folders) == 1 ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
                 sort($bad_folders);
                 $this->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true);
                 $this->template->assign_vars(array('L_SUBMIT' => $user->lang['INSTALL_TEST'], 'U_ACTION' => $this->controller_helper->route('phpbb_convert_convert', array('converter' => $converter))));
                 return;
             }
             // Grab all the tables used in convertor
             $missing_tables = $tables_list = $aliases = array();
             foreach ($convert->convertor['schema'] as $schema) {
                 // Skip those not used (because of addons/plugins not detected)
                 if (!$schema['target']) {
                     continue;
                 }
                 foreach ($schema as $key => $val) {
                     // we're dealing with an array like:
                     // array('forum_status',			'forums.forum_status',				'is_item_locked')
                     if (is_int($key) && !empty($val[1])) {
                         $temp_data = $val[1];
                         if (!is_array($temp_data)) {
                             $temp_data = array($temp_data);
                         }
                         foreach ($temp_data as $value) {
                             if (preg_match('/([a-z0-9_]+)\\.([a-z0-9_]+)\\)* ?A?S? ?([a-z0-9_]*?)\\.?([a-z0-9_]*)$/i', $value, $m)) {
                                 $table = $convert->src_table_prefix . $m[1];
                                 $tables_list[$table] = $table;
                                 if (!empty($m[3])) {
                                     $aliases[] = $convert->src_table_prefix . $m[3];
                                 }
                             }
                         }
                     } else {
                         if ($key == 'left_join') {
                             // Convert the value if it wasn't an array already.
                             if (!is_array($val)) {
                                 $val = array($val);
                             }
                             for ($j = 0; $j < sizeof($val); ++$j) {
                                 if (preg_match('/LEFT JOIN ([a-z0-9_]+) AS ([a-z0-9_]+)/i', $val[$j], $m)) {
                                     $table = $convert->src_table_prefix . $m[1];
                                     $tables_list[$table] = $table;
                                     if (!empty($m[2])) {
                                         $aliases[] = $convert->src_table_prefix . $m[2];
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
             // Remove aliased tables from $tables_list
             foreach ($aliases as $alias) {
                 unset($tables_list[$alias]);
             }
             // Check if the tables that we need exist
             $src_db->sql_return_on_error(true);
             foreach ($tables_list as $table => $null) {
                 $sql = 'SELECT 1 FROM ' . $table;
                 $_result = $src_db->sql_query_limit($sql, 1);
                 if (!$_result) {
                     $missing_tables[] = $table;
                 }
                 $src_db->sql_freeresult($_result);
             }
             $src_db->sql_return_on_error(false);
             // Throw an error if some tables are missing
             // 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
             if (sizeof($missing_tables) == sizeof($tables_list)) {
                 $this->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
             } else {
                 if (sizeof($missing_tables)) {
                     $this->error(sprintf($user->lang['TABLES_MISSING'], implode($user->lang['COMMA_SEPARATOR'], $missing_tables)) . '<br /><br />' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
                 }
             }
             $url = $this->save_convert_progress($converter, 'confirm=1');
             $msg = $user->lang['PRE_CONVERT_COMPLETE'];
             if ($convert->convertor_data['author_notes']) {
                 $msg .= '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
             }
             $this->template->assign_vars(array('L_SUBMIT' => $user->lang['CONTINUE_CONVERT'], 'BODY' => $msg, 'U_ACTION' => $url));
             return;
         }
         // if (!$request->variable('confirm', false)))
         $this->template->assign_block_vars('checks', array('S_LEGEND' => true, 'LEGEND' => $user->lang['STARTING_CONVERT']));
         // Convert the config table and load the settings of the old board
         if (!empty($convert->config_schema)) {
             restore_config($convert->config_schema);
             // Override a couple of config variables for the duration
             $config['max_quote_depth'] = 0;
             // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
             $config['max_post_chars'] = $config['min_post_chars'] = 0;
         }
         $this->template->assign_block_vars('checks', array('TITLE' => $user->lang['CONFIG_CONVERT'], 'RESULT' => $user->lang['DONE']));
         // Now process queries and execute functions that have to be executed prior to the conversion
         if (!empty($convert->convertor['execute_first'])) {
             // @codingStandardsIgnoreStart
             eval($convert->convertor['execute_first']);
             // @codingStandardsIgnoreEnd
         }
         if (!empty($convert->convertor['query_first'])) {
             if (!is_array($convert->convertor['query_first'])) {
                 $convert->convertor['query_first'] = array('target', array($convert->convertor['query_first']));
             } else {
                 if (!is_array($convert->convertor['query_first'][0])) {
                     $convert->convertor['query_first'] = array(array($convert->convertor['query_first'][0], $convert->convertor['query_first'][1]));
                 }
             }
             foreach ($convert->convertor['query_first'] as $query_first) {
                 if ($query_first[0] == 'src') {
                     if ($convert->mysql_convert && $same_db) {
                         $src_db->sql_query("SET NAMES 'binary'");
                     }
                     $src_db->sql_query($query_first[1]);
                     if ($convert->mysql_convert && $same_db) {
                         $src_db->sql_query("SET NAMES 'utf8'");
                     }
                 } else {
                     $db->sql_query($query_first[1]);
                 }
             }
         }
         $this->template->assign_block_vars('checks', array('TITLE' => $user->lang['PREPROCESS_STEP'], 'RESULT' => $user->lang['DONE']));
     }
     // if (!$current_table && !$skip_rows)
     $this->template->assign_block_vars('checks', array('S_LEGEND' => true, 'LEGEND' => $user->lang['FILLING_TABLES']));
     // This loop takes one target table and processes it
     while ($current_table < sizeof($convert->convertor['schema'])) {
         $schema = $convert->convertor['schema'][$current_table];
         // The target table isn't set, this can be because a module (for example the attachement mod) is taking care of this.
         if (empty($schema['target'])) {
             $current_table++;
             continue;
         }
         $this->template->assign_block_vars('checks', array('TITLE' => sprintf($user->lang['FILLING_TABLE'], $schema['target'])));
         // This is only the case when we first start working on the tables.
         if (!$skip_rows) {
             // process execute_first and query_first for this table...
             if (!empty($schema['execute_first'])) {
                 // @codingStandardsIgnoreStart
                 eval($schema['execute_first']);
                 // @codingStandardsIgnoreEnd
             }
             if (!empty($schema['query_first'])) {
                 if (!is_array($schema['query_first'])) {
                     $schema['query_first'] = array('target', array($schema['query_first']));
                 } else {
                     if (!is_array($schema['query_first'][0])) {
                         $schema['query_first'] = array(array($schema['query_first'][0], $schema['query_first'][1]));
                     }
                 }
                 foreach ($schema['query_first'] as $query_first) {
                     if ($query_first[0] == 'src') {
                         if ($convert->mysql_convert && $same_db) {
                             $src_db->sql_query("SET NAMES 'binary'");
                         }
                         $src_db->sql_query($query_first[1]);
                         if ($convert->mysql_convert && $same_db) {
                             $src_db->sql_query("SET NAMES 'utf8'");
                         }
                     } else {
                         $db->sql_query($query_first[1]);
                     }
                 }
             }
             if (!empty($schema['autoincrement'])) {
                 switch ($db->get_sql_layer()) {
                     case 'postgres':
                         $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'] . '));');
                         break;
                     case 'oracle':
                         $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
                         $row = $db->sql_fetchrow($result);
                         $db->sql_freeresult($result);
                         $largest_id = (int) $row['max_id'];
                         if ($largest_id) {
                             $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
                             $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
                         }
                         break;
                 }
             }
         }
         // Process execute_always for this table
         // This is for code which needs to be executed on every pass of this table if
         // it gets split because of time restrictions
         if (!empty($schema['execute_always'])) {
             // @codingStandardsIgnoreStart
             eval($schema['execute_always']);
             // @codingStandardsIgnoreEnd
         }
         //
         // Set up some variables
         //
         // $waiting_rows	holds rows for multirows insertion (MySQL only)
         // $src_tables		holds unique tables with aliases to select from
         // $src_fields		will quickly refer source fields (or aliases) corresponding to the current index
         // $select_fields	holds the names of the fields to retrieve
         //
         $sql_data = array('source_fields' => array(), 'target_fields' => array(), 'source_tables' => array(), 'select_fields' => array());
         // This statement is building the keys for later insertion.
         $insert_query = $this->build_insert_query($schema, $sql_data, $current_table);
         // If no source table is affected, we skip the table
         if (empty($sql_data['source_tables'])) {
             $skip_rows = 0;
             $current_table++;
             continue;
         }
         $distinct = !empty($schema['distinct']) ? 'DISTINCT ' : '';
         $sql = 'SELECT ' . $distinct . implode(', ', $sql_data['select_fields']) . " \nFROM " . implode(', ', $sql_data['source_tables']);
         // Where
         $sql .= !empty($schema['where']) ? "\nWHERE (" . $schema['where'] . ')' : '';
         // Group By
         if (!empty($schema['group_by'])) {
             $schema['group_by'] = array($schema['group_by']);
             foreach ($sql_data['select_fields'] as $select) {
                 $alias = strpos(strtolower($select), ' as ');
                 $select = $alias ? substr($select, 0, $alias) : $select;
                 if (!in_array($select, $schema['group_by'])) {
                     $schema['group_by'][] = $select;
                 }
             }
         }
         $sql .= !empty($schema['group_by']) ? "\nGROUP BY " . implode(', ', $schema['group_by']) : '';
         // Having
         $sql .= !empty($schema['having']) ? "\nHAVING " . $schema['having'] : '';
         // Order By
         if (empty($schema['order_by']) && !empty($schema['primary'])) {
             $schema['order_by'] = $schema['primary'];
         }
         $sql .= !empty($schema['order_by']) ? "\nORDER BY " . $schema['order_by'] : '';
         // Counting basically holds the amount of rows processed.
         $counting = -1;
         $batch_time = 0;
         while ($counting === -1 || $counting >= $convert->batch_size && still_on_time()) {
             $old_current_table = $current_table;
             $rows = '';
             $waiting_rows = array();
             if (!empty($batch_time)) {
                 $mtime = explode(' ', microtime());
                 $mtime = $mtime[0] + $mtime[1];
                 $rows = ceil($counting / ($mtime - $batch_time)) . " rows/s ({$counting} rows) | ";
             }
             $this->template->assign_block_vars('checks', array('TITLE' => "skip_rows = {$skip_rows}", 'RESULT' => $rows . (defined('DEBUG') && function_exists('memory_get_usage') ? ceil(memory_get_usage() / 1024) . ' ' . $user->lang['KIB'] : '')));
             $mtime = explode(' ', microtime());
             $batch_time = $mtime[0] + $mtime[1];
             if ($convert->mysql_convert && $same_db) {
                 $src_db->sql_query("SET NAMES 'binary'");
             }
             // Take skip rows into account and only fetch batch_size amount of rows
             $___result = $src_db->sql_query_limit($sql, $convert->batch_size, $skip_rows);
             if ($convert->mysql_convert && $same_db) {
                 $src_db->sql_query("SET NAMES 'utf8'");
             }
             // This loop processes each row
             $counting = 0;
             $convert->row = $convert_row = array();
             if (!empty($schema['autoincrement'])) {
                 switch ($db->get_sql_layer()) {
                     case 'mssql':
                     case 'mssql_odbc':
                     case 'mssqlnative':
                         $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' ON');
                         break;
                 }
             }
             // Now handle the rows until time is over or no more rows to process...
             while ($counting === 0 || still_on_time()) {
                 $convert_row = $src_db->sql_fetchrow($___result);
                 if (!$convert_row) {
                     // move to the next batch or table
                     break;
                 }
                 // With this we are able to always save the last state
                 $convert->row = $convert_row;
                 // Increment the counting variable, it stores the number of rows we have processed
                 $counting++;
                 $insert_values = array();
                 $sql_flag = $this->process_row($schema, $sql_data, $insert_values);
                 if ($sql_flag === true) {
                     switch ($db->get_sql_layer()) {
                         // If MySQL, we'll wait to have num_wait_rows rows to submit at once
                         case 'mysql':
                         case 'mysql4':
                         case 'mysqli':
                             $waiting_rows[] = '(' . implode(', ', $insert_values) . ')';
                             if (sizeof($waiting_rows) >= $convert->num_wait_rows) {
                                 $errored = false;
                                 $db->sql_return_on_error(true);
                                 if (!$db->sql_query($insert_query . implode(', ', $waiting_rows))) {
                                     $errored = true;
                                 }
                                 $db->sql_return_on_error(false);
                                 if ($errored) {
                                     $db->sql_return_on_error(true);
                                     // Because it errored out we will try to insert the rows one by one... most of the time this
                                     // is caused by duplicate entries - but we also do not want to miss one...
                                     foreach ($waiting_rows as $waiting_sql) {
                                         if (!$db->sql_query($insert_query . $waiting_sql)) {
                                             $this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
                                         }
                                     }
                                     $db->sql_return_on_error(false);
                                 }
                                 $waiting_rows = array();
                             }
                             break;
                         default:
                             $insert_sql = $insert_query . '(' . implode(', ', $insert_values) . ')';
                             $db->sql_return_on_error(true);
                             if (!$db->sql_query($insert_sql)) {
                                 $this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
                             }
                             $db->sql_return_on_error(false);
                             $waiting_rows = array();
                             break;
                     }
                 }
                 $skip_rows++;
             }
             $src_db->sql_freeresult($___result);
             // We might still have some rows waiting
             if (sizeof($waiting_rows)) {
                 $errored = false;
                 $db->sql_return_on_error(true);
                 if (!$db->sql_query($insert_query . implode(', ', $waiting_rows))) {
                     $errored = true;
                 }
                 $db->sql_return_on_error(false);
                 if ($errored) {
                     $db->sql_return_on_error(true);
                     // Because it errored out we will try to insert the rows one by one... most of the time this
                     // is caused by duplicate entries - but we also do not want to miss one...
                     foreach ($waiting_rows as $waiting_sql) {
                         $db->sql_query($insert_query . $waiting_sql);
                         $this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
                     }
                     $db->sql_return_on_error(false);
                 }
                 $waiting_rows = array();
             }
             if (!empty($schema['autoincrement'])) {
                 switch ($db->get_sql_layer()) {
                     case 'mssql':
                     case 'mssql_odbc':
                     case 'mssqlnative':
                         $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' OFF');
                         break;
                     case 'postgres':
                         $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'] . '));');
                         break;
                     case 'oracle':
                         $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
                         $row = $db->sql_fetchrow($result);
                         $db->sql_freeresult($result);
                         $largest_id = (int) $row['max_id'];
                         if ($largest_id) {
                             $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
                             $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
                         }
                         break;
                 }
             }
         }
         // When we reach this point, either the current table has been processed or we're running out of time.
         if (still_on_time() && $counting < $convert->batch_size) {
             $skip_rows = 0;
             $current_table++;
         } else {
             /*
             				if (still_on_time() && $counting < $convert->batch_size)
             				{
             					$skip_rows = 0;
             					$current_table++;
             				}*/
             // Looks like we ran out of time.
             $url = $this->save_convert_progress($converter, 'current_table=' . $current_table . '&amp;skip_rows=' . $skip_rows);
             $current_table++;
             //				$percentage = ($skip_rows == 0) ? 0 : floor(100 / ($total_rows / $skip_rows));
             $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $current_table, sizeof($convert->convertor['schema']));
             $this->template->assign_vars(array('BODY' => $msg, 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'], 'U_ACTION' => $url));
             $this->meta_refresh($url);
             return;
         }
     }
     // Process execute_last then we'll be done
     $url = $this->save_convert_progress($converter, 'jump=1');
     $this->template->assign_vars(array('L_SUBMIT' => $user->lang['FINAL_STEP'], 'U_ACTION' => $url));
     $this->meta_refresh($url);
     return;
 }