diff options
Diffstat (limited to 'phpBB/phpbb')
111 files changed, 2668 insertions, 445 deletions
diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php index 38755ccf99..b59f0e60ec 100644 --- a/phpBB/phpbb/auth/auth.php +++ b/phpBB/phpbb/auth/auth.php @@ -927,11 +927,11 @@ class auth */ function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0) { - global $config, $db, $user, $phpbb_root_path, $phpEx, $phpbb_container; + global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container; - $method = trim(basename($config['auth_method'])); + $provider_collection = $phpbb_container->get('auth.provider_collection'); - $provider = $phpbb_container->get('auth.provider.' . $method); + $provider = $provider_collection->get_provider(); if ($provider) { $login = $provider->login($username, $password); diff --git a/phpBB/phpbb/auth/provider/apache.php b/phpBB/phpbb/auth/provider/apache.php index 9137a77210..aa5bf64335 100644 --- a/phpBB/phpbb/auth/provider/apache.php +++ b/phpBB/phpbb/auth/provider/apache.php @@ -137,7 +137,7 @@ class apache extends \phpbb\auth\provider\base return array( 'status' => LOGIN_SUCCESS_CREATE_PROFILE, 'error_msg' => false, - 'user_row' => user_row_apache($php_auth_user, $php_auth_pw), + 'user_row' => $this->user_row($php_auth_user, $php_auth_pw), ); } @@ -185,7 +185,7 @@ class apache extends \phpbb\auth\provider\base } // create the user if he does not exist yet - user_add(user_row_apache($php_auth_user, $php_auth_pw)); + user_add($this->user_row($php_auth_user, $php_auth_pw)); $sql = 'SELECT * FROM ' . USERS_TABLE . " diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index 722eeffa9a..d8c5fb72de 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -87,7 +87,7 @@ class db extends \phpbb\auth\provider\base $username_clean = utf8_clean_string($username); - $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts + $sql = 'SELECT * FROM ' . USERS_TABLE . " WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'"; $result = $this->db->sql_query($sql); @@ -123,7 +123,7 @@ class db extends \phpbb\auth\provider\base 'username_clean' => $username_clean, ); $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data); - $result = $this->db->sql_query($sql); + $this->db->sql_query($sql); } else { @@ -175,7 +175,7 @@ class db extends \phpbb\auth\provider\base } // Check password ... - if ($this->passwords_manager->check($password, $row['user_password'])) + if ($this->passwords_manager->check($password, $row['user_password'], $row)) { // Check for old password hash... if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32) @@ -232,7 +232,7 @@ class db extends \phpbb\auth\provider\base // Give status about wrong password... return array( 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, - 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD', + 'error_msg' => 'LOGIN_ERROR_PASSWORD', 'user_row' => $row, ); } diff --git a/phpBB/phpbb/auth/provider/ldap.php b/phpBB/phpbb/auth/provider/ldap.php index d32e7504eb..c71950c698 100644 --- a/phpBB/phpbb/auth/provider/ldap.php +++ b/phpBB/phpbb/auth/provider/ldap.php @@ -306,7 +306,7 @@ class ldap extends \phpbb\auth\provider\base return array( 'TEMPLATE_FILE' => 'auth_provider_ldap.html', 'TEMPLATE_VARS' => array( - 'AUTH_LDAP_DN' => $new_config['ldap_base_dn'], + 'AUTH_LDAP_BASE_DN' => $new_config['ldap_base_dn'], 'AUTH_LDAP_EMAIL' => $new_config['ldap_email'], 'AUTH_LDAP_PASSORD' => $new_config['ldap_password'], 'AUTH_LDAP_PORT' => $new_config['ldap_port'], diff --git a/phpBB/phpbb/auth/provider_collection.php b/phpBB/phpbb/auth/provider_collection.php index a74a2135dc..8e7e9e2cc1 100644 --- a/phpBB/phpbb/auth/provider_collection.php +++ b/phpBB/phpbb/auth/provider_collection.php @@ -38,6 +38,7 @@ class provider_collection extends \phpbb\di\service_collection /** * Get an auth provider. * + * @param string $provider_name The name of the auth provider * @return object Default auth provider selected in config if it * does exist. Otherwise the standard db auth * provider. @@ -46,11 +47,12 @@ class provider_collection extends \phpbb\di\service_collection * auth provider exist. The db auth provider * should always exist in a phpBB installation. */ - public function get_provider() + public function get_provider($provider_name = '') { - if ($this->offsetExists('auth.provider.' . basename(trim($this->config['auth_method'])))) + $provider_name = ($provider_name !== '') ? $provider_name : basename(trim($this->config['auth_method'])); + if ($this->offsetExists('auth.provider.' . $provider_name)) { - return $this->offsetGet('auth.provider.' . basename(trim($this->config['auth_method']))); + return $this->offsetGet('auth.provider.' . $provider_name); } // Revert to db auth provider if selected method does not exist else if ($this->offsetExists('auth.provider.db')) diff --git a/phpBB/phpbb/avatar/driver/local.php b/phpBB/phpbb/avatar/driver/local.php index 07b3ed59de..8888686b2d 100644 --- a/phpBB/phpbb/avatar/driver/local.php +++ b/phpBB/phpbb/avatar/driver/local.php @@ -154,7 +154,7 @@ class local extends \phpbb\avatar\driver\driver */ protected function get_avatar_list($user) { - $avatar_list = ($this->cache == null) ? false : $this->cache->get('avatar_local_list'); + $avatar_list = ($this->cache == null) ? false : $this->cache->get('_avatar_local_list'); if ($avatar_list === false) { @@ -192,7 +192,7 @@ class local extends \phpbb\avatar\driver\driver if ($this->cache != null) { - $this->cache->put('avatar_local_list', $avatar_list, 86400); + $this->cache->put('_avatar_local_list', $avatar_list, 86400); } } diff --git a/phpBB/phpbb/avatar/driver/remote.php b/phpBB/phpbb/avatar/driver/remote.php index 1bd7f6c927..4b0ee3f06f 100644 --- a/phpBB/phpbb/avatar/driver/remote.php +++ b/phpBB/phpbb/avatar/driver/remote.php @@ -130,8 +130,24 @@ class remote extends \phpbb\avatar\driver\driver { // Timeout after 1 second stream_set_timeout($file_stream, 1); + // read some data to ensure headers are present + fread($file_stream, 1024); $meta = stream_get_meta_data($file_stream); - foreach ($meta['wrapper_data'] as $header) + + if (isset($meta['wrapper_data']['headers']) && is_array($meta['wrapper_data']['headers'])) + { + $headers = $meta['wrapper_data']['headers']; + } + else if (isset($meta['wrapper_data']) && is_array($meta['wrapper_data'])) + { + $headers = $meta['wrapper_data']; + } + else + { + $headers = array(); + } + + foreach ($headers as $header) { $header = preg_split('/ /', $header, 2); if (strtr(strtolower(trim($header[0], ':')), '_', '-') === 'content-type') diff --git a/phpBB/phpbb/avatar/manager.php b/phpBB/phpbb/avatar/manager.php index 42ae61a9a2..8d83152ed6 100644 --- a/phpBB/phpbb/avatar/manager.php +++ b/phpBB/phpbb/avatar/manager.php @@ -326,17 +326,41 @@ class manager $driver->delete($avatar_data); } - $result = self::$default_row; + $result = $this->prefix_avatar_columns($prefix, self::$default_row); - foreach ($result as $key => $value) + $sql = 'UPDATE ' . $table . ' + SET ' . $db->sql_build_array('UPDATE', $result) . ' + WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id']; + $db->sql_query($sql); + + // Make sure we also delete this avatar from the users + if ($prefix === 'group_') { - $result[$prefix . $key] = $value; - unset($result[$key]); + $result = $this->prefix_avatar_columns('user_', self::$default_row); + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $result) . " + WHERE user_avatar = '" . $db->sql_escape($avatar_data['avatar']) . "'"; + $db->sql_query($sql); } + } - $sql = 'UPDATE ' . $table . ' - SET ' . $db->sql_build_array('UPDATE', $result) . ' - WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id']; - $db->sql_query($sql); + /** + * Prefix avatar columns + * + * @param string $prefix Column prefix + * @param array $data Column data + * + * @return array Column data with prefixed column names + */ + public function prefix_avatar_columns($prefix, $data) + { + foreach ($data as $key => $value) + { + $data[$prefix . $key] = $value; + unset($data[$key]); + } + + return $data; } } diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php index fd5bce4515..9a7c4aec7f 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -279,6 +279,7 @@ class file extends \phpbb\cache\driver\base if ($var_name[0] == '_') { global $phpEx; + $var_name = $this->clean_varname($var_name); return file_exists($this->cache_dir . 'data' . $var_name . ".$phpEx"); } else @@ -334,6 +335,7 @@ class file extends \phpbb\cache\driver\base { global $phpEx; + $filename = $this->clean_varname($filename); $file = "{$this->cache_dir}$filename.$phpEx"; $type = substr($filename, 0, strpos($filename, '_')); @@ -516,6 +518,7 @@ class file extends \phpbb\cache\driver\base { global $phpEx; + $filename = $this->clean_varname($filename); $file = "{$this->cache_dir}$filename.$phpEx"; $lock = new \phpbb\lock\flock($file); @@ -584,4 +587,15 @@ class file extends \phpbb\cache\driver\base return $return_value; } + + /** + * Replace slashes in the file name + * + * @param string $varname name of a cache variable + * @return string $varname name that is safe to use as a filename + */ + protected function clean_varname($varname) + { + return str_replace('/', '-', $varname); + } } diff --git a/phpBB/phpbb/cache/driver/memory.php b/phpBB/phpbb/cache/driver/memory.php index 56308be8da..0b0e323e3d 100644 --- a/phpBB/phpbb/cache/driver/memory.php +++ b/phpBB/phpbb/cache/driver/memory.php @@ -208,12 +208,24 @@ abstract class memory extends \phpbb\cache\driver\base // determine which tables this query belongs to // Some queries use backticks, namely the get_database_size() query // don't check for conformity, the SQL would error and not reach here. - if (!preg_match('/FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?/', $query, $regs)) + if (!preg_match_all('/(?:FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?)|(?:JOIN (`?\\w+`?(?: \\w+)?))/', $query, $regs, PREG_SET_ORDER)) { // Bail out if the match fails. return $query_result; } - $tables = array_map('trim', explode(',', $regs[1])); + + $tables = array(); + foreach ($regs as $match) + { + if ($match[0][0] == 'F') + { + $tables = array_merge($tables, array_map('trim', explode(',', $match[1]))); + } + else + { + $tables[] = $match[2]; + } + } foreach ($tables as $table_name) { diff --git a/phpBB/phpbb/captcha/plugins/recaptcha.php b/phpBB/phpbb/captcha/plugins/recaptcha.php index ea446d7bc3..584f3afec1 100644 --- a/phpBB/phpbb/captcha/plugins/recaptcha.php +++ b/phpBB/phpbb/captcha/plugins/recaptcha.php @@ -26,8 +26,10 @@ class recaptcha extends captcha_abstract var $challenge; var $response; - // PHP4 Constructor - function phpbb_recaptcha() + /** + * Constructor + */ + public function __construct() { global $request; $this->recaptcha_server = $request->is_secure() ? $this->recaptcha_server_secure : $this->recaptcha_server; diff --git a/phpBB/phpbb/config/db.php b/phpBB/phpbb/config/db.php index ef20ebf62a..26489bdd34 100644 --- a/phpBB/phpbb/config/db.php +++ b/phpBB/phpbb/config/db.php @@ -145,9 +145,9 @@ class db extends \phpbb\config\config $sql .= " AND config_value = '" . $this->db->sql_escape($old_value) . "'"; } - $result = $this->db->sql_query($sql); + $this->db->sql_query($sql); - if (!$this->db->sql_affectedrows($result) && isset($this->config[$key])) + if (!$this->db->sql_affectedrows() && isset($this->config[$key])) { return false; } diff --git a/phpBB/phpbb/config/db_text.php b/phpBB/phpbb/config/db_text.php index b1e3ef5da4..ddc7c9aef0 100644 --- a/phpBB/phpbb/config/db_text.php +++ b/phpBB/phpbb/config/db_text.php @@ -154,6 +154,6 @@ class db_text $sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true); - $result = $this->db->sql_query($sql); + $this->db->sql_query($sql); } } diff --git a/phpBB/phpbb/console/command/cache/purge.php b/phpBB/phpbb/console/command/cache/purge.php index ec8229200c..d0c2ef6f72 100644 --- a/phpBB/phpbb/console/command/cache/purge.php +++ b/phpBB/phpbb/console/command/cache/purge.php @@ -26,7 +26,7 @@ class purge extends \phpbb\console\command\command /** @var \phpbb\auth\auth */ protected $auth; - /** @var \phpbb\log\log */ + /** @var \phpbb\log\log_interface */ protected $log; /** @var \phpbb\config\config */ @@ -42,7 +42,7 @@ class purge extends \phpbb\console\command\command * @param \phpbb\log\log $log Logger instance * @param \phpbb\config\config $config Config instance */ - public function __construct(\phpbb\user $user, \phpbb\cache\driver\driver_interface $cache, \phpbb\db\driver\driver_interface $db, \phpbb\auth\auth $auth, \phpbb\log\log $log, \phpbb\config\config $config) + public function __construct(\phpbb\user $user, \phpbb\cache\driver\driver_interface $cache, \phpbb\db\driver\driver_interface $db, \phpbb\auth\auth $auth, \phpbb\log\log_interface $log, \phpbb\config\config $config) { $this->cache = $cache; $this->db = $db; diff --git a/phpBB/phpbb/console/command/db/console_migrator_output_handler.php b/phpBB/phpbb/console/command/db/console_migrator_output_handler.php new file mode 100644 index 0000000000..b9741a3838 --- /dev/null +++ b/phpBB/phpbb/console/command/db/console_migrator_output_handler.php @@ -0,0 +1,69 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\console\command\db; + +use phpbb\user; +use phpbb\db\migrator_output_handler_interface; +use Symfony\Component\Console\Output\OutputInterface; + +class console_migrator_output_handler implements migrator_output_handler_interface +{ + /** + * User object. + * + * @var user + */ + private $user; + + /** + * Console output object. + * + * @var OutputInterface + */ + private $output; + + /** + * Constructor + * + * @param user $user User object + * @param OutputInterface $output Console output object + */ + public function __construct(user $user, OutputInterface $output) + { + $this->user = $user; + $this->output = $output; + } + + /** + * {@inheritdoc} + */ + public function write($message, $verbosity) + { + if ($verbosity <= $this->output->getVerbosity()) + { + $translated_message = call_user_func_array(array($this->user, 'lang'), $message); + + if ($verbosity === migrator_output_handler_interface::VERBOSITY_NORMAL) + { + $translated_message = '<info>' . $translated_message . '</info>'; + } + else if ($verbosity === migrator_output_handler_interface::VERBOSITY_VERBOSE) + { + $translated_message = '<comment>' . $translated_message . '</comment>'; + } + + $this->output->writeln($translated_message); + } + } +} diff --git a/phpBB/phpbb/console/command/db/migrate.php b/phpBB/phpbb/console/command/db/migrate.php index 86545c237d..87c2a057d1 100644 --- a/phpBB/phpbb/console/command/db/migrate.php +++ b/phpBB/phpbb/console/command/db/migrate.php @@ -32,13 +32,17 @@ class migrate extends \phpbb\console\command\command /** @var \phpbb\log\log */ protected $log; - function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\log\log $log) + /** @var string phpBB root path */ + protected $phpbb_root_path; + + function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\log\log $log, $phpbb_root_path) { $this->migrator = $migrator; $this->extension_manager = $extension_manager; $this->config = $config; $this->cache = $cache; $this->log = $log; + $this->phpbb_root_path = $phpbb_root_path; parent::__construct($user); $this->user->add_lang(array('common', 'install', 'migrator')); } @@ -53,14 +57,16 @@ class migrate extends \phpbb\console\command\command protected function execute(InputInterface $input, OutputInterface $output) { + $this->migrator->set_output_handler(new \phpbb\db\log_wrapper_migrator_output_handler($this->user, new console_migrator_output_handler($this->user, $output), $this->phpbb_root_path . 'store/migrations_' . time() . '.log')); + $this->migrator->create_migrations_table(); + $this->cache->purge(); + $this->load_migrations(); $orig_version = $this->config['version']; while (!$this->migrator->finished()) { - $migration_start_time = microtime(true); - try { $this->migrator->update(); @@ -71,36 +77,6 @@ class migrate extends \phpbb\console\command\command $this->finalise_update(); return 1; } - - $migration_stop_time = microtime(true) - $migration_start_time; - - $state = array_merge( - array( - 'migration_schema_done' => false, - 'migration_data_done' => false, - ), - $this->migrator->last_run_migration['state'] - ); - - if (!empty($this->migrator->last_run_migration['effectively_installed'])) - { - $msg = $this->user->lang('MIGRATION_EFFECTIVELY_INSTALLED', $this->migrator->last_run_migration['name']); - $output->writeln("<comment>$msg</comment>"); - } - else if ($this->migrator->last_run_migration['task'] == 'process_data_step' && $state['migration_data_done']) - { - $msg = $this->user->lang('MIGRATION_DATA_DONE', $this->migrator->last_run_migration['name'], $migration_stop_time); - $output->writeln("<info>$msg</info>"); - } - else if ($this->migrator->last_run_migration['task'] == 'process_data_step') - { - $output->writeln($this->user->lang('MIGRATION_DATA_IN_PROGRESS', $this->migrator->last_run_migration['name'], $migration_stop_time)); - } - else if ($state['migration_schema_done']) - { - $msg = $this->user->lang('MIGRATION_SCHEMA_DONE', $this->migrator->last_run_migration['name'], $migration_stop_time); - $output->writeln("<info>$msg</info>"); - } } if ($orig_version != $this->config['version']) diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php index 8bd537586e..700009da6a 100644 --- a/phpBB/phpbb/content_visibility.php +++ b/phpBB/phpbb/content_visibility.php @@ -44,6 +44,12 @@ class content_visibility protected $config; /** + * Event dispatcher object + * @var \phpbb\event\dispatcher_interface + */ + protected $phpbb_dispatcher; + + /** * phpBB root path * @var string */ @@ -60,6 +66,7 @@ class content_visibility * * @param \phpbb\auth\auth $auth Auth object * @param \phpbb\config\config $config Config object + * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object * @param \phpbb\db\driver\driver_interface $db Database object * @param \phpbb\user $user User object * @param string $phpbb_root_path Root path @@ -69,10 +76,11 @@ class content_visibility * @param string $topics_table Topics table name * @param string $users_table Users table name */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table) + public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table) { $this->auth = $auth; $this->config = $config; + $this->phpbb_dispatcher = $phpbb_dispatcher; $this->db = $db; $this->user = $user; $this->phpbb_root_path = $phpbb_root_path; @@ -135,12 +143,43 @@ class content_visibility */ public function get_visibility_sql($mode, $forum_id, $table_alias = '') { + $where_sql = ''; + + $get_visibility_sql_overwrite = false; + + /** + * Allow changing the result of calling get_visibility_sql + * + * @event core.phpbb_content_visibility_get_visibility_sql_before + * @var string where_sql Extra visibility conditions. It must end with either an SQL "AND" or an "OR" + * @var string mode Either "topic" or "post" depending on the query this is being used in + * @var array forum_id The forum id in which the search is made. + * @var string table_alias Table alias to prefix in SQL queries + * @var mixed get_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event + * If false, get_visibility_sql continues normally + * It must be either boolean or string + * @since 3.1.4-RC1 + */ + $vars = array( + 'where_sql', + 'mode', + 'forum_id', + 'table_alias', + 'get_visibility_sql_overwrite', + ); + extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_visibility_sql_before', compact($vars))); + + if ($get_visibility_sql_overwrite !== false) + { + return $get_visibility_sql_overwrite; + } + if ($this->auth->acl_get('m_approve', $forum_id)) { - return '1 = 1'; + return $where_sql . '1 = 1'; } - return $table_alias . $mode . '_visibility = ' . ITEM_APPROVED; + return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED; } /** @@ -160,6 +199,36 @@ class content_visibility $approve_forums = array_intersect($forum_ids, array_keys($this->auth->acl_getf('m_approve', true))); + $get_forums_visibility_sql_overwrite = false; + /** + * Allow changing the result of calling get_forums_visibility_sql + * + * @event core.phpbb_content_visibility_get_forums_visibility_before + * @var string where_sql The action the user tried to execute + * @var string mode Either "topic" or "post" depending on the query this is being used in + * @var array forum_ids Array of forum ids which the posts/topics are limited to + * @var string table_alias Table alias to prefix in SQL queries + * @var array approve_forums Array of forums where the user has m_approve permissions + * @var mixed get_forums_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event + * If false, get_forums_visibility_sql continues normally + * It must be either boolean or string + * @since 3.1.3-RC1 + */ + $vars = array( + 'where_sql', + 'mode', + 'forum_ids', + 'table_alias', + 'approve_forums', + 'get_forums_visibility_sql_overwrite', + ); + extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_forums_visibility_before', compact($vars))); + + if ($get_forums_visibility_sql_overwrite !== false) + { + return $get_forums_visibility_sql_overwrite; + } + if (sizeof($approve_forums)) { // Remove moderator forums from the rest @@ -206,6 +275,35 @@ class content_visibility $approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids); + $visibility_sql_overwrite = null; + + /** + * Allow changing the result of calling get_global_visibility_sql + * + * @event core.phpbb_content_visibility_get_global_visibility_before + * @var array where_sqls The action the user tried to execute + * @var string mode Either "topic" or "post" depending on the query this is being used in + * @var array exclude_forum_ids Array of forum ids the current user doesn't have access to + * @var string table_alias Table alias to prefix in SQL queries + * @var array approve_forums Array of forums where the user has m_approve permissions + * @var string visibility_sql_overwrite Forces the function to return an implosion of where_sqls (joined by "OR") + * @since 3.1.3-RC1 + */ + $vars = array( + 'where_sqls', + 'mode', + 'exclude_forum_ids', + 'table_alias', + 'approve_forums', + 'visibility_sql_overwrite', + ); + extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_global_visibility_before', compact($vars))); + + if ($visibility_sql_overwrite) + { + return $visibility_sql_overwrite; + } + if (sizeof($exclude_forum_ids)) { $where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true) . ' diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php index fc19b855c0..c6c470e91b 100644 --- a/phpBB/phpbb/controller/helper.php +++ b/phpBB/phpbb/controller/helper.php @@ -44,6 +44,9 @@ class helper /* @var \phpbb\symfony_request */ protected $symfony_request; + /* @var \phpbb\request\request_interface */ + protected $request; + /** * @var \phpbb\filesystem The filesystem object */ @@ -70,16 +73,18 @@ class helper * @param \phpbb\controller\provider $provider Path provider * @param \phpbb\extension\manager $manager Extension manager object * @param \phpbb\symfony_request $symfony_request Symfony Request object + * @param \phpbb\request\request_interface $request phpBB request object * @param \phpbb\filesystem $filesystem The filesystem object * @param string $phpbb_root_path phpBB root path * @param string $php_ext PHP file extension */ - public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext) + public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext) { $this->template = $template; $this->user = $user; $this->config = $config; $this->symfony_request = $symfony_request; + $this->request = $request; $this->filesystem = $filesystem; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; @@ -140,17 +145,20 @@ class helper // If enable_mod_rewrite is false we need to replace the current front-end by app.php, otherwise we need to remove it. $base_url = str_replace('/' . $page_name, empty($this->config['enable_mod_rewrite']) ? '/app.' . $this->php_ext : '', $base_url); - // We need to update the base url to move to the directory of the app.php file - if (empty($this->config['enable_mod_rewrite'])) - { - $base_url = str_replace('/app.' . $this->php_ext, '/' . $this->phpbb_root_path . 'app.' . $this->php_ext, $base_url); - } - else + // We need to update the base url to move to the directory of the app.php file if the current script is not app.php + if ($page_name !== 'app.php') { - $base_url .= preg_replace(get_preg_expression('path_remove_dot_trailing_slash'), '$2', $this->phpbb_root_path); + if (empty($this->config['enable_mod_rewrite'])) + { + $base_url = str_replace('/app.' . $this->php_ext, '/' . $this->phpbb_root_path . 'app.' . $this->php_ext, $base_url); + } + else + { + $base_url .= preg_replace(get_preg_expression('path_remove_dot_trailing_slash'), '$2', $this->phpbb_root_path); + } } - $base_url = $this->filesystem->clean_path($base_url); + $base_url = $this->request->escape($this->filesystem->clean_path($base_url), true); $context->setBaseUrl($base_url); @@ -176,15 +184,34 @@ class helper * @param string $message The error message * @param int $code The error code (e.g. 404, 500, 503, etc.) * @return Response A Response instance + * + * @deprecated 3.1.3 (To be removed: 3.3.0) Use exceptions instead. */ public function error($message, $code = 500) { + return $this->message($message, array(), 'INFORMATION', $code); + } + + /** + * Output a message + * + * In case of an error, please throw an exception instead + * + * @param string $message The message to display (must be a language variable) + * @param array $parameters The parameters to use with the language var + * @param string $title Title for the message (must be a language variable) + * @param int $code The HTTP status code (e.g. 404, 500, 503, etc.) + * @return Response A Response instance + */ + public function message($message, array $parameters = array(), $title = 'INFORMATION', $code = 200) + { + array_unshift($parameters, $message); $this->template->assign_vars(array( - 'MESSAGE_TEXT' => $message, - 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'), + 'MESSAGE_TEXT' => call_user_func_array(array($this->user, 'lang'), $parameters), + 'MESSAGE_TITLE' => $this->user->lang($title), )); - return $this->render('message_body.html', $this->user->lang('INFORMATION'), $code); + return $this->render('message_body.html', $this->user->lang($title), $code); } /** @@ -194,6 +221,6 @@ class helper */ public function get_current_url() { - return generate_board_url(true) . $this->symfony_request->getRequestUri(); + return generate_board_url(true) . $this->request->escape($this->symfony_request->getRequestUri(), true); } } diff --git a/phpBB/phpbb/cron/manager.php b/phpBB/phpbb/cron/manager.php index 5c8ac04b77..079ce8107e 100644 --- a/phpBB/phpbb/cron/manager.php +++ b/phpBB/phpbb/cron/manager.php @@ -73,6 +73,7 @@ class manager */ public function find_one_ready_task() { + shuffle($this->tasks); foreach ($this->tasks as $task) { if ($task->is_ready()) diff --git a/phpBB/phpbb/cron/task/core/queue.php b/phpBB/phpbb/cron/task/core/queue.php index 796a96d7f5..a9345a44df 100644 --- a/phpBB/phpbb/cron/task/core/queue.php +++ b/phpBB/phpbb/cron/task/core/queue.php @@ -73,6 +73,6 @@ class queue extends \phpbb\cron\task\base */ public function should_run() { - return $this->config['last_queue_run'] < time() - $this->config['queue_interval_config']; + return $this->config['last_queue_run'] < time() - $this->config['queue_interval']; } } diff --git a/phpBB/phpbb/db/driver/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php index 2ed08211ad..c0ddfbf76c 100644 --- a/phpBB/phpbb/db/driver/mysqli.php +++ b/phpBB/phpbb/db/driver/mysqli.php @@ -34,8 +34,7 @@ class mysqli extends \phpbb\db\driver\mysql_base return $this->sql_error(''); } - // Mysqli extension supports persistent connection since PHP 5.3.0 - $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false; + $this->persistency = $persistency; $this->user = $sqluser; // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix diff --git a/phpBB/phpbb/db/html_migrator_output_handler.php b/phpBB/phpbb/db/html_migrator_output_handler.php new file mode 100644 index 0000000000..e37c667463 --- /dev/null +++ b/phpBB/phpbb/db/html_migrator_output_handler.php @@ -0,0 +1,48 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db; + +use phpbb\user; + +class html_migrator_output_handler implements migrator_output_handler_interface +{ + /** + * User object. + * + * @var user + */ + private $user; + + /** + * Constructor + * + * @param user $user User object + */ + public function __construct(user $user) + { + $this->user = $user; + } + + /** + * {@inheritdoc} + */ + public function write($message, $verbosity) + { + if ($verbosity <= migrator_output_handler_interface::VERBOSITY_VERBOSE) + { + $final_message = call_user_func_array(array($this->user, 'lang'), $message); + echo $final_message . "<br />\n"; + } + } +} diff --git a/phpBB/phpbb/db/log_wrapper_migrator_output_handler.php b/phpBB/phpbb/db/log_wrapper_migrator_output_handler.php new file mode 100644 index 0000000000..94c293dc45 --- /dev/null +++ b/phpBB/phpbb/db/log_wrapper_migrator_output_handler.php @@ -0,0 +1,95 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db; + +use phpbb\user; + +class log_wrapper_migrator_output_handler implements migrator_output_handler_interface +{ + /** + * User object. + * + * @var user + */ + protected $user; + + /** + * A migrator output handler + * + * @var migrator_output_handler_interface + */ + protected $migrator; + + /** + * Log file handle + * @var resource + */ + protected $file_handle = false; + + /** + * Constructor + * + * @param user $user User object + * @param migrator_output_handler_interface $migrator Migrator output handler + * @param string $log_file File to log to + */ + public function __construct(user $user, migrator_output_handler_interface $migrator, $log_file) + { + $this->user = $user; + $this->migrator = $migrator; + $this->file_open($log_file); + } + + /** + * Open file for logging + * + * @param string $file File to open + */ + protected function file_open($file) + { + if (phpbb_is_writable(dirname($file))) + { + $this->file_handle = fopen($file, 'w'); + } + else + { + throw new \RuntimeException('Unable to write to migrator log file'); + } + } + + /** + * {@inheritdoc} + */ + public function write($message, $verbosity) + { + $this->migrator->write($message, $verbosity); + + if ($this->file_handle !== false) + { + $translated_message = call_user_func_array(array($this->user, 'lang'), $message) . "\n"; + + if ($verbosity <= migrator_output_handler_interface::VERBOSITY_NORMAL) + { + $translated_message = '[INFO] ' . $translated_message; + } + else + { + $translated_message = '[DEBUG] ' . $translated_message; + } + + fwrite($this->file_handle, $translated_message); + fflush($this->file_handle); + } + } +} diff --git a/phpBB/phpbb/db/migration/container_aware_migration.php b/phpBB/phpbb/db/migration/container_aware_migration.php new file mode 100644 index 0000000000..3b4b49b04b --- /dev/null +++ b/phpBB/phpbb/db/migration/container_aware_migration.php @@ -0,0 +1,36 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration; + +use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** +* Abstract base class for container aware database migrations. +*/ +abstract class container_aware_migration extends migration implements ContainerAwareInterface +{ + /** + * @var ContainerInterface + */ + protected $container; + + /** + * {@inheritdoc} + */ + public function setContainer(ContainerInterface $container = null) + { + $this->container = $container; + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_12_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_12_rc1.php index 8600472cca..f9f6d9f7f7 100644 --- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_12_rc1.php +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_12_rc1.php @@ -31,7 +31,6 @@ class release_3_0_12_rc1 extends \phpbb\db\migration\migration { return array( array('custom', array(array(&$this, 'update_module_auth'))), - array('custom', array(array(&$this, 'update_bots'))), array('custom', array(array(&$this, 'disable_bots_from_receiving_pms'))), array('config.update', array('version', '3.0.12-RC1')), @@ -70,60 +69,4 @@ class release_3_0_12_rc1 extends \phpbb\db\migration\migration AND module_mode = \'signature\''; $this->sql_query($sql); } - - public function update_bots() - { - // Update bots - if (!function_exists('user_delete')) - { - include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - $bots_updates = array( - // Bot Deletions - 'NG-Search [Bot]' => false, - 'Nutch/CVS [Bot]' => false, - 'OmniExplorer [Bot]' => false, - 'Seekport [Bot]' => false, - 'Synoo [Bot]' => false, - 'WiseNut [Bot]' => false, - - // Bot Updates - // Bot name to bot user agent map - 'Baidu [Spider]' => 'Baiduspider', - 'Exabot [Bot]' => 'Exabot', - 'Voyager [Bot]' => 'voyager/', - 'W3C [Validator]' => 'W3C_Validator', - ); - - foreach ($bots_updates as $bot_name => $bot_agent) - { - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_IGNORE . " - AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($bot_name)) . "'"; - $result = $this->db->sql_query($sql); - $bot_user_id = (int) $this->db->sql_fetchfield('user_id'); - $this->db->sql_freeresult($result); - - if ($bot_user_id) - { - if ($bot_agent === false) - { - $sql = 'DELETE FROM ' . BOTS_TABLE . " - WHERE user_id = $bot_user_id"; - $this->sql_query($sql); - - user_delete('retain', $bot_user_id); - } - else - { - $sql = 'UPDATE ' . BOTS_TABLE . " - SET bot_agent = '" . $this->db->sql_escape($bot_agent) . "' - WHERE user_id = $bot_user_id"; - $this->sql_query($sql); - } - } - } - } } diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_13.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13.php new file mode 100644 index 0000000000..310fcc70fc --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13.php @@ -0,0 +1,37 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v30x; + +class release_3_0_13 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return phpbb_version_compare($this->config['version'], '3.0.13', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v30x\release_3_0_13_rc1'); + } + + public function update_data() + { + return array( + array('if', array( + phpbb_version_compare($this->config['version'], '3.0.13', '<'), + array('config.update', array('version', '3.0.13')), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_pl1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_pl1.php new file mode 100644 index 0000000000..b12a96a7fb --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_pl1.php @@ -0,0 +1,37 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v30x; + +class release_3_0_13_pl1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return phpbb_version_compare($this->config['version'], '3.0.13-PL1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v30x\release_3_0_13'); + } + + public function update_data() + { + return array( + array('if', array( + phpbb_version_compare($this->config['version'], '3.0.13-PL1', '<'), + array('config.update', array('version', '3.0.13-PL1')), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_rc1.php new file mode 100644 index 0000000000..9ea68fa862 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_rc1.php @@ -0,0 +1,37 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v30x; + +class release_3_0_13_rc1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return phpbb_version_compare($this->config['version'], '3.0.13-RC1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v30x\release_3_0_12'); + } + + public function update_data() + { + return array( + array('if', array( + phpbb_version_compare($this->config['version'], '3.0.13-RC1', '<'), + array('config.update', array('version', '3.0.13-RC1')), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php index f593c32181..003ccf8f18 100644 --- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php @@ -13,7 +13,9 @@ namespace phpbb\db\migration\data\v30x; -class release_3_0_5_rc1 extends \phpbb\db\migration\migration +use phpbb\db\migration\container_aware_migration; + +class release_3_0_5_rc1 extends container_aware_migration { public function effectively_installed() { @@ -55,6 +57,7 @@ class release_3_0_5_rc1 extends \phpbb\db\migration\migration public function hash_old_passwords() { + $passwords_manager = $this->container->get('passwords.manager'); $sql = 'SELECT user_id, user_password FROM ' . $this->table_prefix . 'users WHERE user_pass_convert = 1'; @@ -65,7 +68,7 @@ class release_3_0_5_rc1 extends \phpbb\db\migration\migration if (strlen($row['user_password']) == 32) { $sql_ary = array( - 'user_password' => phpbb_hash($row['user_password']), + 'user_password' => '$CP$' . $passwords_manager->hash($row['user_password'], 'passwords.driver.salted_md5'), ); $this->sql_query('UPDATE ' . $this->table_prefix . 'users SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $row['user_id']); @@ -107,7 +110,7 @@ class release_3_0_5_rc1 extends \phpbb\db\migration\migration // Select auth_option_ids... the largest id will be preserved $sql = 'SELECT auth_option_id FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option = '" . $db->sql_escape($option) . "' + WHERE auth_option = '" . $this->db->sql_escape($option) . "' ORDER BY auth_option_id DESC"; // sql_query_limit not possible here, due to bug in postgresql layer $result = $this->db->sql_query($sql); diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php index 4e863fa143..22fd51543b 100644 --- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php @@ -30,7 +30,6 @@ class release_3_0_8_rc1 extends \phpbb\db\migration\migration return array( array('custom', array(array(&$this, 'update_file_extension_group_names'))), array('custom', array(array(&$this, 'update_module_auth'))), - array('custom', array(array(&$this, 'update_bots'))), array('custom', array(array(&$this, 'delete_orphan_shadow_topics'))), array('module.add', array( 'acp', @@ -114,70 +113,6 @@ class release_3_0_8_rc1 extends \phpbb\db\migration\migration $this->sql_query($sql); } - public function update_bots() - { - $bot_name = 'Bing [Bot]'; - $bot_name_clean = utf8_clean_string($bot_name); - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $this->db->sql_escape($bot_name_clean) . "'"; - $result = $this->db->sql_query($sql); - $bing_already_added = (bool) $this->db->sql_fetchfield('user_id'); - $this->db->sql_freeresult($result); - - if (!$bing_already_added) - { - $bot_agent = 'bingbot/'; - $bot_ip = ''; - $sql = 'SELECT group_id, group_colour - FROM ' . GROUPS_TABLE . " - WHERE group_name = 'BOTS'"; - $result = $this->db->sql_query($sql); - $group_row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if (!$group_row) - { - // default fallback, should never get here - $group_row['group_id'] = 6; - $group_row['group_colour'] = '9E8DA7'; - } - - if (!function_exists('user_add')) - { - include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - $user_row = array( - 'user_type' => USER_IGNORE, - 'group_id' => $group_row['group_id'], - 'username' => $bot_name, - 'user_regdate' => time(), - 'user_password' => '', - 'user_colour' => $group_row['group_colour'], - 'user_email' => '', - 'user_lang' => $this->config['default_lang'], - 'user_style' => $this->config['default_style'], - 'user_timezone' => 0, - 'user_dateformat' => $this->config['default_dateformat'], - 'user_allow_massemail' => 0, - ); - - $user_id = user_add($user_row); - - $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $this->db->sql_build_array('INSERT', array( - 'bot_active' => 1, - 'bot_name' => (string) $bot_name, - 'user_id' => (int) $user_id, - 'bot_agent' => (string) $bot_agent, - 'bot_ip' => (string) $bot_ip, - )); - - $this->sql_query($sql); - } - } - public function delete_orphan_shadow_topics() { // Delete shadow topics pointing to not existing topics diff --git a/phpBB/phpbb/db/migration/data/v310/bot_update.php b/phpBB/phpbb/db/migration/data/v310/bot_update.php new file mode 100644 index 0000000000..39b16c68f8 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/bot_update.php @@ -0,0 +1,150 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class bot_update extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\rc6'); + } + + public function update_data() + { + return array( + array('custom', array(array(&$this, 'update_bing_bot'))), + array('custom', array(array(&$this, 'update_bots'))), + ); + } + + public function update_bing_bot() + { + $bot_name = 'Bing [Bot]'; + $bot_name_clean = utf8_clean_string($bot_name); + + $sql = 'SELECT user_id + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $this->db->sql_escape($bot_name_clean) . "'"; + $result = $this->db->sql_query($sql); + $bing_already_added = (bool) $this->db->sql_fetchfield('user_id'); + $this->db->sql_freeresult($result); + + if (!$bing_already_added) + { + $bot_agent = 'bingbot/'; + $bot_ip = ''; + $sql = 'SELECT group_id, group_colour + FROM ' . GROUPS_TABLE . " + WHERE group_name = 'BOTS'"; + $result = $this->db->sql_query($sql); + $group_row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if (!$group_row) + { + // default fallback, should never get here + $group_row['group_id'] = 6; + $group_row['group_colour'] = '9E8DA7'; + } + + if (!function_exists('user_add')) + { + include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); + } + + $user_row = array( + 'user_type' => USER_IGNORE, + 'group_id' => $group_row['group_id'], + 'username' => $bot_name, + 'user_regdate' => time(), + 'user_password' => '', + 'user_colour' => $group_row['group_colour'], + 'user_email' => '', + 'user_lang' => $this->config['default_lang'], + 'user_style' => $this->config['default_style'], + 'user_timezone' => 0, + 'user_dateformat' => $this->config['default_dateformat'], + 'user_allow_massemail' => 0, + ); + + $user_id = user_add($user_row); + + $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $this->db->sql_build_array('INSERT', array( + 'bot_active' => 1, + 'bot_name' => (string) $bot_name, + 'user_id' => (int) $user_id, + 'bot_agent' => (string) $bot_agent, + 'bot_ip' => (string) $bot_ip, + )); + + $this->sql_query($sql); + } + } + + public function update_bots() + { + // Update bots + if (!function_exists('user_delete')) + { + include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); + } + + $bots_updates = array( + // Bot Deletions + 'NG-Search [Bot]' => false, + 'Nutch/CVS [Bot]' => false, + 'OmniExplorer [Bot]' => false, + 'Seekport [Bot]' => false, + 'Synoo [Bot]' => false, + 'WiseNut [Bot]' => false, + + // Bot Updates + // Bot name to bot user agent map + 'Baidu [Spider]' => 'Baiduspider', + 'Exabot [Bot]' => 'Exabot', + 'Voyager [Bot]' => 'voyager/', + 'W3C [Validator]' => 'W3C_Validator', + ); + + foreach ($bots_updates as $bot_name => $bot_agent) + { + $sql = 'SELECT user_id + FROM ' . USERS_TABLE . ' + WHERE user_type = ' . USER_IGNORE . " + AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($bot_name)) . "'"; + $result = $this->db->sql_query($sql); + $bot_user_id = (int) $this->db->sql_fetchfield('user_id'); + $this->db->sql_freeresult($result); + + if ($bot_user_id) + { + if ($bot_agent === false) + { + $sql = 'DELETE FROM ' . BOTS_TABLE . " + WHERE user_id = $bot_user_id"; + $this->sql_query($sql); + + user_delete('retain', $bot_user_id); + } + else + { + $sql = 'UPDATE ' . BOTS_TABLE . " + SET bot_agent = '" . $this->db->sql_escape($bot_agent) . "' + WHERE user_id = $bot_user_id"; + $this->sql_query($sql); + } + } + } + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php index 13071e9891..328c08f1ec 100644 --- a/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php +++ b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php @@ -25,9 +25,13 @@ class captcha_plugins extends \phpbb\db\migration\migration public function update_data() { $captcha_plugin = $this->config['captcha_plugin']; - if (strpos($this->config['captcha_plugin'], 'phpbb_captcha_') === 0) + if (strpos($captcha_plugin, 'phpbb_captcha_') === 0) { - $captcha_plugin = substr($this->config['captcha_plugin'], strlen('phpbb_captcha_')); + $captcha_plugin = substr($captcha_plugin, strlen('phpbb_captcha_')); + } + else if (strpos($captcha_plugin, 'phpbb_') === 0) + { + $captcha_plugin = substr($captcha_plugin, strlen('phpbb_')); } return array( diff --git a/phpBB/phpbb/db/migration/data/v310/contact_admin_form.php b/phpBB/phpbb/db/migration/data/v310/contact_admin_form.php index c2dd09ddf6..5736369f1a 100644 --- a/phpBB/phpbb/db/migration/data/v310/contact_admin_form.php +++ b/phpBB/phpbb/db/migration/data/v310/contact_admin_form.php @@ -20,6 +20,11 @@ class contact_admin_form extends \phpbb\db\migration\migration return isset($this->config['contact_admin_form_enable']); } + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\config_db_text'); + } + public function update_data() { return array( diff --git a/phpBB/phpbb/db/migration/data/v310/gold.php b/phpBB/phpbb/db/migration/data/v310/gold.php new file mode 100644 index 0000000000..e84c7ee951 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/gold.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class gold extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v310\rc6', + '\phpbb\db\migration\data\v310\bot_update', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.0')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php b/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php index 4530ebe285..e04a705c91 100644 --- a/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php +++ b/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php @@ -15,10 +15,18 @@ namespace phpbb\db\migration\data\v310; class mysql_fulltext_drop extends \phpbb\db\migration\migration { + protected $indexes; + public function effectively_installed() { // This migration is irrelevant for all non-MySQL DBMSes. - return strpos($this->db->get_sql_layer(), 'mysql') === false; + if (strpos($this->db->get_sql_layer(), 'mysql') === false) + { + return true; + } + + $this->find_indexes_to_drop(); + return empty($this->indexes); } static public function depends_on() @@ -30,6 +38,11 @@ class mysql_fulltext_drop extends \phpbb\db\migration\migration public function update_schema() { + if (empty($this->indexes)) + { + return array(); + } + /* * Drop FULLTEXT indexes related to MySQL fulltext search. * Doing so is equivalent to dropping the search index from the ACP. @@ -40,12 +53,28 @@ class mysql_fulltext_drop extends \phpbb\db\migration\migration */ return array( 'drop_keys' => array( - $this->table_prefix . 'posts' => array( - 'post_subject', - 'post_text', - 'post_content', - ), + $this->table_prefix . 'posts' => $this->indexes, ), ); } + + public function find_indexes_to_drop() + { + if ($this->indexes !== null) + { + return $this->indexes; + } + + $this->indexes = array(); + $potential_keys = array('post_subject', 'post_text', 'post_content'); + foreach ($potential_keys as $key) + { + if ($this->db_tools->sql_index_exists($this->table_prefix . 'posts', $key)) + { + $this->indexes[] = $key; + } + } + + return $this->indexes; + } } diff --git a/phpBB/phpbb/db/migration/data/v310/notifications_use_full_name.php b/phpBB/phpbb/db/migration/data/v310/notifications_use_full_name.php index f749b32119..112c1e85e8 100644 --- a/phpBB/phpbb/db/migration/data/v310/notifications_use_full_name.php +++ b/phpBB/phpbb/db/migration/data/v310/notifications_use_full_name.php @@ -92,10 +92,41 @@ class notifications_use_full_name extends \phpbb\db\migration\migration foreach ($this->notification_types as $notification_type) { - $sql = 'UPDATE ' . NOTIFICATION_TYPES_TABLE . " - SET notification_type_name = 'notification.type.{$notification_type}' - WHERE notification_type_name = '{$notification_type}'"; - $this->db->sql_query($sql); + $sql = 'SELECT notification_type_id + FROM ' . NOTIFICATION_TYPES_TABLE . " + WHERE notification_type_name = 'notification.type.{$notification_type}'"; + $result = $this->db->sql_query($sql); + $new_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); + $this->db->sql_freeresult($result); + + if ($new_type_id) + { + // New type name already exists, + // so we delete the old type and update the type id of existing entries. + $sql = 'SELECT notification_type_id + FROM ' . NOTIFICATION_TYPES_TABLE . " + WHERE notification_type_name = '{$notification_type}'"; + $result = $this->db->sql_query($sql); + $old_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); + $this->db->sql_freeresult($result); + + $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . ' + SET notification_type_id = ' . (int) $new_type_id . ' + WHERE notification_type_id = ' . (int) $old_type_id; + $this->db->sql_query($sql); + + $sql = 'DELETE FROM ' . NOTIFICATION_TYPES_TABLE . " + WHERE notification_type_name = '{$notification_type}'"; + $this->db->sql_query($sql); + } + else + { + // Otherwise we just update the name + $sql = 'UPDATE ' . NOTIFICATION_TYPES_TABLE . " + SET notification_type_name = 'notification.type.{$notification_type}' + WHERE notification_type_name = '{$notification_type}'"; + $this->db->sql_query($sql); + } $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . " SET item_type = 'notification.type.{$notification_type}' @@ -108,10 +139,41 @@ class notifications_use_full_name extends \phpbb\db\migration\migration { foreach ($this->notification_types as $notification_type) { - $sql = 'UPDATE ' . NOTIFICATION_TYPES_TABLE . " - SET notification_type_name = '{$notification_type}' - WHERE notification_type_name = 'notification.type.{$notification_type}'"; - $this->db->sql_query($sql); + $sql = 'SELECT notification_type_id + FROM ' . NOTIFICATION_TYPES_TABLE . " + WHERE notification_type_name = '{$notification_type}'"; + $result = $this->db->sql_query($sql); + $new_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); + $this->db->sql_freeresult($result); + + if ($new_type_id) + { + // New type name already exists, + // so we delete the old type and update the type id of existing entries. + $sql = 'SELECT notification_type_id + FROM ' . NOTIFICATION_TYPES_TABLE . " + WHERE notification_type_name = 'notification.type.{$notification_type}'"; + $result = $this->db->sql_query($sql); + $old_type_id = (int) $this->db->sql_fetchfield('notification_type_id'); + $this->db->sql_freeresult($result); + + $sql = 'UPDATE ' . NOTIFICATIONS_TABLE . ' + SET notification_type_id = ' . (int) $new_type_id . ' + WHERE notification_type_id = ' . (int) $old_type_id; + $this->db->sql_query($sql); + + $sql = 'DELETE FROM ' . NOTIFICATION_TYPES_TABLE . " + WHERE notification_type_name = 'notification.type.{$notification_type}'"; + $this->db->sql_query($sql); + } + else + { + // Otherwise we just update the name + $sql = 'UPDATE ' . NOTIFICATION_TYPES_TABLE . " + SET notification_type_name = '{$notification_type}' + WHERE notification_type_name = 'notification.type.{$notification_type}'"; + $this->db->sql_query($sql); + } $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . " SET item_type = '{$notification_type}' diff --git a/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php b/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php index ea442dfb1b..3457c19478 100644 --- a/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php +++ b/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php @@ -15,10 +15,18 @@ namespace phpbb\db\migration\data\v310; class postgres_fulltext_drop extends \phpbb\db\migration\migration { + protected $indexes; + public function effectively_installed() { // This migration is irrelevant for all non-PostgreSQL DBMSes. - return strpos($this->db->get_sql_layer(), 'postgres') === false; + if (strpos($this->db->get_sql_layer(), 'postgres') === false) + { + return true; + } + + $this->find_indexes_to_drop(); + return empty($this->indexes); } static public function depends_on() @@ -30,6 +38,11 @@ class postgres_fulltext_drop extends \phpbb\db\migration\migration public function update_schema() { + if (empty($this->indexes)) + { + return array(); + } + /* * Drop FULLTEXT indexes related to PostgreSQL fulltext search. * Doing so is equivalent to dropping the search index from the ACP. @@ -40,12 +53,28 @@ class postgres_fulltext_drop extends \phpbb\db\migration\migration */ return array( 'drop_keys' => array( - $this->table_prefix . 'posts' => array( - 'post_subject', - 'post_text', - 'post_content', - ), + $this->table_prefix . 'posts' => $this->indexes, ), ); } + + public function find_indexes_to_drop() + { + if ($this->indexes !== null) + { + return $this->indexes; + } + + $this->indexes = array(); + $potential_keys = array('post_subject', 'post_text', 'post_content'); + foreach ($potential_keys as $key) + { + if ($this->db_tools->sql_index_exists($this->table_prefix . 'posts', $key)) + { + $this->indexes[] = $key; + } + } + + return $this->indexes; + } } diff --git a/phpBB/phpbb/db/migration/data/v310/rc5.php b/phpBB/phpbb/db/migration/data/v310/rc5.php new file mode 100644 index 0000000000..5b6f70e32e --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/rc5.php @@ -0,0 +1,33 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class rc5 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v310\rc4', + '\phpbb\db\migration\data\v310\profilefield_field_validation_length', + '\phpbb\db\migration\data\v310\remove_acp_styles_cache', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.0-RC5')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/rc6.php b/phpBB/phpbb/db/migration/data/v310/rc6.php new file mode 100644 index 0000000000..b84f2edcc9 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/rc6.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class rc6 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v310\rc5', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.0-RC6')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/remove_acp_styles_cache.php b/phpBB/phpbb/db/migration/data/v310/remove_acp_styles_cache.php new file mode 100644 index 0000000000..7b84539814 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/remove_acp_styles_cache.php @@ -0,0 +1,51 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v310; + +class remove_acp_styles_cache extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + $sql = 'SELECT module_id + FROM ' . MODULES_TABLE . " + WHERE module_class = 'acp' + AND module_langname = 'ACP_STYLES_CACHE'"; + $result = $this->db->sql_query($sql); + $module_id = $this->db->sql_fetchfield('module_id'); + $this->db->sql_freeresult($result); + + return !$module_id; + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\rc4'); + } + + public function update_data() + { + return array( + array('module.remove', array( + 'acp', + 'ACP_STYLE_MANAGEMENT', + array( + 'module_basename' => 'acp_styles', + 'module_langname' => 'ACP_STYLES_CACHE', + 'module_mode' => 'cache', + 'module_auth' => 'acl_a_styles', + ), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php b/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php index d5f9076196..8211457dc6 100644 --- a/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php +++ b/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php @@ -29,7 +29,8 @@ class reset_missing_captcha_plugin extends \phpbb\db\migration\migration { return array( array('if', array( - (!is_file($this->phpbb_root_path . "includes/captcha/plugins/{$this->config['captcha_plugin']}_plugin." . $this->php_ext)), + (is_dir($this->phpbb_root_path . 'includes/captcha/plugins/') && + !is_file($this->phpbb_root_path . "includes/captcha/plugins/{$this->config['captcha_plugin']}_plugin." . $this->php_ext)), array('config.update', array('captcha_plugin', 'phpbb_captcha_nogd')), )), ); diff --git a/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php b/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php index 58845b88ec..85b90da5fa 100644 --- a/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php +++ b/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php @@ -13,12 +13,14 @@ namespace phpbb\db\migration\data\v310; +use phpbb\db\migration\container_aware_migration; + /** * Migration to convert the Soft Delete MOD for 3.0 * * https://www.phpbb.com/customise/db/mod/soft_delete/ */ -class soft_delete_mod_convert extends \phpbb\db\migration\migration +class soft_delete_mod_convert extends container_aware_migration { static public function depends_on() { @@ -115,19 +117,11 @@ class soft_delete_mod_convert extends \phpbb\db\migration\migration } } + /** + * @return \phpbb\content_visibility + */ protected function get_content_visibility() { - return new \phpbb\content_visibility( - new \phpbb\auth\auth(), - $this->config, - $this->db, - new \phpbb\user('\phpbb\datetime'), - $this->phpbb_root_path, - $this->php_ext, - $this->table_prefix . 'forums', - $this->table_prefix . 'posts', - $this->table_prefix . 'topics', - $this->table_prefix . 'users' - ); + return $this->container->get('content.visibility'); } } diff --git a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php index 5a3a1d5de7..e8d3a3af64 100644 --- a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php +++ b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php @@ -92,7 +92,7 @@ class style_update_p1 extends \phpbb\db\migration\migration else { $sql = 'SELECT s.style_id, t.template_path, t.template_id, t.bbcode_bitfield, t.template_inherits_id, t.template_inherit_path, c.theme_path, c.theme_id - FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . "stles_theme c + FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . "styles_theme c WHERE t.template_id = s.template_id AND c.theme_id = s.theme_id"; } diff --git a/phpBB/phpbb/db/migration/data/v31x/m_softdelete_global.php b/phpBB/phpbb/db/migration/data/v31x/m_softdelete_global.php new file mode 100644 index 0000000000..dd7e20e762 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/m_softdelete_global.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class m_softdelete_global extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v311'); + } + + public function update_data() + { + return array( + // Make m_softdelete global. The add method will take care of updating + // it if it already exists. + array('permission.add', array('m_softdelete', true)), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/plupload_last_gc_dynamic.php b/phpBB/phpbb/db/migration/data/v31x/plupload_last_gc_dynamic.php new file mode 100644 index 0000000000..0783d707c5 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/plupload_last_gc_dynamic.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class plupload_last_gc_dynamic extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v312'); + } + + public function update_data() + { + return array( + // Make plupload_last_gc dynamic. + array('config.remove', array('plupload_last_gc')), + array('config.add', array('plupload_last_gc', 0, 1)), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/profilefield_remove_underscore_from_alpha.php b/phpBB/phpbb/db/migration/data/v31x/profilefield_remove_underscore_from_alpha.php new file mode 100644 index 0000000000..60491f8de8 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/profilefield_remove_underscore_from_alpha.php @@ -0,0 +1,47 @@ +<?php + +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\migration\data\v31x; + +class profilefield_remove_underscore_from_alpha extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v311'); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'remove_underscore_from_alpha_validations'))), + ); + } + + public function remove_underscore_from_alpha_validations() + { + $this->update_validation_rule('[\w]+', '[a-zA-Z0-9]+'); + $this->update_validation_rule('[\w_]+', '[\w]+'); + $this->update_validation_rule('[\w.]+', '[a-zA-Z0-9.]+'); + $this->update_validation_rule('[\w\x20_+\-\[\]]+', '[\w\x20+\-\[\]]+'); + $this->update_validation_rule('[a-zA-Z][\w\.,\-_]+', '[a-zA-Z][\w\.,\-]+'); + } + + public function update_validation_rule($old_validation, $new_validation) + { + $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " + SET field_validation = '" . $this->db->sql_escape($new_validation) . "' + WHERE field_validation = '" . $this->db->sql_escape($old_validation) . "'"; + $this->db->sql_query($sql); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/profilefield_yahoo_update_url.php b/phpBB/phpbb/db/migration/data/v31x/profilefield_yahoo_update_url.php new file mode 100644 index 0000000000..4df9083bdf --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/profilefield_yahoo_update_url.php @@ -0,0 +1,38 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class profilefield_yahoo_update_url extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v312'); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'update_contact_url'))), + ); + } + + public function update_contact_url() + { + $sql = 'UPDATE ' . $this->table_prefix . "profile_fields + SET field_contact_url = 'ymsgr:sendim?%s' + WHERE field_name = 'phpbb_yahoo' + AND field_contact_url = 'http://edit.yahoo.com/config/send_webmesg?.target=%s&.src=pg'"; + $this->sql_query($sql); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/style_update.php b/phpBB/phpbb/db/migration/data/v31x/style_update.php new file mode 100644 index 0000000000..bb030bbe6d --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/style_update.php @@ -0,0 +1,136 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class style_update extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v310\gold'); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'update_installed_styles'))), + ); + } + + public function update_installed_styles() + { + // Get all currently available styles + $styles = $this->find_style_dirs(); + $style_paths = $style_ids = array(); + + $sql = 'SELECT style_path, style_id + FROM ' . $this->table_prefix . 'styles'; + $result = $this->db->sql_query($sql); + while ($styles_row = $this->db->sql_fetchrow()) + { + if (in_array($styles_row['style_path'], $styles)) + { + $style_paths[] = $styles_row['style_path']; + $style_ids[] = $styles_row['style_id']; + } + } + $this->db->sql_freeresult($result); + + // Install prosilver if no style is available and prosilver can be installed + if (empty($style_paths) && in_array('prosilver', $styles)) + { + // Try to parse config file + $cfg = parse_cfg_file($this->phpbb_root_path . 'styles/prosilver/style.cfg'); + + // Stop running this if prosilver cfg file can't be read + if (empty($cfg)) + { + throw new \RuntimeException('No styles available and could not fall back to prosilver.'); + } + + $style = array( + 'style_name' => 'prosilver', + 'style_copyright' => '© phpBB Limited', + 'style_active' => 1, + 'style_path' => 'prosilver', + 'bbcode_bitfield' => 'kNg=', + 'style_parent_id' => 0, + 'style_parent_tree' => '', + ); + + // Add to database + $this->db->sql_transaction('begin'); + + $sql = 'INSERT INTO ' . $this->table_prefix . 'styles + ' . $this->db->sql_build_array('INSERT', $style); + $this->db->sql_query($sql); + + $style_id = $this->db->sql_nextid(); + $style_ids[] = $style_id; + + $this->db->sql_transaction('commit'); + + // Set prosilver to default style + $this->config->set('default_style', $style_id); + } + else if (empty($styles) && empty($available_styles)) + { + throw new \RuntimeException('No valid styles available'); + } + + // Make sure default style is available + if (!in_array($this->config['default_style'], $style_ids)) + { + $this->config->set('default_style', array_pop($style_ids)); + } + + // Reset users to default style if their user_style is nonexistent + $sql = 'UPDATE ' . $this->table_prefix . "users + SET user_style = {$this->config['default_style']} + WHERE " . $this->db->sql_in_set('user_style', $style_ids, true, true); + $this->db->sql_query($sql); + } + + /** + * Find all directories that have styles + * Copied from acp_styles + * + * @return array Directory names + */ + protected function find_style_dirs() + { + $styles = array(); + $styles_path = $this->phpbb_root_path . 'styles/'; + + $dp = @opendir($styles_path); + if ($dp) + { + while (($file = readdir($dp)) !== false) + { + $dir = $styles_path . $file; + if ($file[0] == '.' || !is_dir($dir)) + { + continue; + } + + if (file_exists("{$dir}/style.cfg")) + { + $styles[] = $file; + } + } + closedir($dp); + } + + return $styles; + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php new file mode 100644 index 0000000000..854ed1f568 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php @@ -0,0 +1,70 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class update_custom_bbcodes_with_idn extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v312', + ); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'update_bbcodes_table'))), + ); + } + + public function update_bbcodes_table() + { + if (!class_exists('acp_bbcodes')) + { + include($this->phpbb_root_path . 'includes/acp/acp_bbcodes.' . $this->php_ext); + } + + $bbcodes = new \acp_bbcodes(); + + $sql = 'SELECT bbcode_id, bbcode_match, bbcode_tpl + FROM ' . BBCODES_TABLE; + $result = $this->sql_query($sql); + + $sql_ary = array(); + while ($row = $this->db->sql_fetchrow($result)) + { + $data = array(); + if (preg_match('/(URL|LOCAL_URL|RELATIVE_URL)/', $row['bbcode_match'])) + { + $data = $bbcodes->build_regexp($row['bbcode_match'], $row['bbcode_tpl']); + $sql_ary[$row['bbcode_id']] = array( + 'first_pass_match' => $data['first_pass_match'], + 'first_pass_replace' => $data['first_pass_replace'], + 'second_pass_match' => $data['second_pass_match'], + 'second_pass_replace' => $data['second_pass_replace'] + ); + } + } + $this->db->sql_freeresult($result); + + foreach ($sql_ary as $bbcode_id => $bbcode_data) + { + $sql = 'UPDATE ' . BBCODES_TABLE . ' + SET ' . $this->db->sql_build_array('UPDATE', $bbcode_data) . ' + WHERE bbcode_id = ' . (int) $bbcode_id; + $this->sql_query($sql); + } + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v311.php b/phpBB/phpbb/db/migration/data/v31x/v311.php new file mode 100644 index 0000000000..00844dd4c0 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v311.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v311 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v310\gold', + '\phpbb\db\migration\data\v31x\style_update', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.1')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v312.php b/phpBB/phpbb/db/migration/data/v31x/v312.php new file mode 100644 index 0000000000..bf49935f4d --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v312.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v312 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v312rc1', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.2')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v312rc1.php b/phpBB/phpbb/db/migration/data/v31x/v312rc1.php new file mode 100644 index 0000000000..d4b133fc01 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v312rc1.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v312rc1 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v311', + '\phpbb\db\migration\data\v31x\m_softdelete_global', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.2-RC1')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v313.php b/phpBB/phpbb/db/migration/data/v31x/v313.php new file mode 100644 index 0000000000..5a4e21a9b7 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v313.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v313 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v313rc2', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.3')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v313rc1.php b/phpBB/phpbb/db/migration/data/v31x/v313rc1.php new file mode 100644 index 0000000000..e50754f805 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v313rc1.php @@ -0,0 +1,35 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v313rc1 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v30x\release_3_0_13_rc1', + '\phpbb\db\migration\data\v31x\plupload_last_gc_dynamic', + '\phpbb\db\migration\data\v31x\profilefield_remove_underscore_from_alpha', + '\phpbb\db\migration\data\v31x\profilefield_yahoo_update_url', + '\phpbb\db\migration\data\v31x\update_custom_bbcodes_with_idn', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.3-RC1')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v313rc2.php b/phpBB/phpbb/db/migration/data/v31x/v313rc2.php new file mode 100644 index 0000000000..d832d6f502 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v313rc2.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v313rc2 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v30x\release_3_0_13_pl1', + '\phpbb\db\migration\data\v31x\v313rc1', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.3-RC2')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/profilefield_base_migration.php b/phpBB/phpbb/db/migration/profilefield_base_migration.php index 9000949a7d..da1a38e2fa 100644 --- a/phpBB/phpbb/db/migration/profilefield_base_migration.php +++ b/phpBB/phpbb/db/migration/profilefield_base_migration.php @@ -13,7 +13,7 @@ namespace phpbb\db\migration; -abstract class profilefield_base_migration extends \phpbb\db\migration\migration +abstract class profilefield_base_migration extends container_aware_migration { protected $profilefield_name; @@ -237,8 +237,7 @@ abstract class profilefield_base_migration extends \phpbb\db\migration\migration if ($profile_row === null) { - global $phpbb_container; - $manager = $phpbb_container->get('profilefields.manager'); + $manager = $this->container->get('profilefields.manager'); $profile_row = $manager->build_insert_sql_array(array()); } diff --git a/phpBB/phpbb/db/migration/tool/module.php b/phpBB/phpbb/db/migration/tool/module.php index db43046a95..035625b095 100644 --- a/phpBB/phpbb/db/migration/tool/module.php +++ b/phpBB/phpbb/db/migration/tool/module.php @@ -475,6 +475,7 @@ class module implements \phpbb\db\migration\tool\tool_interface if (!class_exists('acp_modules')) { include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); + $this->user->add_lang('acp/modules'); } $acp_modules = new \acp_modules(); $module = $acp_modules->get_module_infos($basename, $class, true); diff --git a/phpBB/phpbb/db/migration/tool/permission.php b/phpBB/phpbb/db/migration/tool/permission.php index 5cfbc5ca00..1a91127d2d 100644 --- a/phpBB/phpbb/db/migration/tool/permission.php +++ b/phpBB/phpbb/db/migration/tool/permission.php @@ -537,7 +537,8 @@ class permission implements \phpbb\db\migration\tool\tool_interface } $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' - WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove); + WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove) . ' + AND role_id = ' . (int) $role_id; $this->db->sql_query($sql); break; diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php index 44bea3c5d2..7fc3e787e2 100644 --- a/phpBB/phpbb/db/migrator.php +++ b/phpBB/phpbb/db/migrator.php @@ -13,11 +13,19 @@ namespace phpbb\db; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + /** * The migrator is responsible for applying new migrations in the correct order. */ class migrator { + /** + * @var ContainerInterface + */ + protected $container; + /** @var \phpbb\config\config */ protected $config; @@ -59,6 +67,13 @@ class migrator protected $migrations = array(); /** + * Array of migrations that have been determined to be fulfillable + * + * @var array + */ + protected $fulfillable_migrations = array(); + + /** * 'name,' 'class,' and 'state' of the last migration run * * 'effectively_installed' set and set to true if the migration was effectively_installed @@ -68,10 +83,18 @@ class migrator public $last_run_migration = false; /** + * The output handler. A null handler is configured by default. + * + * @var migrator_output_handler_interface + */ + public $output_handler; + + /** * Constructor of the database migrator */ - public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $migrations_table, $phpbb_root_path, $php_ext, $table_prefix, $tools, \phpbb\db\migration\helper $helper) + public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $migrations_table, $phpbb_root_path, $php_ext, $table_prefix, $tools, \phpbb\db\migration\helper $helper) { + $this->container = $container; $this->config = $config; $this->db = $db; $this->db_tools = $db_tools; @@ -84,6 +107,8 @@ class migrator $this->table_prefix = $table_prefix; + $this->output_handler = new null_migrator_output_handler(); + foreach ($tools as $tool) { $this->tools[$tool->get_name()] = $tool; @@ -95,6 +120,16 @@ class migrator } /** + * Set the output handler. + * + * @param migrator_output_handler $handler The output handler + */ + public function set_output_handler(migrator_output_handler_interface $handler) + { + $this->output_handler = $handler; + } + + /** * Loads all migrations and their application state from the database. * * @return null @@ -146,6 +181,18 @@ class migrator */ public function update() { + $this->container->get('dispatcher')->disable(); + $this->update_do(); + $this->container->get('dispatcher')->enable(); + } + + /** + * Effectively runs a single update step from the next migration to be applied. + * + * @return null + */ + protected function update_do() + { foreach ($this->migrations as $name) { if (!isset($this->migration_state[$name]) || @@ -161,6 +208,10 @@ class migrator return; } } + else + { + $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); + } } } @@ -175,6 +226,7 @@ class migrator { if (!class_exists($name)) { + $this->output_handler->write(array('MIGRATION_NOT_VALID', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); return false; } @@ -191,6 +243,11 @@ class migrator 'migration_end_time' => 0, ); + if (!empty($state['migration_depends_on'])) + { + $this->output_handler->write(array('MIGRATION_APPLY_DEPENDENCIES', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); + } + foreach ($state['migration_depends_on'] as $depend) { if ($this->unfulfillable($depend) !== false) @@ -227,6 +284,8 @@ class migrator ); $this->last_run_migration['effectively_installed'] = true; + + $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); } else { @@ -238,28 +297,48 @@ class migrator if (!$state['migration_schema_done']) { + $this->output_handler->write(array('MIGRATION_SCHEMA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); + $this->last_run_migration['task'] = 'process_schema_step'; + $elapsed_time = microtime(true); $steps = $this->helper->get_schema_steps($migration->update_schema()); $result = $this->process_data_step($steps, $state['migration_data_state']); + $elapsed_time = microtime(true) - $elapsed_time; $state['migration_data_state'] = ($result === true) ? '' : $result; $state['migration_schema_done'] = ($result === true); + + $this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL); } else if (!$state['migration_data_done']) { try { + $this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); + $this->last_run_migration['task'] = 'process_data_step'; + + $elapsed_time = microtime(true); $result = $this->process_data_step($migration->update_data(), $state['migration_data_state']); + $elapsed_time = microtime(true) - $elapsed_time; $state['migration_data_state'] = ($result === true) ? '' : $result; $state['migration_data_done'] = ($result === true); $state['migration_end_time'] = ($result === true) ? time() : 0; + + if ($state['migration_schema_done']) + { + $this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL); + } + else + { + $this->output_handler->write(array('MIGRATION_DATA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE); + } } catch (\phpbb\db\migration\exception $e) { // Revert the schema changes - $this->revert($name); + $this->revert_do($name); // Rethrow exception throw $e; @@ -279,10 +358,22 @@ class migrator * check if revert() needs to be called again use the migration_state() method. * * @param string $migration String migration name to revert (including any that depend on this migration) - * @return null */ public function revert($migration) { + $this->container->get('dispatcher')->disable(); + $this->revert_do($migration); + $this->container->get('dispatcher')->enable(); + } + + /** + * Effectively runs a single revert step from the last migration installed + * + * @param string $migration String migration name to revert (including any that depend on this migration) + * @return null + */ + protected function revert_do($migration) + { if (!isset($this->migration_state[$migration])) { // Not installed @@ -293,7 +384,7 @@ class migrator { if (!empty($state['migration_depends_on']) && in_array($migration, $state['migration_depends_on'])) { - $this->revert($name); + $this->revert_do($name); } } @@ -602,7 +693,7 @@ class migrator */ public function unfulfillable($name) { - if (isset($this->migration_state[$name])) + if (isset($this->migration_state[$name]) || isset($this->fulfillable_migrations[$name])) { return false; } @@ -623,6 +714,7 @@ class migrator return $unfulfillable; } } + $this->fulfillable_migrations[$name] = true; return false; } @@ -683,7 +775,14 @@ class migrator */ protected function get_migration($name) { - return new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); + $migration = new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); + + if ($migration instanceof ContainerAwareInterface) + { + $migration->setContainer($this->container); + } + + return $migration; } /** diff --git a/phpBB/phpbb/db/migrator_output_handler_interface.php b/phpBB/phpbb/db/migrator_output_handler_interface.php new file mode 100644 index 0000000000..a923af99f6 --- /dev/null +++ b/phpBB/phpbb/db/migrator_output_handler_interface.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db; + +interface migrator_output_handler_interface +{ + const VERBOSITY_QUIET = 0; + const VERBOSITY_NORMAL = 1; + const VERBOSITY_VERBOSE = 2; + const VERBOSITY_VERY_VERBOSE = 3; + const VERBOSITY_DEBUG = 4; + + /** + * Write output using the configured closure. + * + * @param string|array $message The message to write or an array containing the language key and all of its parameters. + * @param int $verbosity The verbosity of the message. + */ + public function write($message, $verbosity); +} diff --git a/phpBB/phpbb/db/null_migrator_output_handler.php b/phpBB/phpbb/db/null_migrator_output_handler.php new file mode 100644 index 0000000000..0e8cfbb049 --- /dev/null +++ b/phpBB/phpbb/db/null_migrator_output_handler.php @@ -0,0 +1,24 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db; + +class null_migrator_output_handler implements migrator_output_handler_interface +{ + /** + * {@inheritdoc} + */ + public function write($message, $verbosity) + { + } +} diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php index 3567570137..775deccc30 100644 --- a/phpBB/phpbb/db/tools.php +++ b/phpBB/phpbb/db/tools.php @@ -1512,7 +1512,7 @@ class tools $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' "; } - if (!is_null($column_data[1])) + if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment')) { $sql .= 'NOT NULL'; } @@ -1574,7 +1574,15 @@ class tools } else { - $default_val = "'" . $column_data[1] . "'"; + // Integers need to have 0 instead of empty string as default + if (strpos($column_type, 'INT') === 0) + { + $default_val = '0'; + } + else + { + $default_val = "'" . $column_data[1] . "'"; + } $return_array['null'] = 'NULL'; $sql .= 'NULL '; } @@ -2175,7 +2183,7 @@ class tools } // no break case 'mysql_41': - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . '(' . implode(', ', $column) . ')'; + $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . ' (' . implode(', ', $column) . ')'; break; case 'mssql': @@ -2643,7 +2651,7 @@ class tools AND cols.id = ix.id WHERE ix.id = object_id('{$table_name}') AND cols.name = '{$column_name}' - AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique) ? '1' : '0'; + AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0'); } else { @@ -2657,7 +2665,7 @@ class tools AND cols.object_id = ix.object_id WHERE ix.object_id = object_id('{$table_name}') AND cols.name = '{$column_name}' - AND ix.is_unique = " . ($unique) ? '1' : '0'; + AND ix.is_unique = " . ($unique ? '1' : '0'); } break; diff --git a/phpBB/phpbb/di/extension/config.php b/phpBB/phpbb/di/extension/config.php index 27ebc94bae..7984a783df 100644 --- a/phpBB/phpbb/di/extension/config.php +++ b/phpBB/phpbb/di/extension/config.php @@ -39,16 +39,24 @@ class config extends Extension */ public function load(array $config, ContainerBuilder $container) { - $container->setParameter('core.adm_relative_path', ($this->config_php->get('phpbb_adm_relative_path') ? $this->config_php->get('phpbb_adm_relative_path') : 'adm/')); - $container->setParameter('core.table_prefix', $this->config_php->get('table_prefix')); - $container->setParameter('cache.driver.class', $this->convert_30_acm_type($this->config_php->get('acm_type'))); - $container->setParameter('dbal.driver.class', $this->config_php->convert_30_dbms_to_31($this->config_php->get('dbms'))); - $container->setParameter('dbal.dbhost', $this->config_php->get('dbhost')); - $container->setParameter('dbal.dbuser', $this->config_php->get('dbuser')); - $container->setParameter('dbal.dbpasswd', $this->config_php->get('dbpasswd')); - $container->setParameter('dbal.dbname', $this->config_php->get('dbname')); - $container->setParameter('dbal.dbport', $this->config_php->get('dbport')); - $container->setParameter('dbal.new_link', defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK); + $parameters = array( + 'core.adm_relative_path' => $this->config_php->get('phpbb_adm_relative_path') ? $this->config_php->get('phpbb_adm_relative_path') : 'adm/', + 'core.table_prefix' => $this->config_php->get('table_prefix'), + 'cache.driver.class' => $this->convert_30_acm_type($this->config_php->get('acm_type')), + 'dbal.driver.class' => $this->config_php->convert_30_dbms_to_31($this->config_php->get('dbms')), + 'dbal.dbhost' => $this->config_php->get('dbhost'), + 'dbal.dbuser' => $this->config_php->get('dbuser'), + 'dbal.dbpasswd' => $this->config_php->get('dbpasswd'), + 'dbal.dbname' => $this->config_php->get('dbname'), + 'dbal.dbport' => $this->config_php->get('dbport'), + 'dbal.new_link' => defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK, + ); + $parameter_bag = $container->getParameterBag(); + + foreach ($parameters as $parameter => $value) + { + $container->setParameter($parameter, $parameter_bag->escapeValue($value)); + } } /** diff --git a/phpBB/phpbb/error_collector.php b/phpBB/phpbb/error_collector.php index 7141f83174..bf8efd1065 100644 --- a/phpBB/phpbb/error_collector.php +++ b/phpBB/phpbb/error_collector.php @@ -16,15 +16,28 @@ namespace phpbb; class error_collector { var $errors; + var $error_types; - function __construct() + /** + * Constructor. + * + * The variable $error_types may be set to a mask of PHP error types that + * the collector should keep, e.g. `E_ALL`. If unset, the current value of + * the error_reporting() function will be used to determine which errors + * the collector will keep. + * + * @see PHPBB3-13306 + * @param int|null $error_types + */ + function __construct($error_types = null) { $this->errors = array(); + $this->error_types = $error_types; } function install() { - set_error_handler(array(&$this, 'error_handler')); + set_error_handler(array(&$this, 'error_handler'), ($this->error_types !== null) ? $this->error_types : error_reporting()); } function uninstall() diff --git a/phpBB/phpbb/event/dispatcher.php b/phpBB/phpbb/event/dispatcher.php index 9a786022c2..1c4abeb108 100644 --- a/phpBB/phpbb/event/dispatcher.php +++ b/phpBB/phpbb/event/dispatcher.php @@ -14,6 +14,7 @@ namespace phpbb\event; use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; +use Symfony\Component\EventDispatcher\Event; /** * Extension of the Symfony2 EventDispatcher @@ -32,6 +33,11 @@ use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; class dispatcher extends ContainerAwareEventDispatcher implements dispatcher_interface { /** + * @var bool + */ + protected $disabled = false; + + /** * {@inheritdoc} */ public function trigger_event($eventName, $data = array()) @@ -40,4 +46,33 @@ class dispatcher extends ContainerAwareEventDispatcher implements dispatcher_int $this->dispatch($eventName, $event); return $event->get_data_filtered(array_keys($data)); } + + /** + * {@inheritdoc} + */ + public function dispatch($eventName, Event $event = null) + { + if ($this->disabled) + { + return $event; + } + + return parent::dispatch($eventName, $event); + } + + /** + * {@inheritdoc} + */ + public function disable() + { + $this->disabled = true; + } + + /** + * {@inheritdoc} + */ + public function enable() + { + $this->disabled = false; + } } diff --git a/phpBB/phpbb/event/dispatcher_interface.php b/phpBB/phpbb/event/dispatcher_interface.php index 50a3ef9101..c66aa98260 100644 --- a/phpBB/phpbb/event/dispatcher_interface.php +++ b/phpBB/phpbb/event/dispatcher_interface.php @@ -37,4 +37,14 @@ interface dispatcher_interface extends \Symfony\Component\EventDispatcher\EventD * @return mixed */ public function trigger_event($eventName, $data = array()); + + /** + * Disable the event dispatcher. + */ + public function disable(); + + /** + * Enable the event dispatcher. + */ + public function enable(); } diff --git a/phpBB/phpbb/event/kernel_exception_subscriber.php b/phpBB/phpbb/event/kernel_exception_subscriber.php index 44e87507f9..eb7831ad34 100644 --- a/phpBB/phpbb/event/kernel_exception_subscriber.php +++ b/phpBB/phpbb/event/kernel_exception_subscriber.php @@ -14,9 +14,10 @@ namespace phpbb\event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; -use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpFoundation\Response; class kernel_exception_subscriber implements EventSubscriberInterface @@ -53,23 +54,55 @@ class kernel_exception_subscriber implements EventSubscriberInterface */ public function on_kernel_exception(GetResponseForExceptionEvent $event) { - page_header($this->user->lang('INFORMATION')); - $exception = $event->getException(); - $this->template->assign_vars(array( - 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'), - 'MESSAGE_TEXT' => $exception->getMessage(), - )); + $message = $exception->getMessage(); + + if ($exception instanceof \phpbb\exception\exception_interface) + { + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($message), $exception->get_parameters())); + } + + if (!$event->getRequest()->isXmlHttpRequest()) + { + page_header($this->user->lang('INFORMATION')); + + $this->template->assign_vars(array( + 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'), + 'MESSAGE_TEXT' => $message, + )); + + $this->template->set_filenames(array( + 'body' => 'message_body.html', + )); + + page_footer(true, false, false); + + $response = new Response($this->template->assign_display('body'), 500); + } + else + { + $data = array(); + + if (!empty($message)) + { + $data['message'] = $message; + } + + if (defined('DEBUG')) + { + $data['trace'] = $exception->getTrace(); + } - $this->template->set_filenames(array( - 'body' => 'message_body.html', - )); + $response = new JsonResponse($data, 500); + } - page_footer(true, false, false); + if ($exception instanceof HttpExceptionInterface) + { + $response->setStatusCode($exception->getStatusCode()); + $response->headers->add($exception->getHeaders()); + } - $status_code = $exception instanceof HttpException ? $exception->getStatusCode() : 500; - $response = new Response($this->template->assign_display('body'), $status_code); $event->setResponse($response); } diff --git a/phpBB/phpbb/event/kernel_terminate_subscriber.php b/phpBB/phpbb/event/kernel_terminate_subscriber.php index 57e4840380..3a709f73fd 100644 --- a/phpBB/phpbb/event/kernel_terminate_subscriber.php +++ b/phpBB/phpbb/event/kernel_terminate_subscriber.php @@ -35,7 +35,7 @@ class kernel_terminate_subscriber implements EventSubscriberInterface public static function getSubscribedEvents() { return array( - KernelEvents::TERMINATE => 'on_kernel_terminate', + KernelEvents::TERMINATE => array('on_kernel_terminate', ~PHP_INT_MAX), ); } } diff --git a/phpBB/phpbb/event/php_exporter.php b/phpBB/phpbb/event/php_exporter.php index badbbb48fd..35144eeeec 100644 --- a/phpBB/phpbb/event/php_exporter.php +++ b/phpBB/phpbb/event/php_exporter.php @@ -253,7 +253,7 @@ class php_exporter public function get_event_name($event_line, $is_dispatch) { $event_text_line = $this->file_lines[$event_line]; - $event_text_line = ltrim($event_text_line, "\t"); + $event_text_line = ltrim($event_text_line, "\t "); if ($is_dispatch) { @@ -389,7 +389,7 @@ class php_exporter $found_comment_end = false; while (ltrim($this->file_lines[$this->current_event_line - $current_doc_line], "\t") !== '/**') { - if (ltrim($this->file_lines[$this->current_event_line - $current_doc_line], "\t") === '*/') + if (ltrim($this->file_lines[$this->current_event_line - $current_doc_line], "\t ") === '*/') { $found_comment_end = true; } @@ -471,7 +471,7 @@ class php_exporter { $find_tag_line = 0; $found_comment_end = false; - while (strpos(ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t"), '* @' . $find_tag . ' ') !== 0) + while (strpos(ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t "), '* @' . $find_tag . ' ') !== 0) { if ($found_comment_end && ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t") === '/**') { @@ -482,7 +482,7 @@ class php_exporter foreach ($disallowed_tags as $disallowed_tag) { - if ($found_comment_end && strpos(ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t"), '* @' . $disallowed_tag) === 0) + if ($found_comment_end && strpos(ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t "), '* @' . $disallowed_tag) === 0) { // Found @var after the @since throw new \LogicException("Found '@{$disallowed_tag}' information after '@{$find_tag}' for event " @@ -490,7 +490,7 @@ class php_exporter } } - if (ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t") === '*/') + if (ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t ") === '*/') { $found_comment_end = true; } @@ -550,7 +550,7 @@ class php_exporter public function validate_since($line) { $match = array(); - preg_match('#^\* @since (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)$#', ltrim($line, "\t"), $match); + preg_match('#^\* @since (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)$#', ltrim($line, "\t "), $match); if (!isset($match[1])) { throw new \LogicException("Invalid '@since' information for event " @@ -570,7 +570,7 @@ class php_exporter */ public function validate_event($event_name, $line) { - $event = substr(ltrim($line, "\t"), strlen('* @event ')); + $event = substr(ltrim($line, "\t "), strlen('* @event ')); if ($event !== trim($event)) { diff --git a/phpBB/phpbb/exception/exception_interface.php b/phpBB/phpbb/exception/exception_interface.php new file mode 100644 index 0000000000..e8526a35f5 --- /dev/null +++ b/phpBB/phpbb/exception/exception_interface.php @@ -0,0 +1,29 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\exception; + +/** + * Interface exception_interface + * + * Define an exception which support a language var as message. + */ +interface exception_interface +{ + /** + * Return the arguments associated with the message if it's a language var. + * + * @return array + */ + public function get_parameters(); +} diff --git a/phpBB/phpbb/exception/http_exception.php b/phpBB/phpbb/exception/http_exception.php new file mode 100644 index 0000000000..0e6ffe4f59 --- /dev/null +++ b/phpBB/phpbb/exception/http_exception.php @@ -0,0 +1,70 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\exception; + +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; + +/** + * Class http_exception + */ +class http_exception extends runtime_exception implements HttpExceptionInterface +{ + /** + * Http status code. + * + * @var integer + */ + private $status_code; + + /** + * Additional headers to set in the response. + * + * @var array + */ + private $headers; + + /** + * Constructor + * + * @param integer $status_code The http status code. + * @param string $message The Exception message to throw (must be a language variable). + * @param array $parameters The parameters to use with the language var. + * @param \Exception $previous The previous exception used for the exception chaining. + * @param array $headers Additional headers to set in the response. + * @param integer $code The Exception code. + */ + public function __construct($status_code, $message = "", array $parameters = array(), \Exception $previous = null, array $headers = array(), $code = 0) + { + $this->status_code = $status_code; + $this->headers = $headers; + + parent::__construct($message, $parameters, $previous, $code); + } + + /** + * {@inheritdoc} + */ + public function getStatusCode() + { + return $this->status_code; + } + + /** + * {@inheritdoc} + */ + public function getHeaders() + { + return $this->headers; + } +} diff --git a/phpBB/phpbb/exception/runtime_exception.php b/phpBB/phpbb/exception/runtime_exception.php new file mode 100644 index 0000000000..6568bbf86f --- /dev/null +++ b/phpBB/phpbb/exception/runtime_exception.php @@ -0,0 +1,52 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\exception; + +/** + * Class runtime_exception + * + * Define an exception which support a language var as message. + */ +class runtime_exception extends \RuntimeException implements exception_interface +{ + /** + * Parameters to use with the language var. + * + * @var array + */ + private $parameters; + + /** + * Constructor + * + * @param string $message The Exception message to throw (must be a language variable). + * @param array $parameters The parameters to use with the language var. + * @param \Exception $previous The previous runtime_exception used for the runtime_exception chaining. + * @param integer $code The Exception code. + */ + public function __construct($message = "", array $parameters = array(), \Exception $previous = null, $code = 0) + { + $this->parameters = $parameters; + + parent::__construct($message, $code, $previous); + } + + /** + * {@inheritdoc} + */ + public function get_parameters() + { + return $this->parameters; + } +} diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php index edca8ee1af..a64d88fe39 100644 --- a/phpBB/phpbb/extension/metadata_manager.php +++ b/phpBB/phpbb/extension/metadata_manager.php @@ -177,6 +177,7 @@ class metadata_manager throw new \phpbb\extension\exception($this->user->lang('FILE_JSON_DECODE_ERR', $this->metadata_file)); } + array_walk_recursive($metadata, array($this, 'sanitize_json')); $this->metadata = $metadata; return true; @@ -184,6 +185,17 @@ class metadata_manager } /** + * Sanitize input from JSON array using htmlspecialchars() + * + * @param mixed $value Value of array row + * @param string $key Key of array row + */ + public function sanitize_json(&$value, $key) + { + $value = htmlspecialchars($value); + } + + /** * This array handles the cleaning of the array * * @return array Contains the cleaned metadata array @@ -337,30 +349,30 @@ class metadata_manager public function output_template_data() { $this->template->assign_vars(array( - 'META_NAME' => htmlspecialchars($this->metadata['name']), - 'META_TYPE' => htmlspecialchars($this->metadata['type']), - 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? htmlspecialchars($this->metadata['description']) : '', + 'META_NAME' => $this->metadata['name'], + 'META_TYPE' => $this->metadata['type'], + 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? $this->metadata['description'] : '', 'META_HOMEPAGE' => (isset($this->metadata['homepage'])) ? $this->metadata['homepage'] : '', - 'META_VERSION' => (isset($this->metadata['version'])) ? htmlspecialchars($this->metadata['version']) : '', - 'META_TIME' => (isset($this->metadata['time'])) ? htmlspecialchars($this->metadata['time']) : '', - 'META_LICENSE' => htmlspecialchars($this->metadata['license']), + 'META_VERSION' => (isset($this->metadata['version'])) ? $this->metadata['version'] : '', + 'META_TIME' => (isset($this->metadata['time'])) ? $this->metadata['time'] : '', + 'META_LICENSE' => $this->metadata['license'], - 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? htmlspecialchars($this->metadata['require']['php']) : '', + 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? $this->metadata['require']['php'] : '', 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(), - 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? htmlspecialchars($this->metadata['extra']['soft-require']['phpbb/phpbb']) : '', + 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? $this->metadata['extra']['soft-require']['phpbb/phpbb'] : '', 'META_REQUIRE_PHPBB_FAIL' => !$this->validate_require_phpbb(), - 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? htmlspecialchars($this->metadata['extra']['display-name']) : '', + 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '', )); foreach ($this->metadata['authors'] as $author) { $this->template->assign_block_vars('meta_authors', array( - 'AUTHOR_NAME' => htmlspecialchars($author['name']), + 'AUTHOR_NAME' => $author['name'], 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '', 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '', - 'AUTHOR_ROLE' => (isset($author['role'])) ? htmlspecialchars($author['role']) : '', + 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '', )); } } diff --git a/phpBB/phpbb/feed/base.php b/phpBB/phpbb/feed/base.php index e31854160a..322e2ee9f1 100644 --- a/phpBB/phpbb/feed/base.php +++ b/phpBB/phpbb/feed/base.php @@ -67,6 +67,9 @@ abstract class base */ var $separator_stats = "\xE2\x80\x94"; // — + /** @var mixed Query result handle */ + protected $result; + /** * Constructor * @@ -229,9 +232,7 @@ abstract class base function get_item() { - static $result; - - if (!isset($result)) + if (!isset($this->result)) { if (!$this->get_sql()) { @@ -240,10 +241,10 @@ abstract class base // Query database $sql = $this->db->sql_build_query('SELECT', $this->sql); - $result = $this->db->sql_query_limit($sql, $this->num_items); + $this->result = $this->db->sql_query_limit($sql, $this->num_items); } - return $this->db->sql_fetchrow($result); + return $this->db->sql_fetchrow($this->result); } function user_viewprofile($row) diff --git a/phpBB/phpbb/file_downloader.php b/phpBB/phpbb/file_downloader.php new file mode 100644 index 0000000000..462b87ca51 --- /dev/null +++ b/phpBB/phpbb/file_downloader.php @@ -0,0 +1,120 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb; + +class file_downloader +{ + /** @var string Error string */ + protected $error_string = ''; + + /** @var int Error number */ + protected $error_number = 0; + + /** + * Retrieve contents from remotely stored file + * + * @param string $host File host + * @param string $directory Directory file is in + * @param string $filename Filename of file to retrieve + * @param int $port Port to connect to; default: 80 + * @param int $timeout Connection timeout in seconds; default: 6 + * + * @return mixed File data as string if file can be read and there is no + * timeout, false if there were errors or the connection timed out + * + * @throws \phpbb\exception\runtime_exception If data can't be retrieved and no error + * message is returned + */ + public function get($host, $directory, $filename, $port = 80, $timeout = 6) + { + // Set default values for error variables + $this->error_number = 0; + $this->error_string = ''; + + if ($socket = @fsockopen($host, $port, $this->error_number, $this->error_string, $timeout)) + { + @fputs($socket, "GET $directory/$filename HTTP/1.0\r\n"); + @fputs($socket, "HOST: $host\r\n"); + @fputs($socket, "Connection: close\r\n\r\n"); + + $timer_stop = time() + $timeout; + stream_set_timeout($socket, $timeout); + + $file_info = ''; + $get_info = false; + + while (!@feof($socket)) + { + if ($get_info) + { + $file_info .= @fread($socket, 1024); + } + else + { + $line = @fgets($socket, 1024); + if ($line == "\r\n") + { + $get_info = true; + } + else if (stripos($line, '404 not found') !== false) + { + throw new \phpbb\exception\runtime_exception('FILE_NOT_FOUND', array($filename)); + } + } + + $stream_meta_data = stream_get_meta_data($socket); + + if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop) + { + throw new \phpbb\exception\runtime_exception('FSOCK_TIMEOUT'); + } + } + @fclose($socket); + } + else + { + if ($this->error_string) + { + $this->error_string = utf8_convert_message($this->error_string); + return false; + } + else + { + throw new \phpbb\exception\runtime_exception('FSOCK_DISABLED'); + } + } + + return $file_info; + } + + /** + * Get error string + * + * @return string Error string + */ + public function get_error_string() + { + return $this->error_string; + } + + /** + * Get error number + * + * @return int Error number + */ + public function get_error_number() + { + return $this->error_number; + } +} diff --git a/phpBB/phpbb/log/log.php b/phpBB/phpbb/log/log.php index 2af8b50b54..0c5205530b 100644 --- a/phpBB/phpbb/log/log.php +++ b/phpBB/phpbb/log/log.php @@ -708,6 +708,50 @@ class log implements \phpbb\log\log_interface } } + /** + * Allow modifying or execute extra final filter on log entries + * + * @event core.get_logs_after + * @var array log Array with all our log entries + * @var array topic_id_list Array of topic ids, for which we + * get the permission data + * @var array reportee_id_list Array of additional user IDs we + * get the username strings for + * @var string mode Mode of the entries we display + * @var bool count_logs Do we count all matching entries? + * @var int limit Limit the number of entries + * @var int offset Offset when fetching the entries + * @var mixed forum_id Limit entries to the forum_id, + * can also be an array of forum_ids + * @var int topic_id Limit entries to the topic_id + * @var int user_id Limit entries to the user_id + * @var int log_time Limit maximum age of log entries + * @var string sort_by SQL order option + * @var string keywords Will only return entries that have the + * keywords in log_operation or log_data + * @var string profile_url URL to the users profile + * @var int log_type The type of logs it was filtered + * @since 3.1.3-RC1 + */ + $vars = array( + 'log', + 'topic_id_list', + 'reportee_id_list', + 'mode', + 'count_logs', + 'limit', + 'offset', + 'forum_id', + 'topic_id', + 'user_id', + 'log_time', + 'sort_by', + 'keywords', + 'profile_url', + 'log_type', + ); + extract($this->dispatcher->trigger_event('core.get_logs_after', compact($vars))); + return $log; } diff --git a/phpBB/phpbb/message/admin_form.php b/phpBB/phpbb/message/admin_form.php index 93db59880c..96b8d3499e 100644 --- a/phpBB/phpbb/message/admin_form.php +++ b/phpBB/phpbb/message/admin_form.php @@ -178,6 +178,7 @@ class admin_form extends form 'S_CONTACT_ADMIN' => true, 'S_CONTACT_FORM' => $this->config['contact_admin_form_enable'], 'S_IS_REGISTERED' => $this->user->data['is_registered'], + 'S_POST_ACTION' => append_sid($this->phpbb_root_path . 'memberlist.' . $this->phpEx, 'mode=contactadmin'), 'CONTACT_INFO' => $l_admin_info, 'MESSAGE' => $this->body, diff --git a/phpBB/phpbb/message/form.php b/phpBB/phpbb/message/form.php index 076b41dc07..21d4de0b4d 100644 --- a/phpBB/phpbb/message/form.php +++ b/phpBB/phpbb/message/form.php @@ -146,7 +146,7 @@ abstract class form WHERE user_id = ' . $this->user->data['user_id']; $this->db->sql_query($sql); - if ($this->cc_sender) + if ($this->cc_sender && $this->user->data['is_registered']) { $this->message->cc_sender(); } diff --git a/phpBB/phpbb/message/topic_form.php b/phpBB/phpbb/message/topic_form.php index 1e0f2a1945..174643bb81 100644 --- a/phpBB/phpbb/message/topic_form.php +++ b/phpBB/phpbb/message/topic_form.php @@ -117,7 +117,7 @@ class topic_form extends form 'TOPIC_NAME' => htmlspecialchars_decode($this->topic_row['topic_title']), 'U_TOPIC' => generate_board_url() . '/viewtopic.' . $this->phpEx . '?f=' . $this->topic_row['forum_id'] . '&t=' . $this->topic_id, )); - + $this->message->set_body($this->body); $this->message->add_recipient( $this->recipient_name, $this->recipient_address, diff --git a/phpBB/phpbb/notification/manager.php b/phpBB/phpbb/notification/manager.php index 81b450ebbd..db92170dd8 100644 --- a/phpBB/phpbb/notification/manager.php +++ b/phpBB/phpbb/notification/manager.php @@ -24,6 +24,9 @@ class manager protected $notification_types; /** @var array */ + protected $subscription_types; + + /** @var array */ protected $notification_methods; /** @var ContainerInterface */ @@ -35,6 +38,9 @@ class manager /** @var \phpbb\config\config */ protected $config; + /** @var \phpbb\event\dispatcher_interface */ + protected $phpbb_dispatcher; + /** @var \phpbb\db\driver\driver_interface */ protected $db; @@ -67,6 +73,7 @@ class manager * @param ContainerInterface $phpbb_container * @param \phpbb\user_loader $user_loader * @param \phpbb\config\config $config + * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\cache\service $cache * @param \phpbb\user $user @@ -78,7 +85,7 @@ class manager * * @return \phpbb\notification\manager */ - public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table) + public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table) { $this->notification_types = $notification_types; $this->notification_methods = $notification_methods; @@ -86,6 +93,7 @@ class manager $this->user_loader = $user_loader; $this->config = $config; + $this->phpbb_dispatcher = $phpbb_dispatcher; $this->db = $db; $this->cache = $cache; $this->user = $user; @@ -289,7 +297,7 @@ class manager WHERE notification_time <= " . (int) $time . (($notification_type_name !== false) ? ' AND ' . (is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name)) : '') . - (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id) : 'item_parent_id = ' . (int) $item_parent_id) : '') . + (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id, false, true) : 'item_parent_id = ' . (int) $item_parent_id) : '') . (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : ''); $this->db->sql_query($sql); } @@ -347,6 +355,26 @@ class manager // find out which users want to receive this type of notification $notify_users = $this->get_item_type_class($notification_type_name)->find_users_for_notification($data, $options); + /** + * Allow filtering the notify_users array for a notification that is about to be sent. + * Here, $notify_users is already filtered by f_read and the ignored list included in the options variable + * + * @event core.notification_manager_add_notifications + * @var string notification_type_name The forum id from where the topic belongs + * @var array data Data specific for the notification_type_name used will be inserted + * @var array notify_users The array of userid that are going to be notified for this notification. Set to array() to cancel. + * @var array options The options that were used when this method was called (read only) + * + * @since 3.1.3-RC1 + */ + $vars = array( + 'notification_type_name', + 'data', + 'notify_users', + 'options', + ); + extract($this->phpbb_dispatcher->trigger_event('core.notification_manager_add_notifications', compact($vars))); + $this->add_notifications_for_users($notification_type_name, $data, $notify_users); return $notify_users; @@ -524,33 +552,36 @@ class manager */ public function get_subscription_types() { - $subscription_types = array(); - - foreach ($this->notification_types as $type_name => $data) + if ($this->subscription_types === null) { - $type = $this->get_item_type_class($type_name); + $this->subscription_types = array(); - if ($type instanceof \phpbb\notification\type\type_interface && $type->is_available()) + foreach ($this->notification_types as $type_name => $data) { - $options = array_merge(array( - 'id' => $type->get_type(), - 'lang' => 'NOTIFICATION_TYPE_' . strtoupper($type->get_type()), - 'group' => 'NOTIFICATION_GROUP_MISCELLANEOUS', - ), (($type::$notification_option !== false) ? $type::$notification_option : array())); + $type = $this->get_item_type_class($type_name); - $subscription_types[$options['group']][$options['id']] = $options; + if ($type instanceof \phpbb\notification\type\type_interface && $type->is_available()) + { + $options = array_merge(array( + 'id' => $type->get_type(), + 'lang' => 'NOTIFICATION_TYPE_' . strtoupper($type->get_type()), + 'group' => 'NOTIFICATION_GROUP_MISCELLANEOUS', + ), (($type::$notification_option !== false) ? $type::$notification_option : array())); + + $this->subscription_types[$options['group']][$options['id']] = $options; + } } - } - // Move Miscellaneous to the very last section - if (isset($subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'])) - { - $miscellaneous = $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']; - unset($subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']); - $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'] = $miscellaneous; + // Move Miscellaneous to the very last section + if (isset($this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'])) + { + $miscellaneous = $this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']; + unset($this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']); + $this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'] = $miscellaneous; + } } - return $subscription_types; + return $this->subscription_types; } /** diff --git a/phpBB/phpbb/notification/type/admin_activate_user.php b/phpBB/phpbb/notification/type/admin_activate_user.php index 038ca3726e..dfc0157558 100644 --- a/phpBB/phpbb/notification/type/admin_activate_user.php +++ b/phpBB/phpbb/notification/type/admin_activate_user.php @@ -131,7 +131,7 @@ class admin_activate_user extends \phpbb\notification\type\base public function get_email_template_variables() { $board_url = generate_board_url(); - $username = $this->user_loader->get_username($this->item_id, 'no_profile'); + $username = $this->user_loader->get_username($this->item_id, 'username'); return array( 'USERNAME' => htmlspecialchars_decode($username), diff --git a/phpBB/phpbb/notification/type/post.php b/phpBB/phpbb/notification/type/post.php index d9e74f2e95..421eff6372 100644 --- a/phpBB/phpbb/notification/type/post.php +++ b/phpBB/phpbb/notification/type/post.php @@ -357,6 +357,7 @@ class post extends \phpbb\notification\type\base { $tracking_data[$row['user_id']] = $row['mark_time']; } + $this->db->sql_freeresult($result); return $tracking_data; } diff --git a/phpBB/phpbb/notification/type/topic.php b/phpBB/phpbb/notification/type/topic.php index cf0ec77099..5f57087b73 100644 --- a/phpBB/phpbb/notification/type/topic.php +++ b/phpBB/phpbb/notification/type/topic.php @@ -257,6 +257,7 @@ class topic extends \phpbb\notification\type\base { $tracking_data[$row['user_id']] = $row['mark_time']; } + $this->db->sql_freeresult($result); return $tracking_data; } diff --git a/phpBB/phpbb/pagination.php b/phpBB/phpbb/pagination.php index 8aba41d651..7a81c25ad2 100644 --- a/phpBB/phpbb/pagination.php +++ b/phpBB/phpbb/pagination.php @@ -21,18 +21,26 @@ class pagination /** @var \phpbb\user */ protected $user; + /** @var \phpbb\controller\helper */ + protected $helper; + + /** @var \phpbb\event\dispatcher_interface */ + protected $phpbb_dispatcher; + /** * Constructor * - * @param \phpbb\template\template $template - * @param \phpbb\user $user - * @param \phpbb\controller\helper $helper + * @param \phpbb\template\template $template + * @param \phpbb\user $user + * @param \phpbb\controller\helper $helper + * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher */ - public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\controller\helper $helper) + public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\controller\helper $helper, \phpbb\event\dispatcher_interface $phpbb_dispatcher) { $this->template = $template; $this->user = $user; $this->helper = $helper; + $this->phpbb_dispatcher = $phpbb_dispatcher; } /** @@ -50,6 +58,36 @@ class pagination */ protected function generate_page_link($base_url, $on_page, $start_name, $per_page) { + // A listener can set this variable to the new pagination URL + // to override the generate_page_link() function generated value + $generate_page_link_override = false; + + /** + * Execute code and/or override generate_page_link() + * + * To override the generate_page_link() function generated value + * set $generate_page_link_override to the new URL value + * + * @event core.pagination_generate_page_link + * @var string base_url is url prepended to all links generated within the function + * If you use page numbers inside your controller route, base_url should contains a placeholder (%d) + * for the page. Also be sure to specify the pagination path information into the start_name argument + * @var string on_page is the page for which we want to generate the link + * @var string start_name is the name of the parameter containing the first item of the given page (example: start=20) + * If you use page numbers inside your controller route, start name should be the string + * that should be removed for the first page (example: /page/%d) + * @var int per_page the number of items, posts, etc. to display per page, used to determine the number of pages to produce + * @var bool|string generate_page_link_override Shall we return custom pagination link (string URL) or not (false) + * @since 3.1.0-RC5 + */ + $vars = array('base_url', 'on_page', 'start_name', 'per_page', 'generate_page_link_override'); + extract($this->phpbb_dispatcher->trigger_event('core.pagination_generate_page_link', compact($vars))); + + if ($generate_page_link_override) + { + return $generate_page_link_override; + } + if (!is_string($base_url)) { if (is_array($base_url['routes'])) diff --git a/phpBB/phpbb/passwords/driver/bcrypt.php b/phpBB/phpbb/passwords/driver/bcrypt.php index 23add37a56..eab1c3d569 100644 --- a/phpBB/phpbb/passwords/driver/bcrypt.php +++ b/phpBB/phpbb/passwords/driver/bcrypt.php @@ -68,7 +68,7 @@ class bcrypt extends base return false; } - if ($hash == $this->hash($password, $salt)) + if ($this->helper->string_compare($hash, $this->hash($password, $salt))) { return true; } diff --git a/phpBB/phpbb/passwords/driver/bcrypt_wcf2.php b/phpBB/phpbb/passwords/driver/bcrypt_wcf2.php index 2d6f897a7b..0eee98d7b7 100644 --- a/phpBB/phpbb/passwords/driver/bcrypt_wcf2.php +++ b/phpBB/phpbb/passwords/driver/bcrypt_wcf2.php @@ -78,7 +78,7 @@ class bcrypt_wcf2 extends base return false; } // Works for standard WCF 2.x, i.e. WBB4 and similar - return $hash === $this->bcrypt->hash($this->bcrypt->hash($password, $salt), $salt); + return $this->helper->string_compare($hash, $this->bcrypt->hash($this->bcrypt->hash($password, $salt), $salt)); } } } diff --git a/phpBB/phpbb/passwords/driver/helper.php b/phpBB/phpbb/passwords/driver/helper.php index 2b3ebce53a..caa65080ac 100644 --- a/phpBB/phpbb/passwords/driver/helper.php +++ b/phpBB/phpbb/passwords/driver/helper.php @@ -142,4 +142,24 @@ class helper } return $random; } + + /** + * Compare two strings byte by byte + * + * @param string $string_a The first string + * @param string $string_b The second string + * + * @return bool True if strings are the same, false if not + */ + public function string_compare($string_a, $string_b) + { + $difference = strlen($string_a) != strlen($string_b); + + for ($i = 0; $i < strlen($string_a) && $i < strlen($string_b); $i++) + { + $difference |= $string_a[$i] != $string_b[$i]; + } + + return $difference === 0; + } } diff --git a/phpBB/phpbb/passwords/driver/md5_mybb.php b/phpBB/phpbb/passwords/driver/md5_mybb.php index 61ea8dafd8..f631ceae78 100644 --- a/phpBB/phpbb/passwords/driver/md5_mybb.php +++ b/phpBB/phpbb/passwords/driver/md5_mybb.php @@ -54,7 +54,7 @@ class md5_mybb extends base else { // Works for myBB 1.1.x, 1.2.x, 1.4.x, 1.6.x - return $hash === md5(md5($user_row['user_passwd_salt']) . md5($password)); + return $this->helper->string_compare($hash, md5(md5($user_row['user_passwd_salt']) . md5($password))); } } } diff --git a/phpBB/phpbb/passwords/driver/md5_phpbb2.php b/phpBB/phpbb/passwords/driver/md5_phpbb2.php index 86a4b62ea5..bd8cc51e5a 100644 --- a/phpBB/phpbb/passwords/driver/md5_phpbb2.php +++ b/phpBB/phpbb/passwords/driver/md5_phpbb2.php @@ -23,6 +23,9 @@ class md5_phpbb2 extends base /** @var \phpbb\passwords\driver\salted_md5 */ protected $salted_md5; + /** @var \phpbb\passwords\driver\helper */ + protected $helper; + /** @var string phpBB root path */ protected $phpbb_root_path; @@ -34,13 +37,15 @@ class md5_phpbb2 extends base * * @param \phpbb\request\request $request phpBB request object * @param \phpbb\passwords\driver\salted_md5 $salted_md5 Salted md5 driver + * @param \phpbb\passwords\driver\helper $helper Driver helper * @param string $phpbb_root_path phpBB root path * @param string $php_ext PHP file extension */ - public function __construct($request, \phpbb\passwords\driver\salted_md5 $salted_md5, $phpbb_root_path, $php_ext) + public function __construct($request, salted_md5 $salted_md5, helper $helper, $phpbb_root_path, $php_ext) { $this->request = $request; $this->salted_md5 = $salted_md5; + $this->helper = $helper; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; } @@ -105,7 +110,7 @@ class md5_phpbb2 extends base include($this->phpbb_root_path . 'includes/utf/data/recode_basic.' . $this->php_ext); } - if (md5($password_old_format) === $hash || md5(\utf8_to_cp1252($password_old_format)) === $hash + if ($this->helper->string_compare(md5($password_old_format), $hash) || $this->helper->string_compare(md5(\utf8_to_cp1252($password_old_format)), $hash) || $this->salted_md5->check(md5($password_old_format), $hash) === true || $this->salted_md5->check(md5(\utf8_to_cp1252($password_old_format)), $hash) === true) { diff --git a/phpBB/phpbb/passwords/driver/md5_vb.php b/phpBB/phpbb/passwords/driver/md5_vb.php index c83c32a596..280b7114c7 100644 --- a/phpBB/phpbb/passwords/driver/md5_vb.php +++ b/phpBB/phpbb/passwords/driver/md5_vb.php @@ -54,7 +54,7 @@ class md5_vb extends base else { // Works for vB 3.8.x, 4.x.x, 5.0.x - return $hash === md5(md5($password) . $user_row['user_passwd_salt']); + return $this->helper->string_compare($hash, md5(md5($password) . $user_row['user_passwd_salt'])); } } } diff --git a/phpBB/phpbb/passwords/driver/salted_md5.php b/phpBB/phpbb/passwords/driver/salted_md5.php index 97a2b9154b..81ac010785 100644 --- a/phpBB/phpbb/passwords/driver/salted_md5.php +++ b/phpBB/phpbb/passwords/driver/salted_md5.php @@ -107,7 +107,7 @@ class salted_md5 extends base return md5($password) === $hash; } - return $hash === $this->hash($password, $hash); + return $this->helper->string_compare($hash, $this->hash($password, $hash)); } /** diff --git a/phpBB/phpbb/passwords/driver/sha1.php b/phpBB/phpbb/passwords/driver/sha1.php index 0852fd32fc..1abead42cd 100644 --- a/phpBB/phpbb/passwords/driver/sha1.php +++ b/phpBB/phpbb/passwords/driver/sha1.php @@ -47,6 +47,6 @@ class sha1 extends base */ public function check($password, $hash, $user_row = array()) { - return (strlen($hash) == 40) ? $hash === sha1($password) : false; + return (strlen($hash) == 40) ? $this->helper->string_compare($hash, sha1($password)) : false; } } diff --git a/phpBB/phpbb/passwords/driver/sha1_smf.php b/phpBB/phpbb/passwords/driver/sha1_smf.php index ec64bd6afb..b30d87265e 100644 --- a/phpBB/phpbb/passwords/driver/sha1_smf.php +++ b/phpBB/phpbb/passwords/driver/sha1_smf.php @@ -46,6 +46,6 @@ class sha1_smf extends base */ public function check($password, $hash, $user_row = array()) { - return (strlen($hash) == 40) ? $hash === $this->hash($password, $user_row) : false; + return (strlen($hash) == 40) ? $this->helper->string_compare($hash, $this->hash($password, $user_row)) : false; } } diff --git a/phpBB/phpbb/passwords/driver/sha1_wcf1.php b/phpBB/phpbb/passwords/driver/sha1_wcf1.php index 919fa2bb71..68006486c4 100644 --- a/phpBB/phpbb/passwords/driver/sha1_wcf1.php +++ b/phpBB/phpbb/passwords/driver/sha1_wcf1.php @@ -54,7 +54,7 @@ class sha1_wcf1 extends base else { // Works for standard WCF 1.x, i.e. WBB3 and similar - return $hash === sha1($user_row['user_passwd_salt'] . sha1($user_row['user_passwd_salt'] . sha1($password))); + return $this->helper->string_compare($hash, sha1($user_row['user_passwd_salt'] . sha1($user_row['user_passwd_salt'] . sha1($password)))); } } } diff --git a/phpBB/phpbb/passwords/driver/sha_xf1.php b/phpBB/phpbb/passwords/driver/sha_xf1.php index 7a1ea1450a..9d8f01796e 100644 --- a/phpBB/phpbb/passwords/driver/sha_xf1.php +++ b/phpBB/phpbb/passwords/driver/sha_xf1.php @@ -54,8 +54,8 @@ class sha_xf1 extends base else { // Works for xenforo 1.0, 1.1 - if ($hash === sha1(sha1($password) . $user_row['user_passwd_salt']) - || $hash === hash('sha256', hash('sha256', $password) . $user_row['user_passwd_salt'])) + if ($this->helper->string_compare($hash, sha1(sha1($password) . $user_row['user_passwd_salt'])) + || $this->helper->string_compare($hash, hash('sha256', hash('sha256', $password) . $user_row['user_passwd_salt']))) { return true; } diff --git a/phpBB/phpbb/path_helper.php b/phpBB/phpbb/path_helper.php index 936564d8b6..5400c1c5a6 100644 --- a/phpBB/phpbb/path_helper.php +++ b/phpBB/phpbb/path_helper.php @@ -154,6 +154,7 @@ class path_helper return $this->web_root_path; } + // We do not need to escape $path_info, $request_uri and $script_name because we can not find their content in the result. // Path info (e.g. /foo/bar) $path_info = $this->filesystem->clean_path($this->symfony_request->getPathInfo()); @@ -203,9 +204,12 @@ class path_helper */ if ($this->request->is_ajax() && $this->symfony_request->get('_referer')) { + // We need to escape $absolute_board_url because it can be partially concatenated to the result. + $absolute_board_url = $this->request->escape($this->symfony_request->getSchemeAndHttpHost() . $this->symfony_request->getBasePath(), true); + $referer_web_root_path = $this->get_web_root_path_from_ajax_referer( $this->symfony_request->get('_referer'), - $this->symfony_request->getSchemeAndHttpHost() . $this->symfony_request->getBasePath() + $absolute_board_url ); return $this->web_root_path = $this->phpbb_root_path . $referer_web_root_path; } @@ -278,10 +282,16 @@ class path_helper $referer_dir = dirname($referer_dir); } - while (strpos($absolute_board_url, $referer_dir) !== 0) + while (($dir_position = strpos($absolute_board_url, $referer_dir)) !== 0) { $fixed_root_path .= '../'; $referer_dir = dirname($referer_dir); + + // Just return phpbb_root_path if we reach the top directory + if ($referer_dir === '.') + { + return $this->phpbb_root_path; + } } $fixed_root_path .= substr($absolute_board_url, strlen($referer_dir) + 1); @@ -445,4 +455,38 @@ class path_helper return $url_parts['base'] . (($params) ? '?' . $this->glue_url_params($params) : ''); } + + /** + * Get a valid page + * + * @param string $page The page to verify + * @param bool $mod_rewrite Whether mod_rewrite is enabled, default: false + * + * @return string A valid page based on given page and mod_rewrite + */ + public function get_valid_page($page, $mod_rewrite = false) + { + // We need to be cautious here. + // On some situations, the redirect path is an absolute URL, sometimes a relative path + // For a relative path, let's prefix it with $phpbb_root_path to point to the correct location, + // else we use the URL directly. + $url_parts = parse_url($page); + + // URL + if ($url_parts === false || empty($url_parts['scheme']) || empty($url_parts['host'])) + { + // Remove 'app.php/' from the page, when rewrite is enabled. + // Treat app.php as a reserved file name and remove on mod rewrite + // even if it might not be in the phpBB root. + if ($mod_rewrite && ($app_position = strpos($page, 'app.' . $this->php_ext . '/')) !== false) + { + $page = substr($page, 0, $app_position) . substr($page, $app_position + strlen('app.' . $this->php_ext . '/')); + } + + // Remove preceding slashes from page name and prepend root path + $page = $this->get_phpbb_root_path() . ltrim($page, '/\\'); + } + + return $page; + } } diff --git a/phpBB/phpbb/plupload/plupload.php b/phpBB/phpbb/plupload/plupload.php index 3c686a552f..fcce5b3bd8 100644 --- a/phpBB/phpbb/plupload/plupload.php +++ b/phpBB/phpbb/plupload/plupload.php @@ -326,7 +326,7 @@ class plupload $tmp_file = $this->temporary_filepath($upload['tmp_name']); - if (!move_uploaded_file($upload['tmp_name'], $tmp_file)) + if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file)) { $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED'); } diff --git a/phpBB/phpbb/profilefields/type/type_base.php b/phpBB/phpbb/profilefields/type/type_base.php index c770a0d93c..9b4bada26d 100644 --- a/phpBB/phpbb/profilefields/type/type_base.php +++ b/phpBB/phpbb/profilefields/type/type_base.php @@ -133,7 +133,7 @@ abstract class type_base implements type_interface { foreach ($field_data[$key] as $lang_id => $options) { - $field_data[$key][$lang_id] = explode("\n", $options); + $field_data[$key][$lang_id] = is_array($options) ? $options : explode("\n", $options); } return $current_value; @@ -158,7 +158,19 @@ abstract class type_base implements type_interface } else { - return $this->request->variable($key, '', true); + $default_value = ''; + $lang_fields = array( + 'l_lang_name', + 'l_lang_explain', + 'l_lang_default_value', + 'l_lang_options', + ); + + if (in_array($key, $lang_fields)) + { + $default_value = array(0 => ''); + } + return $this->request->variable($key, $default_value, true); } } diff --git a/phpBB/phpbb/profilefields/type/type_bool.php b/phpBB/phpbb/profilefields/type/type_bool.php index 0582722833..f6f3f17a6c 100644 --- a/phpBB/phpbb/profilefields/type/type_bool.php +++ b/phpBB/phpbb/profilefields/type/type_bool.php @@ -173,7 +173,7 @@ class type_bool extends type_base } else { - return $this->lang_helper->is_set($field_id, $lang_id, $field_value + 1); + return $this->lang_helper->is_set($field_id, $lang_id, $field_value + 1) ? $this->lang_helper->get($field_id, $lang_id, $field_value + 1) : null; } } @@ -352,7 +352,7 @@ class type_bool extends type_base } } - if ($step == 3 && ($field_data[$key] || $action != 'edit') && $key == 'l_lang_options') + if ($key == 'l_lang_options' && $this->request->is_set($key)) { $field_data[$key] = $this->request->variable($key, array(0 => array('')), true); @@ -367,29 +367,29 @@ class type_bool extends type_base */ public function prepare_hidden_fields($step, $key, $action, &$field_data) { - if ($key == 'l_lang_options' && $this->request->is_set('l_lang_options')) + if ($key == 'field_default_value') { - return $this->request->variable($key, array(array('')), true); - } - else if ($key == 'field_default_value') - { - return $this->request->variable($key, $field_data[$key]); - } - else - { - if (!$this->request->is_set($key)) - { - return false; - } - else if ($key == 'field_ident' && isset($field_data[$key])) - { - return $field_data[$key]; - } - else + $field_length = $this->request->variable('field_length', 0); + + // Do a simple is set check if using checkbox. + if ($field_length == 2) { - return ($key == 'lang_options') ? $this->request->variable($key, array(''), true) : $this->request->variable($key, '', true); + return $this->request->is_set($key); } + return $this->request->variable($key, $field_data[$key], true); + } + + $default_lang_options = array( + 'l_lang_options' => array(0 => array('')), + 'lang_options' => array(0 => ''), + ); + + if (isset($default_lang_options[$key]) && $this->request->is_set($key)) + { + return $this->request->variable($key, $default_lang_options[$key], true); } + + return parent::prepare_hidden_fields($step, $key, $action, $field_data); } /** diff --git a/phpBB/phpbb/profilefields/type/type_string_common.php b/phpBB/phpbb/profilefields/type/type_string_common.php index ff33a7b49c..f5e1992044 100644 --- a/phpBB/phpbb/profilefields/type/type_string_common.php +++ b/phpBB/phpbb/profilefields/type/type_string_common.php @@ -18,11 +18,11 @@ abstract class type_string_common extends type_base protected $validation_options = array( 'CHARS_ANY' => '.*', 'NUMBERS_ONLY' => '[0-9]+', - 'ALPHA_ONLY' => '[\w]+', - 'ALPHA_UNDERSCORE' => '[\w_]+', - 'ALPHA_DOTS' => '[\w.]+', - 'ALPHA_SPACERS' => '[\w\x20_+\-\[\]]+', - 'ALPHA_PUNCTUATION' => '[a-zA-Z][\w\.,\-_]+', + 'ALPHA_ONLY' => '[a-zA-Z0-9]+', + 'ALPHA_UNDERSCORE' => '[\w]+', + 'ALPHA_DOTS' => '[a-zA-Z0-9.]+', + 'ALPHA_SPACERS' => '[\w\x20+\-\[\]]+', + 'ALPHA_PUNCTUATION' => '[a-zA-Z][\w\.,\-]+', 'LETTER_NUM_ONLY' => '[\p{Lu}\p{Ll}0-9]+', 'LETTER_NUM_UNDERSCORE' => '[\p{Lu}\p{Ll}0-9_]+', 'LETTER_NUM_DOTS' => '[\p{Lu}\p{Ll}0-9.]+', diff --git a/phpBB/phpbb/profilefields/type/type_url.php b/phpBB/phpbb/profilefields/type/type_url.php index bc8ac869d0..fe0bffd582 100644 --- a/phpBB/phpbb/profilefields/type/type_url.php +++ b/phpBB/phpbb/profilefields/type/type_url.php @@ -64,7 +64,7 @@ class type_url extends type_string return false; } - if (!preg_match('#^' . get_preg_expression('url') . '$#i', $field_value)) + if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $field_value)) { return $this->user->lang('FIELD_INVALID_URL', $this->get_field_name($field_data['lang_name'])); } diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php index ea9854894c..56ce3999ed 100644 --- a/phpBB/phpbb/request/request.php +++ b/phpBB/phpbb/request/request.php @@ -275,7 +275,7 @@ class request implements \phpbb\request\request_interface */ public function file($form_name) { - return $this->variable($form_name, array('name' => 'none'), false, \phpbb\request\request_interface::FILES); + return $this->variable($form_name, array('name' => 'none'), true, \phpbb\request\request_interface::FILES); } /** @@ -416,4 +416,27 @@ class request implements \phpbb\request\request_interface { return $this->input[$super_global]; } + + /** + * {@inheritdoc} + */ + public function escape($var, $multibyte) + { + if (is_array($var)) + { + $result = array(); + foreach ($var as $key => $value) + { + $this->type_cast_helper->set_var($key, $key, gettype($key), $multibyte); + $result[$key] = $this->escape($value, $multibyte); + } + $var = $result; + } + else + { + $this->type_cast_helper->set_var($var, $var, 'string', $multibyte); + } + + return $var; + } } diff --git a/phpBB/phpbb/request/request_interface.php b/phpBB/phpbb/request/request_interface.php index 3236f73990..47b3b3a4ed 100644 --- a/phpBB/phpbb/request/request_interface.php +++ b/phpBB/phpbb/request/request_interface.php @@ -142,4 +142,14 @@ interface request_interface * @return array The original array of the requested super global. */ public function get_super_global($super_global = \phpbb\request\request_interface::REQUEST); + + /** + * Escape a string variable. + * + * @param mixed $value The contents to fill with + * @param bool $multibyte Indicates whether string values may contain UTF-8 characters. + * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks. + * @return string|array + */ + public function escape($value, $multibyte); } diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index 48b0f077c7..4d02dd1cbf 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -300,7 +300,7 @@ class fulltext_native extends \phpbb\search\base $this->search_query = $keywords; $exact_words = array(); - preg_match_all('#([^\\s+\\-|*()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words); + preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words); $exact_words = $exact_words[1]; $common_ids = $words = array(); @@ -434,7 +434,7 @@ class fulltext_native extends \phpbb\search\base // throw an error if we shall not ignore unexistant words else if (!$ignore_no_id && sizeof($non_common_words)) { - trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], implode($user->lang['COMMA_SEPARATOR'], $non_common_words))); + trigger_error(sprintf($this->user->lang['WORDS_IN_NO_POST'], implode($this->user->lang['COMMA_SEPARATOR'], $non_common_words))); } unset($non_common_words); } @@ -823,6 +823,13 @@ class fulltext_native extends \phpbb\search\base ); } + // if using mysql and the total result count is not calculated yet, get it from the db + if (!$total_results && $is_mysql) + { + // Also count rows for the query as if there was not LIMIT. Add SQL_CALC_FOUND_ROWS to SQL + $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; + } + $sql_array['WHERE'] = implode(' AND ', $sql_where); $sql_array['GROUP_BY'] = ($group_by) ? (($type == 'posts') ? 'p.post_id' : 'p.topic_id') . ', ' . $sort_by_sql[$sort_key] : ''; $sql_array['ORDER_BY'] = $sql_sort; @@ -838,19 +845,9 @@ class fulltext_native extends \phpbb\search\base } $this->db->sql_freeresult($result); - // if we use mysql and the total result count is not cached yet, retrieve it from the db if (!$total_results && $is_mysql) { - // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it - $sql_array_copy = $sql_array; - $sql_array_copy['SELECT'] = 'SQL_CALC_FOUND_ROWS p.post_id '; - - $sql_calc = $this->db->sql_build_query('SELECT', $sql_array_copy); - unset($sql_array_copy); - - $this->db->sql_query($sql_calc); - $this->db->sql_freeresult($result); - + // Get the number of results as calculated by MySQL $sql_count = 'SELECT FOUND_ROWS() as total_results'; $result = $this->db->sql_query($sql_count); $total_results = (int) $this->db->sql_fetchfield('total_results'); diff --git a/phpBB/phpbb/search/fulltext_sphinx.php b/phpBB/phpbb/search/fulltext_sphinx.php index 79d68d2ae1..eb53ca6d40 100644 --- a/phpBB/phpbb/search/fulltext_sphinx.php +++ b/phpBB/phpbb/search/fulltext_sphinx.php @@ -256,8 +256,8 @@ class fulltext_sphinx array('type', $this->dbtype . ' # mysql or pgsql'), // This config value sql_host needs to be changed incase sphinx and sql are on different servers array('sql_host', $dbhost . ' # SQL server host sphinx connects to'), - array('sql_user', $dbuser), - array('sql_pass', $dbpasswd), + array('sql_user', '[dbuser]'), + array('sql_pass', '[dbpassword]'), array('sql_db', $dbname), array('sql_port', $dbport . ' # optional, default is 3306 for mysql and 5432 for pgsql'), array('sql_query_pre', 'SET NAMES \'utf8\''), @@ -715,6 +715,7 @@ class fulltext_sphinx ), 'ON' => 'p1.topic_id = p2.topic_id', )), + 'WHERE' => 'p2.post_id = ' . ((int) $post_id), ); $sql = $this->db->sql_build_query('SELECT', $sql_array); diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index da8b848fa5..bedd581725 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -31,10 +31,11 @@ class session var $update_session_page = true; /** - * Extract current session page - * - * @param string $root_path current root path (phpbb_root_path) - */ + * Extract current session page + * + * @param string $root_path current root path (phpbb_root_path) + * @return array + */ static function extract_current_page($root_path) { global $request, $symfony_request, $phpbb_filesystem; @@ -42,8 +43,8 @@ class session $page_array = array(); // First of all, get the request uri... - $script_name = $symfony_request->getScriptName(); - $args = explode('&', $symfony_request->getQueryString()); + $script_name = $request->escape($symfony_request->getScriptName(), true); + $args = $request->escape(explode('&', $symfony_request->getQueryString()), true); // If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support... if (!$script_name) @@ -61,8 +62,8 @@ class session // Since some browser do not encode correctly we need to do this with some "special" characters... // " -> %22, ' => %27, < -> %3C, > -> %3E - $find = array('"', "'", '<', '>'); - $replace = array('%22', '%27', '%3C', '%3E'); + $find = array('"', "'", '<', '>', '"', '<', '>'); + $replace = array('%22', '%27', '%3C', '%3E', '%22', '%3C', '%3E'); foreach ($args as $key => $argument) { @@ -87,7 +88,7 @@ class session $symfony_request_path = $phpbb_filesystem->clean_path($symfony_request->getPathInfo()); if ($symfony_request_path !== '/') { - $page_name .= $symfony_request_path; + $page_name .= str_replace('%2F', '/', urlencode($symfony_request_path)); } // current directory within the phpBB root (for example: adm) @@ -129,6 +130,10 @@ class session $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/'; $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/'; + $forum_id = $request->variable('f', 0); + // maximum forum id value is maximum value of mediumint unsigned column + $forum_id = ($forum_id > 0 && $forum_id < 16777215) ? $forum_id : 0; + $page_array += array( 'page_name' => $page_name, 'page_dir' => $page_dir, @@ -138,7 +143,7 @@ class session 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)), 'page' => $page, - 'forum' => request_var('f', 0), + 'forum' => $forum_id, ); return $page_array; @@ -581,6 +586,11 @@ class session $provider = $provider_collection->get_provider(); $this->data = $provider->autologin(); + if ($user_id !== false && sizeof($this->data) && $this->data['user_id'] != $user_id) + { + $this->data = array(); + } + if (sizeof($this->data)) { $this->cookie_data['k'] = ''; @@ -598,11 +608,18 @@ class session AND k.user_id = u.user_id AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); + $user_data = $db->sql_fetchrow($result); + + if ($user_id === false || (isset($user_data['user_id']) && $user_id == $user_data['user_id'])) + { + $this->data = $user_data; + $bot = false; + } + $db->sql_freeresult($result); - $bot = false; } - else if ($user_id !== false && !sizeof($this->data)) + + if ($user_id !== false && !sizeof($this->data)) { $this->cookie_data['k'] = ''; $this->cookie_data['u'] = $user_id; @@ -1050,7 +1067,7 @@ class session $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata); $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); - $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']; + $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == '127.0.0.1' || strpos($config['cookie_domain'], '.') === false) ? '' : '; domain=' . $config['cookie_domain']; header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false); } @@ -1069,7 +1086,7 @@ class session */ function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false) { - global $config, $db; + global $config, $db, $phpbb_dispatcher; if (defined('IN_CHECK_BAN') || defined('SKIP_CHECK_BAN')) { @@ -1183,6 +1200,20 @@ class session } $db->sql_freeresult($result); + /** + * Event to set custom ban type + * + * @event core.session_set_custom_ban + * @var bool return If $return is false this routine does not return on finding a banned user, it outputs a relevant message and stops execution + * @var bool banned Check if user already banned + * @var array|false ban_row Ban data + * @var string ban_triggered_by Method that caused ban, can be your custom method + * @since 3.1.3-RC1 + */ + $ban_row = isset($ban_row) ? $ban_row : false; + $vars = array('return', 'banned', 'ban_row', 'ban_triggered_by'); + extract($phpbb_dispatcher->trigger_event('core.session_set_custom_ban', compact($vars))); + if ($banned && !$return) { global $template, $phpbb_root_path, $phpEx; diff --git a/phpBB/phpbb/symfony_request.php b/phpBB/phpbb/symfony_request.php index bf9ddec493..2931cae3cc 100644 --- a/phpBB/phpbb/symfony_request.php +++ b/phpBB/phpbb/symfony_request.php @@ -15,6 +15,10 @@ namespace phpbb; use Symfony\Component\HttpFoundation\Request; +/** + * WARNING: The Symfony request does not escape the input and should be used very carefully + * prefer the phpbb request as possible + */ class symfony_request extends Request { /** @@ -24,21 +28,12 @@ class symfony_request extends Request */ public function __construct(\phpbb\request\request_interface $phpbb_request) { - // This function is meant to sanitize the global input arrays - $sanitizer = function(&$value, $key) { - $type_cast_helper = new \phpbb\request\type_cast_helper(); - $type_cast_helper->set_var($value, $value, gettype($value), true); - }; - $get_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::GET); $post_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::POST); $server_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::SERVER); $files_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::FILES); $cookie_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::COOKIE); - array_walk_recursive($get_parameters, $sanitizer); - array_walk_recursive($post_parameters, $sanitizer); - parent::__construct($get_parameters, $post_parameters, array(), $cookie_parameters, $files_parameters, $server_parameters); } } diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php index a3b002f350..bd754d9bbd 100644 --- a/phpBB/phpbb/template/twig/twig.php +++ b/phpBB/phpbb/template/twig/twig.php @@ -115,6 +115,11 @@ class twig extends \phpbb\template\base ) ); + if (defined('DEBUG')) + { + $this->twig->addExtension(new \Twig_Extension_Debug()); + } + $lexer = new \phpbb\template\twig\lexer($this->twig); $this->twig->setLexer($lexer); @@ -189,13 +194,24 @@ class twig extends \phpbb\template\base { $path = $this->phpbb_root_path . trim($directory, '/') . "/{$name}/"; $template_path = $path . 'template/'; + $theme_path = $path . 'theme/'; + $is_valid_dir = false; if (is_dir($template_path)) { + $is_valid_dir = true; + $paths[] = $template_path; + } + if (is_dir($theme_path)) + { + $is_valid_dir = true; + $paths[] = $theme_path; + } + + if ($is_valid_dir) + { // Add the base style directory as a safe directory $this->twig->getLoader()->addSafeDirectory($path); - - $paths[] = $template_path; } } } @@ -253,25 +269,38 @@ class twig extends \phpbb\template\base { $ext_style_template_path = $ext_path . $template_dir['ext_path']; $ext_style_path = dirname($ext_style_template_path); + $ext_style_theme_path = $ext_style_path . 'theme/'; } else { $ext_style_path = $ext_path . 'styles/' . $template_dir['name'] . '/'; $ext_style_template_path = $ext_style_path . 'template/'; + $ext_style_theme_path = $ext_style_path . 'theme/'; } } else { $ext_style_path = $ext_path . 'styles/' . $template_dir . '/'; $ext_style_template_path = $ext_style_path . 'template/'; + $ext_style_theme_path = $ext_style_path . 'theme/'; } + $is_valid_dir = false; if (is_dir($ext_style_template_path)) { + $is_valid_dir = true; + $paths[] = $ext_style_template_path; + } + if (is_dir($ext_style_theme_path)) + { + $is_valid_dir = true; + $paths[] = $ext_style_theme_path; + } + + if ($is_valid_dir) + { // Add the base style directory as a safe directory $this->twig->getLoader()->addSafeDirectory($ext_style_path); - - $paths[] = $ext_style_template_path; } } diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php index ea98034434..882e9cef26 100644 --- a/phpBB/phpbb/user.php +++ b/phpBB/phpbb/user.php @@ -717,7 +717,7 @@ class user extends \phpbb\session $utc = new \DateTimeZone('UTC'); } - $time = new \phpbb\datetime($this, "@$gmepoch", $utc); + $time = new $this->datetime($this, "@$gmepoch", $utc); $time->setTimezone($this->timezone); return $time->format($format, $forcedate); diff --git a/phpBB/phpbb/user_loader.php b/phpBB/phpbb/user_loader.php index c9707ee432..24e663b150 100644 --- a/phpBB/phpbb/user_loader.php +++ b/phpBB/phpbb/user_loader.php @@ -212,7 +212,7 @@ class user_loader return ''; } - if (!function_exists('get_user_rank')) + if (!function_exists('phpbb_get_user_rank')) { include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext); } @@ -223,7 +223,10 @@ class user_loader 'rank_img_src', ); - get_user_rank($user['user_rank'], (($user['user_id'] == ANONYMOUS) ? false : $user['user_posts']), $rank['rank_title'], $rank['rank_img'], $rank['rank_img_src']); + $user_rank_data = phpbb_get_user_rank($user, (($user['user_id'] == ANONYMOUS) ? false : $user['user_posts'])); + $rank['rank_title'] = $user_rank_data['title']; + $rank['rank_img'] = $user_rank_data['img']; + $rank['rank_img_src'] = $user_rank_data['img_src']; return $rank; } diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php index 968a57428f..e4f68f5aab 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -50,6 +50,9 @@ class version_helper /** @var \phpbb\config\config */ protected $config; + /** @var \phpbb\file_downloader */ + protected $file_downloader; + /** @var \phpbb\user */ protected $user; @@ -58,12 +61,14 @@ class version_helper * * @param \phpbb\cache\service $cache * @param \phpbb\config\config $config + * @param \phpbb\file_downloader $file_downloader * @param \phpbb\user $user */ - public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\user $user) + public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader, \phpbb\user $user) { $this->cache = $cache; $this->config = $config; + $this->file_downloader = $file_downloader; $this->user = $user; if (defined('PHPBB_QA')) @@ -239,7 +244,7 @@ class version_helper */ public function get_versions($force_update = false, $force_cache = false) { - $cache_file = 'versioncheck_' . $this->host . $this->path . $this->file; + $cache_file = '_versioncheck_' . $this->host . $this->path . $this->file; $info = $this->cache->get($cache_file); @@ -249,16 +254,33 @@ class version_helper } else if ($info === false || $force_update) { - $errstr = $errno = ''; - $info = get_remote_file($this->host, $this->path, $this->file, $errstr, $errno); + try { + $info = $this->file_downloader->get($this->host, $this->path, $this->file); + } + catch (\phpbb\exception\runtime_exception $exception) + { + $prepare_parameters = array_merge(array($exception->getMessage()), $exception->get_parameters()); + throw new \RuntimeException(call_user_func_array(array($this->user, 'lang'), $prepare_parameters)); + } + $error_string = $this->file_downloader->get_error_string(); - if (!empty($errstr)) + if (!empty($error_string)) { - throw new \RuntimeException($errstr); + throw new \RuntimeException($error_string); } $info = json_decode($info, true); + // Sanitize any data we retrieve from a server + if (!empty($info)) + { + $json_sanitizer = function (&$value, $key) { + $type_cast_helper = new \phpbb\request\type_cast_helper(); + $type_cast_helper->set_var($value, $value, gettype($value), true); + }; + array_walk_recursive($info, $json_sanitizer); + } + if (empty($info['stable']) && empty($info['unstable'])) { $this->user->add_lang('acp/common'); @@ -266,15 +288,6 @@ class version_helper throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL')); } - // Replace & with & on announcement links - foreach ($info as $stability => $branches) - { - foreach ($branches as $branch => $branch_data) - { - $info[$stability][$branch]['announcement'] = str_replace('&', '&', $branch_data['announcement']); - } - } - $info['stable'] = (empty($info['stable'])) ? array() : $info['stable']; $info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable']; |