/** * Open file for logging * * @param string $file File to open */ protected function file_open($file) { if ($this->filesystem->is_writable(dirname($file))) { $this->file_handle = fopen($file, 'w'); } else { throw new \RuntimeException('Unable to write to migrator log file'); } }
/** * {@inheritdoc} */ public function locate_resources() { if ($this->filesystem->exists($this->phpbb_root_path . 'install/update/new/config')) { $resources = array(array('install/update/new/config/' . $this->environment . '/routing/environment.yml', 'yaml')); } else { $resources = array(array('config/' . $this->environment . '/routing/environment.yml', 'yaml')); } return $resources; }
public function __construct(filesystem_interface $filesystem, $paths = []) { $paths = (array) $paths; $absolute_paths = []; foreach ($paths as $path) { $absolute_paths[] = $filesystem->realpath($path); } parent::__construct($absolute_paths); }
/** * Test Settings */ function test_upload(&$error, $upload_dir, $create_directory = false) { global $user, $phpbb_root_path; // Does the target directory exist, is it a directory and writable. if ($create_directory) { if (!file_exists($phpbb_root_path . $upload_dir)) { @mkdir($phpbb_root_path . $upload_dir, 0777); try { $this->filesystem->phpbb_chmod($phpbb_root_path . $upload_dir, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } } if (!file_exists($phpbb_root_path . $upload_dir)) { $error[] = sprintf($user->lang['NO_UPLOAD_DIR'], $upload_dir); return; } if (!is_dir($phpbb_root_path . $upload_dir)) { $error[] = sprintf($user->lang['UPLOAD_NOT_DIR'], $upload_dir); return; } if (!$this->filesystem->is_writable($phpbb_root_path . $upload_dir)) { $error[] = sprintf($user->lang['NO_WRITE_UPLOAD'], $upload_dir); return; } }
/** * Check if the avatar directory is writable and disable avatars * if it isn't writable. */ function disable_avatars_if_unwritable() { global $config, $phpbb_root_path; if (!$this->filesystem->is_writable($phpbb_root_path . 'images/avatars/upload/')) { $config->set('allow_avatar', 0); $config->set('allow_avatar_upload', 0); } }
/** * Find a list of controllers * * @param string $base_path Base path to prepend to file paths * @return router */ public function find($base_path = '') { if ($this->route_collection === null || $this->route_collection->count() === 0) { $this->route_collection = new RouteCollection(); foreach ($this->routing_files as $file_path) { $loader = new YamlFileLoader(new FileLocator($this->filesystem->realpath($base_path))); $this->route_collection->addCollection($loader->load($file_path)); } } return $this; }
/** * {@inheritdoc} */ public function run() { $this->db->sql_return_on_error(true); $server_name = $this->install_config->get('server_name'); $current_time = time(); $user_ip = phpbb_ip_normalise($this->iohandler->get_server_variable('REMOTE_ADDR')); $user_ip = $user_ip === false ? '' : $user_ip; $referer = $this->iohandler->get_server_variable('REFERER'); // Calculate cookie domain $cookie_domain = $server_name; if (strpos($cookie_domain, 'www.') === 0) { $cookie_domain = substr($cookie_domain, 3); } // Set default config and post data, this applies to all DB's $sql_ary = array('INSERT INTO ' . $this->config_table . " (config_name, config_value)\n\t\t\t\tVALUES ('board_startdate', '{$current_time}')", 'INSERT INTO ' . $this->config_table . " (config_name, config_value)\n\t\t\t\tVALUES ('default_lang', '" . $this->db->sql_escape($this->install_config->get('default_lang')) . "')", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('img_imagick')) . "'\n\t\t\t\tWHERE config_name = 'img_imagick'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('server_name')) . "'\n\t\t\t\tWHERE config_name = 'server_name'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('server_port')) . "'\n\t\t\t\tWHERE config_name = 'server_port'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('board_email')) . "'\n\t\t\t\tWHERE config_name = 'board_email'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('board_email')) . "'\n\t\t\t\tWHERE config_name = 'board_contact'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($cookie_domain) . "'\n\t\t\t\tWHERE config_name = 'cookie_domain'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->language->lang('default_dateformat')) . "'\n\t\t\t\tWHERE config_name = 'default_dateformat'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('email_enable')) . "'\n\t\t\t\tWHERE config_name = 'email_enable'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_delivery')) . "'\n\t\t\t\tWHERE config_name = 'smtp_delivery'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_host')) . "'\n\t\t\t\tWHERE config_name = 'smtp_host'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_port')) . "'\n\t\t\t\tWHERE config_name = 'smtp_port'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_auth')) . "'\n\t\t\t\tWHERE config_name = 'smtp_auth_method'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_user')) . "'\n\t\t\t\tWHERE config_name = 'smtp_username'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_pass')) . "'\n\t\t\t\tWHERE config_name = 'smtp_password'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('cookie_secure')) . "'\n\t\t\t\tWHERE config_name = 'cookie_secure'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('force_server_vars')) . "'\n\t\t\t\tWHERE config_name = 'force_server_vars'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('script_path')) . "'\n\t\t\t\tWHERE config_name = 'script_path'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('server_protocol')) . "'\n\t\t\t\tWHERE config_name = 'server_protocol'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "'\n\t\t\t\tWHERE config_name = 'newest_username'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . md5(mt_rand()) . "'\n\t\t\t\tWHERE config_name = 'avatar_salt'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . md5(mt_rand()) . "'\n\t\t\t\tWHERE config_name = 'plupload_salt'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('board_name')) . "'\n\t\t\t\tWHERE config_name = 'sitename'", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->install_config->get('board_description')) . "'\n\t\t\t\tWHERE config_name = 'site_desc'", 'UPDATE ' . $this->user_table . "\n\t\t\t\tSET username = '******'admin_name')) . "',\n\t\t\t\t\tuser_password='******'admin_passwd')) . "',\n\t\t\t\t\tuser_ip = '" . $this->db->sql_escape($user_ip) . "',\n\t\t\t\t\tuser_lang = '" . $this->db->sql_escape($this->install_config->get('user_language', 'en')) . "',\n\t\t\t\t\tuser_email='" . $this->db->sql_escape($this->install_config->get('board_email')) . "',\n\t\t\t\t\tuser_dateformat='" . $this->db->sql_escape($this->language->lang('default_dateformat')) . "',\n\t\t\t\t\tuser_email_hash = " . $this->db->sql_escape(phpbb_email_hash($this->install_config->get('board_email'))) . ",\n\t\t\t\t\tusername_clean = '" . $this->db->sql_escape(utf8_clean_string($this->install_config->get('admin_name'))) . "'\n\t\t\t\tWHERE username = '******'", 'UPDATE ' . $this->moderator_cache_table . "\n\t\t\t\tSET username = '******'admin_name')) . "'\n\t\t\t\tWHERE username = '******'", 'UPDATE ' . $this->forums_table . "\n\t\t\t\tSET forum_last_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "'\n\t\t\t\tWHERE forum_last_poster_name = 'Admin'", 'UPDATE ' . $this->topics_table . "\n\t\t\t\tSET topic_first_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "',\n\t\t\t\ttopic_last_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "'\n\t\t\t\tWHERE topic_first_poster_name = 'Admin'\n\t\t\t\t\tOR topic_last_poster_name = 'Admin'", 'UPDATE ' . $this->user_table . "\n\t\t\t\tSET user_regdate = {$current_time}", 'UPDATE ' . $this->posts_table . "\n\t\t\t\tSET post_time = {$current_time}, poster_ip = '" . $this->db->sql_escape($user_ip) . "'", 'UPDATE ' . $this->topics_table . "\n\t\t\t\tSET topic_time = {$current_time}, topic_last_post_time = {$current_time}", 'UPDATE ' . $this->forums_table . "\n\t\t\t\tSET forum_last_post_time = {$current_time}", 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '" . $this->db->sql_escape($this->db->sql_server_info(true)) . "'\n\t\t\t\tWHERE config_name = 'dbms_version'"); if (@extension_loaded('gd')) { $sql_ary[] = 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = 'core.captcha.plugins.gd'\n\t\t\t\tWHERE config_name = 'captcha_plugin'"; $sql_ary[] = 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '1'\n\t\t\t\tWHERE config_name = 'captcha_gd'"; } $ref = substr($referer, strpos($referer, '://') + 3); if (!(stripos($ref, $server_name) === 0)) { $sql_ary[] = 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '0'\n\t\t\t\tWHERE config_name = 'referer_validation'"; } // We set a (semi-)unique cookie name to bypass login issues related to the cookie name. $cookie_name = 'phpbb3_'; $rand_str = md5(mt_rand()); $rand_str = str_replace('0', 'z', base_convert($rand_str, 16, 35)); $rand_str = substr($rand_str, 0, 5); $cookie_name .= strtolower($rand_str); $sql_ary[] = 'UPDATE ' . $this->config_table . "\n\t\t\tSET config_value = '" . $this->db->sql_escape($cookie_name) . "'\n\t\t\tWHERE config_name = 'cookie_name'"; // Disable avatars if upload directory is not writable if (!$this->filesystem->is_writable($this->phpbb_root_path . 'images/avatars/upload/')) { $sql_ary[] = 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '0'\n\t\t\t\tWHERE config_name = 'allow_avatar'"; $sql_ary[] = 'UPDATE ' . $this->config_table . "\n\t\t\t\tSET config_value = '0'\n\t\t\t\tWHERE config_name = 'allow_avatar_upload'"; } $i = $this->install_config->get('add_config_settings_index', 0); $total = sizeof($sql_ary); $sql_ary = array_slice($sql_ary, $i); foreach ($sql_ary as $sql) { if (!$this->db->sql_query($sql)) { $error = $this->db->sql_error($this->db->get_sql_error_sql()); $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); } $i++; // Stop execution if resource limit is reached if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0) { break; } } if ($i < $total) { $this->install_config->set('add_config_settings_index', $i); throw new resource_limit_reached_exception(); } }
/** * {@inheritdoc} */ public function run() { $config_written = true; // Create config.php $path_to_config = $this->phpbb_root_path . 'config.' . $this->php_ext; $fp = @fopen($path_to_config, 'w'); if (!$fp) { $config_written = false; } $config_content = $this->get_config_data(); if (!@fwrite($fp, $config_content)) { $config_written = false; } @fclose($fp); // chmod config.php to be only readable if ($config_written) { try { $this->filesystem->phpbb_chmod($path_to_config, \phpbb\filesystem\filesystem_interface::CHMOD_READ); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing, the user will get a notice later } } else { $this->iohandler->add_error_message('UNABLE_TO_WRITE_CONFIG_FILE'); $this->iohandler->send_response(); throw new user_interaction_required_exception(); } // Create a lock file to indicate that there is an install in progress $fp = @fopen($this->phpbb_root_path . 'cache/install_lock', 'wb'); if ($fp === false) { // We were unable to create the lock file - abort $this->iohandler->add_error_message('UNABLE_TO_WRITE_LOCK'); $this->iohandler->send_response(); throw new user_interaction_required_exception(); } @fclose($fp); try { $this->filesystem->phpbb_chmod($this->phpbb_root_path . 'cache/install_lock', 0777); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing, the user will get a notice later } }
/** * Write cache data to a specified file * * 'data_global' is a special case and the generated format is different for this file: * <code> * <?php exit; ?> * (expiration) * (length of var and serialised data) * (var) * (serialised data) * ... (repeat) * </code> * * The other files have a similar format: * <code> * <?php exit; ?> * (expiration) * (query) [SQL files only] * (length of serialised data) * (serialised data) * </code> * * @access private * @param string $filename Filename to write * @param mixed $data Data to store * @param int $expires Timestamp when the data expires * @param string $query Query when caching SQL queries * @return bool True if the file was successfully created, otherwise false */ function _write($filename, $data = null, $expires = 0, $query = '') { global $phpEx; $filename = $this->clean_varname($filename); $file = "{$this->cache_dir}{$filename}.{$phpEx}"; $lock = new \phpbb\lock\flock($file); $lock->acquire(); if ($handle = @fopen($file, 'wb')) { // File header fwrite($handle, '<' . '?php exit; ?' . '>'); if ($filename == 'data_global') { // Global data is a different format foreach ($this->vars as $var => $data) { if (strpos($var, "\r") !== false || strpos($var, "\n") !== false) { // CR/LF would cause fgets() to read the cache file incorrectly // do not cache test entries, they probably won't be read back // the cache keys should really be alphanumeric with a few symbols. continue; } $data = serialize($data); // Write out the expiration time fwrite($handle, "\n" . $this->var_expires[$var] . "\n"); // Length of the remaining data for this var (ignoring two LF's) fwrite($handle, strlen($data . $var) . "\n"); fwrite($handle, $var . "\n"); fwrite($handle, $data); } } else { fwrite($handle, "\n" . $expires . "\n"); if (strpos($filename, 'sql_') === 0) { fwrite($handle, $query . "\n"); } $data = serialize($data); fwrite($handle, strlen($data) . "\n"); fwrite($handle, $data); } fclose($handle); if (function_exists('opcache_invalidate')) { @opcache_invalidate($this->cache_file); } try { $this->filesystem->phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } $return_value = true; } else { $return_value = false; } $lock->release(); return $return_value; }
/** * Eliminates useless . and .. components from specified URL * * @param string $url URL to clean * * @return string Cleaned URL */ public function clean_url($url) { $delimiter_position = strpos($url, '://'); // URL should contain :// but it shouldn't start with it. // Do not clean URLs that do not fit these constraints. if (empty($delimiter_position)) { return $url; } $scheme = substr($url, 0, $delimiter_position) . '://'; // Add length of URL delimiter to position $path = substr($url, $delimiter_position + 3); return $scheme . $this->filesystem->clean_path($path); }
/** * {@inheritdoc} */ public function run() { // Generate database schema if ($this->filesystem->exists($this->phpbb_root_path . 'install/schemas/schema.json')) { $db_table_schema = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema.json'); $this->config->set('change_table_prefix', true); } else { global $table_prefix; // As this task may take a large amount of time to complete refreshing the page might be necessary for some // server configurations with limited resources if (!$this->config->get('pre_schema_forced_refresh', false)) { if ($this->config->get_time_remaining() < 5) { $this->config->set('pre_schema_forced_refresh', true); throw new resource_limit_reached_exception(); } } $table_prefix = $this->config->get('table_prefix'); if (!defined('CONFIG_TABLE')) { // We need to include the constants file for the table constants // when we generate the schema from the migration files. include $this->phpbb_root_path . 'includes/constants.' . $this->php_ext; } $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, null, $this->php_ext); $migrator_classes = $finder->core_path('phpbb/db/migration/data/')->get_classes(); $factory = new \phpbb\db\tools\factory(); $db_tools = $factory->get($this->db, true); $schema_generator = new \phpbb\db\migration\schema_generator($migrator_classes, new \phpbb\config\config(array()), $this->db, $db_tools, $this->phpbb_root_path, $this->php_ext, $table_prefix); $db_table_schema = $schema_generator->get_schema(); $db_table_schema = json_encode($db_table_schema, JSON_PRETTY_PRINT); $this->config->set('change_table_prefix', false); } $fp = @fopen($this->phpbb_root_path . 'store/schema.json', 'wb'); if (!$fp) { throw new \Exception('INST_SCHEMA_FILE_NOT_WRITABLE'); } fwrite($fp, $db_table_schema); fclose($fp); }
/** * {@inheritdoc} */ public function check_requirements() { $dbms = $this->config->get('dbms'); $dbms_info = $this->database_helper->get_available_dbms($dbms); $schema_name = $dbms_info[$dbms]['SCHEMA']; if ($dbms === 'mysql') { if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) { $schema_name .= '_41'; } else { $schema_name .= '_40'; } } $this->schema_file_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql'; return $this->filesystem->exists($this->schema_file_path); }
/** * Recovers install configuration from file */ public function load_config() { if (!$this->filesystem->exists($this->install_config_file)) { return; } $file_content = @file_get_contents($this->install_config_file); $serialized_data = trim(substr($file_content, 8)); $this->installer_config = array(); $this->progress_data = array(); $this->navigation_data = array(); if (!empty($serialized_data)) { $unserialized_data = json_decode($serialized_data, true); $this->installer_config = is_array($unserialized_data['installer_config']) ? $unserialized_data['installer_config'] : array(); $this->progress_data = is_array($unserialized_data['progress_data']) ? $unserialized_data['progress_data'] : array(); $this->navigation_data = is_array($unserialized_data['navigation_data']) ? $unserialized_data['navigation_data'] : array(); } }
/** * Find the template * * Override for Twig_Loader_Filesystem::findTemplate to add support * for loading from safe directories. */ protected function findTemplate($name) { $name = (string) $name; // normalize name $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); // If this is in the cache we can skip the entire process below // as it should have already been validated if (isset($this->cache[$name])) { return $this->cache[$name]; } // First, find the template name. The override above of validateName // causes the validateName process to be skipped for this call $file = parent::findTemplate($name); try { // Try validating the name (which may throw an exception) parent::validateName($name); } catch (\Twig_Error_Loader $e) { if (strpos($e->getRawMessage(), 'Looks like you try to load a template outside configured directories') === 0) { // Ok, so outside of the configured template directories, we // can now check if we're within a "safe" directory // Find the real path of the directory the file is in $directory = $this->filesystem->realpath(dirname($file)); if ($directory === false) { // Some sort of error finding the actual path, must throw the exception throw $e; } foreach ($this->safe_directories as $safe_directory) { if (strpos($directory, $safe_directory) === 0) { // The directory being loaded is below a directory // that is "safe". We're good to load it! return $file; } } } // Not within any safe directories throw $e; } // No exception from validateName, safe to load. return $file; }
/** * Check if a directory is readable and writable * * @param string $dir Filename * @param bool $failable Whether failing test should abort the installation process */ protected function check_dir($dir, $failable = false) { $path = $this->phpbb_root_path . $dir; $exists = $writable = false; // Try to create the directory if it does not exist if (!file_exists($path)) { try { $this->filesystem->mkdir($path, 0777); $this->filesystem->phpbb_chmod($path, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); $exists = true; } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } // Now really check if (file_exists($path) && is_dir($path)) { try { $exists = true; $this->filesystem->phpbb_chmod($path, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } if ($this->filesystem->is_writable($path)) { $writable = true; } $this->set_test_passed($exists && $writable || $failable); if (!($exists && $writable)) { $title = $exists ? 'DIRECTORY_NOT_WRITABLE' : 'DIRECTORY_NOT_EXISTS'; $lang_suffix = '_EXPLAIN'; $lang_suffix .= $failable ? '_OPTIONAL' : ''; $description = array($title . $lang_suffix, $dir); if ($failable) { $this->response->add_warning_message($title, $description); } else { $this->response->add_error_message($title, $description); } } }
/** * @dataProvider is_absolute_data */ public function test_is_absolute($path, $expected) { $this->assertEquals($expected, $this->filesystem->is_absolute_path($path)); }
/** * The function which does the actual work (or dispatches it to the relevant places) */ function convert_data($sub) { global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache, $auth; global $convert, $convert_row, $message_parser, $skip_rows, $language; global $request, $phpbb_config_php_file, $phpbb_dispatcher; extract($phpbb_config_php_file->get_all()); require $phpbb_root_path . 'includes/constants.' . $phpEx; require $phpbb_root_path . 'includes/functions_convert.' . $phpEx; $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms); $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); // This is a little bit of a fudge, but it allows the language entries to be available to the // core code without us loading them again $user->lang =& $lang; $this->page_title = $user->lang['STAGE_IN_PROGRESS']; $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->p_master->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__); } // 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; $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->p_master->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__); } if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx)) { include './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->p_master->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 $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($sync_batch); return; } if ($jump) { $this->jump($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->p_master->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->p_master->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true); $template->assign_vars(array('L_SUBMIT' => $user->lang['INSTALL_TEST'], 'U_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&sub=in_progress&tag={$convert->convertor_tag}&language={$language}")); 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 $val) { if (preg_match('/([a-z0-9_]+)\\.([a-z0-9_]+)\\)* ?A?S? ?([a-z0-9_]*?)\\.?([a-z0-9_]*)$/i', $val, $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->p_master->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__); } else { if (sizeof($missing_tables)) { $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__); } } $url = $this->save_convert_progress('&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']); } $template->assign_vars(array('L_SUBMIT' => $user->lang['CONTINUE_CONVERT'], 'L_MESSAGE' => $msg, 'U_ACTION' => $url)); return; } // if (!$request->variable('confirm', false))) $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; } $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]); } } } $template->assign_block_vars('checks', array('TITLE' => $user->lang['PREPROCESS_STEP'], 'RESULT' => $user->lang['DONE'])); } // if (!$current_table && !$skip_rows) $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; } $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) | "; } $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->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); } } $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->p_master->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->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); } $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('&current_table=' . $current_table . '&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'])); $template->assign_vars(array('L_MESSAGE' => $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('&jump=1'); $template->assign_vars(array('L_SUBMIT' => $user->lang['FINAL_STEP'], 'U_ACTION' => $url)); $this->meta_refresh($url); return; }
/** * Check if the user provided database parameters are correct * * This function checks the database connection data and also checks for * any other problems that could cause an error during the installation * such as if there is any database table names conflicting. * * Note: The function assumes that $table_prefix has been already validated * with validate_table_prefix(). * * @param string $dbms Selected database type * @param string $dbhost Database host address * @param int $dbport Database port number * @param string $dbuser Database username * @param string $dbpass Database password * @param string $dbname Database name * @param string $table_prefix Database table prefix * * @return array|bool Returns true if test is successful, array of errors otherwise */ public function check_database_connection($dbms, $dbhost, $dbport, $dbuser, $dbpass, $dbname, $table_prefix) { $dbms_info = $this->get_available_dbms($dbms); $dbms_info = $dbms_info[$dbms]; $errors = array(); // Instantiate it and set return on error true /** @var \phpbb\db\driver\driver_interface $db */ $db = new $dbms_info['DRIVER'](); $db->sql_return_on_error(true); // Check that we actually have a database name before going any further if (!in_array($dbms_info['SCHEMA'], array('sqlite', 'oracle'), true) && $dbname === '') { $errors[] = array('title' => 'INST_ERR_DB_NO_NAME'); } // Make sure we don't have a daft user who thinks having the SQLite database in the forum directory is a good idea if ($dbms_info['SCHEMA'] === 'sqlite' && stripos($this->filesystem->realpath($dbhost), $this->filesystem->realpath($this->phpbb_root_path) === 0)) { $errors[] = array('title' => 'INST_ERR_DB_FORUM_PATH'); } // Try to connect to db if (is_array($db->sql_connect($dbhost, $dbuser, $dbpass, $dbname, $dbport, false, true))) { $db_error = $db->sql_error(); $errors[] = array('title' => 'INST_ERR_DB_CONNECT', 'description' => $db_error['message'] ? utf8_convert_message($db_error['message']) : 'INST_ERR_DB_NO_ERROR'); } else { // Check if there is any table name collisions $temp_prefix = strtolower($table_prefix); $table_ary = array($temp_prefix . 'attachments', $temp_prefix . 'config', $temp_prefix . 'sessions', $temp_prefix . 'topics', $temp_prefix . 'users'); $db_tools_factory = new \phpbb\db\tools\factory(); $db_tools = $db_tools_factory->get($db); $tables = $db_tools->sql_list_tables(); $tables = array_map('strtolower', $tables); $table_intersect = array_intersect($tables, $table_ary); if (sizeof($table_intersect)) { $errors[] = array('title' => 'INST_ERR_PREFIX'); } // Check if database version is supported switch ($dbms) { case 'mysqli': if (version_compare($db->sql_server_info(true), '4.1.3', '<')) { $errors[] = array('title' => 'INST_ERR_DB_NO_MYSQLI'); } break; case 'sqlite': if (version_compare($db->sql_server_info(true), '2.8.2', '<')) { $errors[] = array('title' => 'INST_ERR_DB_NO_SQLITE'); } break; case 'sqlite3': if (version_compare($db->sql_server_info(true), '3.6.15', '<')) { $errors[] = array('title' => 'INST_ERR_DB_NO_SQLITE3'); } break; case 'oracle': $sql = "SELECT *\n\t\t\t\t\t\tFROM NLS_DATABASE_PARAMETERS\n\t\t\t\t\t\tWHERE PARAMETER = 'NLS_RDBMS_VERSION'\n\t\t\t\t\t\t\tOR PARAMETER = 'NLS_CHARACTERSET'"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $stats[$row['parameter']] = $row['value']; } $db->sql_freeresult($result); if (version_compare($stats['NLS_RDBMS_VERSION'], '9.2', '<') && $stats['NLS_CHARACTERSET'] !== 'UTF8') { $errors[] = array('title' => 'INST_ERR_DB_NO_ORACLE'); } break; case 'postgres': $sql = "SHOW server_encoding;"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); if ($row['server_encoding'] !== 'UNICODE' && $row['server_encoding'] !== 'UTF8') { $errors[] = array('title' => 'INST_ERR_DB_NO_POSTGRES'); } break; } } return empty($errors) ? true : $errors; }
/** * Move file to destination folder * The phpbb_root_path variable will be applied to the destination path * * @param string $destination Destination path, for example $config['avatar_path'] * @param bool $overwrite If set to true, an already existing file will be overwritten * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped * @param string $chmod Permission mask for chmodding the file after a successful move. The mode entered here reflects the mode defined by {@link phpbb_chmod()} * * @access public */ function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false) { global $user, $phpbb_root_path; if (sizeof($this->error)) { return false; } $chmod = $chmod === false ? CHMOD_READ | CHMOD_WRITE : $chmod; // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it... $this->destination_path = $phpbb_root_path . $destination; // Check if the destination path exist... if (!file_exists($this->destination_path)) { @unlink($this->filename); return false; } $upload_mode = @ini_get('open_basedir') || @ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'on' ? 'move' : 'copy'; $upload_mode = $this->local ? 'local' : $upload_mode; $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname); // Check if the file already exist, else there is something wrong... if (file_exists($this->destination_file) && !$overwrite) { @unlink($this->filename); $this->error[] = $user->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file); $this->file_moved = false; return false; } else { if (file_exists($this->destination_file)) { @unlink($this->destination_file); } switch ($upload_mode) { case 'copy': if (!@copy($this->filename, $this->destination_file)) { if (!@move_uploaded_file($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); } } break; case 'move': if (!@move_uploaded_file($this->filename, $this->destination_file)) { if (!@copy($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); } } break; case 'local': if (!@copy($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); } break; } // Remove temporary filename @unlink($this->filename); if (sizeof($this->error)) { return false; } try { $this->filesystem->phpbb_chmod($this->destination_file, $chmod); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } // Try to get real filesize from destination folder $this->filesize = @filesize($this->destination_file) ? @filesize($this->destination_file) : $this->filesize; // Get mimetype of supplied file $this->mimetype = $this->get_mimetype($this->destination_file); if ($this->is_image() && !$skip_image_check) { $this->width = $this->height = 0; // Get imagesize class $imagesize = new \fastImageSize\fastImageSize(); $this->image_info = $imagesize->getImageSize($this->destination_file, $this->mimetype); if ($this->image_info !== false) { $this->width = $this->image_info['width']; $this->height = $this->image_info['height']; // Check image type $types = fileupload::image_types(); if (!isset($types[$this->image_info['type']]) || !in_array($this->extension, $types[$this->image_info['type']])) { if (!isset($types[$this->image_info['type']])) { $this->error[] = $user->lang('IMAGE_FILETYPE_INVALID', $this->image_info['type'], $this->mimetype); } else { $this->error[] = $user->lang('IMAGE_FILETYPE_MISMATCH', $types[$this->image_info['type']][0], $this->extension); } } // Make sure the dimensions match a valid image if (empty($this->width) || empty($this->height)) { $this->error[] = $user->lang['ATTACHED_IMAGE_NOT_IMAGE']; } } else { $this->error[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; } } $this->file_moved = true; $this->additional_checks(); unset($this->upload); return true; }
/** * Save queue */ function save() { if (!sizeof($this->data)) { return; } $lock = new \phpbb\lock\flock($this->cache_file); $lock->acquire(); if (file_exists($this->cache_file)) { include $this->cache_file; foreach ($this->queue_data as $object => $data_ary) { if (isset($this->data[$object]) && sizeof($this->data[$object])) { $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']); } else { $this->data[$object]['data'] = $data_ary['data']; } } } if ($fp = @fopen($this->cache_file, 'w')) { fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>"); fclose($fp); try { $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } $this->data = array(); } $lock->release(); }
/** * {@inheritdoc} */ public function run() { $this->db->sql_return_on_error(true); $dbms = $this->config->get('dbms'); $dbms_info = $this->database_helper->get_available_dbms($dbms); $schema_name = $dbms_info[$dbms]['SCHEMA']; $delimiter = $dbms_info[$dbms]['DELIM']; $table_prefix = $this->config->get('table_prefix'); if ($dbms === 'mysql') { if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) { $schema_name .= '_41'; } else { $schema_name .= '_40'; } } $db_schema_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql'; // Load database vendor specific code if there is any if ($this->filesystem->exists($db_schema_path)) { $sql_query = @file_get_contents($db_schema_path); $sql_query = preg_replace('#phpbb_#i', $table_prefix, $sql_query); $sql_query = $this->database_helper->remove_comments($sql_query); $sql_query = $this->database_helper->split_sql_file($sql_query, $delimiter); foreach ($sql_query as $sql) { if (!$this->db->sql_query($sql)) { $error = $this->db->sql_error($this->db->get_sql_error_sql()); $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); } } unset($sql_query); } $change_prefix = false; // Generate database schema if ($this->filesystem->exists($this->phpbb_root_path . 'install/schemas/schema.json')) { $db_table_schema = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema.json'); $db_table_schema = json_decode($db_table_schema, true); $change_prefix = true; } else { global $table_prefix; $table_prefix = $this->config->get('table_prefix'); if (!defined('CONFIG_TABLE')) { // We need to include the constants file for the table constants // when we generate the schema from the migration files. include $this->phpbb_root_path . 'includes/constants.' . $this->php_ext; } $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, null, $this->php_ext); $migrator_classes = $finder->core_path('phpbb/db/migration/data/')->get_classes(); $factory = new \phpbb\db\tools\factory(); $db_tools = $factory->get($this->db, true); $schema_generator = new \phpbb\db\migration\schema_generator($migrator_classes, new \phpbb\config\config(array()), $this->db, $db_tools, $this->phpbb_root_path, $this->php_ext, $table_prefix); $db_table_schema = $schema_generator->get_schema(); } if (!defined('CONFIG_TABLE')) { // CONFIG_TABLE is required by sql_create_index() to check the // length of index names. However table_prefix is not defined // here yet, so we need to create the constant ourselves. define('CONFIG_TABLE', $table_prefix . 'config'); } foreach ($db_table_schema as $table_name => $table_data) { $this->db_tools->sql_create_table($change_prefix ? $table_prefix . substr($table_name, 6) : $table_name, $table_data); } }
/** * Extract archive */ function extract($dst) { $fzread = $this->isbz && function_exists('bzread') ? 'bzread' : ($this->isgz && @extension_loaded('zlib') ? 'gzread' : 'fread'); // Run through the file and grab directory entries while ($buffer = $fzread($this->fp, 512)) { $tmp = unpack('A6magic', substr($buffer, 257, 6)); if (trim($tmp['magic']) == 'ustar') { $tmp = unpack('A100name', $buffer); $filename = trim($tmp['name']); $tmp = unpack('Atype', substr($buffer, 156, 1)); $filetype = (int) trim($tmp['type']); $tmp = unpack('A12size', substr($buffer, 124, 12)); $filesize = octdec((int) trim($tmp['size'])); $target_filename = "{$dst}{$filename}"; if ($filetype == 5) { if (!is_dir($target_filename)) { $str = ''; $folders = explode('/', $target_filename); // Create and folders and subfolders if they do not exist foreach ($folders as $folder) { $folder = trim($folder); if (!$folder) { continue; } $str = !empty($str) ? $str . '/' . $folder : $folder; if (!is_dir($str)) { if (!@mkdir($str, 0777)) { trigger_error("Could not create directory {$folder}"); } try { $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } } } } else { if ($filesize >= 0 && ($filetype == 0 || $filetype == "")) { // Some archivers are punks, they don't properly order the folders in their archives! $str = ''; $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME)); // Create and folders and subfolders if they do not exist foreach ($folders as $folder) { $folder = trim($folder); if (!$folder) { continue; } $str = !empty($str) ? $str . '/' . $folder : $folder; if (!is_dir($str)) { if (!@mkdir($str, 0777)) { trigger_error("Could not create directory {$folder}"); } try { $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } } // Write out the files if (!($fp = fopen($target_filename, 'wb'))) { trigger_error("Couldn't create file {$filename}"); } try { $this->filesystem->phpbb_chmod($target_filename, CHMOD_READ); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } // Grab the file contents fwrite($fp, $filesize ? $fzread($this->fp, $filesize + 511 & ~511) : '', $filesize); fclose($fp); } } } } }
/** * Check if user is able to upload an avatar * * @return bool True if user can upload, false if not */ protected function can_upload() { return file_exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'); }