diff options
Diffstat (limited to 'phpBB/phpbb')
36 files changed, 1256 insertions, 193 deletions
diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php index b7634e04ce..37d4352c10 100644 --- a/phpBB/phpbb/auth/auth.php +++ b/phpBB/phpbb/auth/auth.php @@ -514,7 +514,7 @@ class auth */ function acl_clear_prefetch($user_id = false) { - global $db, $cache; + global $db, $cache, $phpbb_dispatcher; // Rebuild options cache $cache->destroy('_role_cache'); @@ -553,6 +553,16 @@ class auth $where_sql"; $db->sql_query($sql); + /** + * Event is triggered after user(s) permission settings cache has been cleared + * + * @event core.acl_clear_prefetch_after + * @var mixed user_id User ID(s) + * @since 3.1.11-RC1 + */ + $vars = array('user_id'); + extract($phpbb_dispatcher->trigger_event('core.acl_clear_prefetch_after', compact($vars))); + return; } diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php index fae4614039..1e9ee960dc 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -601,6 +601,6 @@ class file extends \phpbb\cache\driver\base */ protected function clean_varname($varname) { - return str_replace('/', '-', $varname); + return str_replace(array('/', '\\'), '-', $varname); } } diff --git a/phpBB/phpbb/cache/driver/memcache.php b/phpBB/phpbb/cache/driver/memcache.php index caa82fb0b1..57f138f574 100644 --- a/phpBB/phpbb/cache/driver/memcache.php +++ b/phpBB/phpbb/cache/driver/memcache.php @@ -52,8 +52,8 @@ class memcache extends \phpbb\cache\driver\memory $this->memcache = new \Memcache; foreach (explode(',', PHPBB_ACM_MEMCACHE) as $u) { - $parts = explode('/', $u); - $this->memcache->addServer(trim($parts[0]), trim($parts[1])); + preg_match('#(.*)/(\d+)#', $u, $parts); + $this->memcache->addServer(trim($parts[1]), (int) trim($parts[2])); } $this->flags = (PHPBB_ACM_MEMCACHE_COMPRESS) ? MEMCACHE_COMPRESSED : 0; } diff --git a/phpBB/phpbb/cache/driver/memcached.php b/phpBB/phpbb/cache/driver/memcached.php new file mode 100644 index 0000000000..a7da22d7e8 --- /dev/null +++ b/phpBB/phpbb/cache/driver/memcached.php @@ -0,0 +1,134 @@ +<?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\cache\driver; + +if (!defined('PHPBB_ACM_MEMCACHED_PORT')) +{ + define('PHPBB_ACM_MEMCACHED_PORT', 11211); +} + +if (!defined('PHPBB_ACM_MEMCACHED_COMPRESS')) +{ + define('PHPBB_ACM_MEMCACHED_COMPRESS', true); +} + +if (!defined('PHPBB_ACM_MEMCACHED_HOST')) +{ + define('PHPBB_ACM_MEMCACHED_HOST', 'localhost'); +} + +if (!defined('PHPBB_ACM_MEMCACHED')) +{ + //can define multiple servers with host1/port1,host2/port2 format + define('PHPBB_ACM_MEMCACHED', PHPBB_ACM_MEMCACHED_HOST . '/' . PHPBB_ACM_MEMCACHED_PORT); +} + +/** +* ACM for Memcached +*/ +class memcached extends \phpbb\cache\driver\memory +{ + /** @var string Extension to use */ + protected $extension = 'memcached'; + + /** @var \Memcached Memcached class */ + protected $memcached; + + /** @var int Flags */ + protected $flags = 0; + + /** + * Memcached constructor + */ + public function __construct() + { + // Call the parent constructor + parent::__construct(); + + $this->memcached = new \Memcached(); + $this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); + // Memcached defaults to using compression, disable if we don't want + // to use it + if (!PHPBB_ACM_MEMCACHED_COMPRESS) + { + $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false); + } + + foreach (explode(',', PHPBB_ACM_MEMCACHE) as $u) + { + preg_match('#(.*)/(\d+)#', $u, $parts); + $this->memcache->addServer(trim($parts[1]), (int) trim($parts[2])); + } + } + + /** + * {@inheritDoc} + */ + public function unload() + { + parent::unload(); + + unset($this->memcached); + } + + /** + * {@inheritDoc} + */ + public function purge() + { + $this->memcached->flush(); + + parent::purge(); + } + + /** + * Fetch an item from the cache + * + * @param string $var Cache key + * + * @return mixed Cached data + */ + protected function _read($var) + { + return $this->memcached->get($this->key_prefix . $var); + } + + /** + * Store data in the cache + * + * @param string $var Cache key + * @param mixed $data Data to store + * @param int $ttl Time-to-live of cached data + * @return bool True if the operation succeeded + */ + protected function _write($var, $data, $ttl = 2592000) + { + if (!$this->memcached->replace($this->key_prefix . $var, $data, $ttl)) + { + return $this->memcached->set($this->key_prefix . $var, $data, $ttl); + } + return true; + } + + /** + * Remove an item from the cache + * + * @param string $var Cache key + * @return bool True if the operation succeeded + */ + protected function _delete($var) + { + return $this->memcached->delete($this->key_prefix . $var); + } +} diff --git a/phpBB/phpbb/console/command/fixup/fix_left_right_ids.php b/phpBB/phpbb/console/command/fixup/fix_left_right_ids.php new file mode 100644 index 0000000000..f55e1761bc --- /dev/null +++ b/phpBB/phpbb/console/command/fixup/fix_left_right_ids.php @@ -0,0 +1,134 @@ +<?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\fixup; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class fix_left_right_ids extends \phpbb\console\command\command +{ + /** @var \phpbb\user */ + protected $user; + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** @var \phpbb\cache\driver\driver_interface */ + protected $cache; + + /** + * Constructor + * + * @param \phpbb\user $user User instance + * @param \phpbb\db\driver\driver_interface $db Database connection + * @param \phpbb\cache\driver\driver_interface $cache Cache instance + */ + public function __construct(\phpbb\user $user, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache) + { + $this->user = $user; + $this->db = $db; + $this->cache = $cache; + + parent::__construct($user); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('fixup:fix-left-right-ids') + ->setDescription($this->user->lang('CLI_DESCRIPTION_FIX_LEFT_RIGHT_IDS')) + ; + } + + /** + * Executes the command fixup:fix-left-right-ids. + * + * Repairs the tree structure of the forums and modules. + * The code is mainly borrowed from Support toolkit for phpBB Olympus + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return void + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + // Fix Left/Right IDs for the modules table + $result = $this->db->sql_query('SELECT DISTINCT(module_class) FROM ' . MODULES_TABLE); + while ($row = $this->db->sql_fetchrow($result)) + { + $i = 1; + $where = array("module_class = '" . $this->db->sql_escape($row['module_class']) . "'"); + $this->fix_ids_tree($i, 'module_id', MODULES_TABLE, 0, $where); + } + $this->db->sql_freeresult($result); + + // Fix the Left/Right IDs for the forums table + $i = 1; + $this->fix_ids_tree($i, 'forum_id', FORUMS_TABLE); + + $this->cache->purge(); + + $output->writeln('<info>' . $this->user->lang('CLI_FIXUP_FIX_LEFT_RIGHT_IDS_SUCCESS') . '</info>'); + } + + /** + * Item's tree structure rebuild helper + * The item is either forum or ACP/MCP/UCP module + * + * @param int $i Item id offset index + * @param string $field The key field to fix, forum_id|module_id + * @param string $table The table name to perform, FORUMS_TABLE|MODULES_TABLE + * @param int $parent_id Parent item id + * @param array $where Additional WHERE clause condition + * + * @return bool True on rebuild success, false otherwise + */ + protected function fix_ids_tree(&$i, $field, $table, $parent_id = 0, $where = array()) + { + $changes_made = false; + $sql = 'SELECT * FROM ' . $table . ' + WHERE parent_id = ' . (int) $parent_id . + ((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . ' + ORDER BY left_id ASC'; + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + // Update the left_id for the item + if ($row['left_id'] != $i) + { + $this->db->sql_query('UPDATE ' . $table . ' SET ' . $this->db->sql_build_array('UPDATE', array('left_id' => $i)) . " WHERE $field = " . (int) $row[$field]); + $changes_made = true; + } + $i++; + + // Go through children and update their left/right IDs + $changes_made = (($this->fix_ids_tree($i, $field, $table, $row[$field], $where)) || $changes_made) ? true : false; + + // Update the right_id for the item + if ($row['right_id'] != $i) + { + $this->db->sql_query('UPDATE ' . $table . ' SET ' . $this->db->sql_build_array('UPDATE', array('right_id' => $i)) . " WHERE $field = " . (int) $row[$field]); + $changes_made = true; + } + $i++; + } + $this->db->sql_freeresult($result); + + return $changes_made; + } +} diff --git a/phpBB/phpbb/console/command/fixup/update_hashes.php b/phpBB/phpbb/console/command/fixup/update_hashes.php new file mode 100644 index 0000000000..4bcc3b5d19 --- /dev/null +++ b/phpBB/phpbb/console/command/fixup/update_hashes.php @@ -0,0 +1,117 @@ +<?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\fixup; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Helper\ProgressBar; + +class update_hashes extends \phpbb\console\command\command +{ + /** @var \phpbb\config\config */ + protected $config; + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** @var \phpbb\passwords\manager */ + protected $passwords_manager; + + /** @var string Default hashing type */ + protected $default_type; + + /** + * Update_hashes constructor + * + * @param \phpbb\config\config $config + * @param \phpbb\user $user + * @param \phpbb\db\driver\driver_interface $db + * @param \phpbb\passwords\manager $passwords_manager + * @param array $hashing_algorithms Hashing driver + * service collection + * @param array $defaults Default password types + */ + public function __construct(\phpbb\config\config $config, \phpbb\user $user, + \phpbb\db\driver\driver_interface $db, \phpbb\passwords\manager $passwords_manager, + $hashing_algorithms, $defaults) + { + $this->config = $config; + $this->db = $db; + + $this->passwords_manager = $passwords_manager; + + foreach ($defaults as $type) + { + if ($hashing_algorithms[$type]->is_supported()) + { + $this->default_type = $type; + break; + } + } + + parent::__construct($user); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('fixup:update-hashes') + ->setDescription($this->user->lang('CLI_DESCRIPTION_UPDATE_HASH_BCRYPT')) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + // Get count to be able to display progress + $sql = 'SELECT COUNT(user_id) AS count + FROM ' . USERS_TABLE . ' + WHERE user_password ' . $this->db->sql_like_expression('$H$' . $this->db->get_any_char()) . ' + OR user_password ' . $this->db->sql_like_expression('$CP$' . $this->db->get_any_char()); + $result = $this->db->sql_query($sql); + $total_update_passwords = $this->db->sql_fetchfield('count'); + $this->db->sql_freeresult($result); + + // Create progress bar + $progress_bar = new ProgressBar($output, $total_update_passwords); + $progress_bar->start(); + + $sql = 'SELECT user_id, user_password + FROM ' . USERS_TABLE . ' + WHERE user_password ' . $this->db->sql_like_expression('$H$' . $this->db->get_any_char()) . ' + OR user_password ' . $this->db->sql_like_expression('$CP$' . $this->db->get_any_char()); + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + $new_hash = $this->passwords_manager->hash($row['user_password'], array($this->default_type)); + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_password = "' . $this->db->sql_escape($new_hash) . '" + WHERE user_id = ' . (int) $row['user_id']; + $this->db->sql_query($sql); + $progress_bar->advance(); + } + + $this->config->set('update_hashes_last_cron', time()); + + $progress_bar->finish(); + + $output->writeln('<info>' . $this->user->lang('CLI_FIXUP_UPDATE_HASH_BCRYPT_SUCCESS') . '</info>'); + } +} diff --git a/phpBB/phpbb/cron/task/core/update_hashes.php b/phpBB/phpbb/cron/task/core/update_hashes.php new file mode 100644 index 0000000000..a4fe477d99 --- /dev/null +++ b/phpBB/phpbb/cron/task/core/update_hashes.php @@ -0,0 +1,130 @@ +<?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\cron\task\core; + +/** + * Update old hashes to the current default hashing algorithm + * + * It is intended to gradually update all "old" style hashes to the + * current default hashing algorithm. + */ +class update_hashes extends \phpbb\cron\task\base +{ + /** @var \phpbb\config\config */ + protected $config; + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** @var \phpbb\lock\db */ + protected $update_lock; + + /** @var \phpbb\passwords\manager */ + protected $passwords_manager; + + /** @var string Default hashing type */ + protected $default_type; + + /** + * Constructor. + * + * @param \phpbb\config\config $config + * @param \phpbb\db\driver\driver_interface $db + * @param \phpbb\lock\db $update_lock + * @param \phpbb\passwords\manager $passwords_manager + * @param array $hashing_algorithms Hashing driver + * service collection + * @param array $defaults Default password types + */ + public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\lock\db $update_lock, \phpbb\passwords\manager $passwords_manager, $hashing_algorithms, $defaults) + { + $this->config = $config; + $this->db = $db; + $this->passwords_manager = $passwords_manager; + $this->update_lock = $update_lock; + + foreach ($defaults as $type) + { + if ($hashing_algorithms[$type]->is_supported()) + { + $this->default_type = $type; + break; + } + } + } + + /** + * {@inheritdoc} + */ + public function is_runnable() + { + return !$this->config['use_system_cron']; + } + + /** + * {@inheritdoc} + */ + public function should_run() + { + if (!empty($this->config['update_hashes_lock'])) + { + $last_run = explode(' ', $this->config['update_hashes_lock']); + if ($last_run[0] + 60 >= time()) + { + return false; + } + } + + return $this->config['enable_update_hashes'] && $this->config['update_hashes_last_cron'] < (time() - 60); + } + + /** + * {@inheritdoc} + */ + public function run() + { + if ($this->update_lock->acquire()) + { + $sql = 'SELECT user_id, user_password + FROM ' . USERS_TABLE . ' + WHERE user_password ' . $this->db->sql_like_expression('$H$' . $this->db->get_any_char()) . ' + OR user_password ' . $this->db->sql_like_expression('$CP$' . $this->db->get_any_char()); + $result = $this->db->sql_query_limit($sql, 20); + + $affected_rows = 0; + + while ($row = $this->db->sql_fetchrow($result)) + { + $new_hash = $this->passwords_manager->hash($row['user_password'], array($this->default_type)); + + // Increase number so we know that users were selected from the database + $affected_rows++; + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_password = "' . $this->db->sql_escape($new_hash) . '" + WHERE user_id = ' . (int) $row['user_id']; + $this->db->sql_query($sql); + } + + $this->config->set('update_hashes_last_cron', time()); + $this->update_lock->release(); + + // Stop cron for good once all hashes are converted + if ($affected_rows === 0) + { + $this->config->set('enable_update_hashes', '0'); + } + } + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/.htaccess b/phpBB/phpbb/db/migration/data/v30x/.htaccess new file mode 100644 index 0000000000..44242b5418 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v30x/.htaccess @@ -0,0 +1,33 @@ +# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from +# module mod_authz_host to a new module called mod_access_compat (which may be +# disabled) and a new "Require" syntax has been introduced to mod_authz_host. +# We could just conditionally provide both versions, but unfortunately Apache +# does not explicitly tell us its version if the module mod_version is not +# available. In this case, we check for the availability of module +# mod_authz_core (which should be on 2.4 or higher only) as a best guess. +<IfModule mod_version.c> + <IfVersion < 2.4> + <Files "*"> + Order Allow,Deny + Deny from All + </Files> + </IfVersion> + <IfVersion >= 2.4> + <Files "*"> + Require all denied + </Files> + </IfVersion> +</IfModule> +<IfModule !mod_version.c> + <IfModule !mod_authz_core.c> + <Files "*"> + Order Allow,Deny + Deny from All + </Files> + </IfModule> + <IfModule mod_authz_core.c> + <Files "*"> + Require all denied + </Files> + </IfModule> +</IfModule> diff --git a/phpBB/phpbb/db/migration/data/v310/.htaccess b/phpBB/phpbb/db/migration/data/v310/.htaccess new file mode 100644 index 0000000000..44242b5418 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v310/.htaccess @@ -0,0 +1,33 @@ +# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from +# module mod_authz_host to a new module called mod_access_compat (which may be +# disabled) and a new "Require" syntax has been introduced to mod_authz_host. +# We could just conditionally provide both versions, but unfortunately Apache +# does not explicitly tell us its version if the module mod_version is not +# available. In this case, we check for the availability of module +# mod_authz_core (which should be on 2.4 or higher only) as a best guess. +<IfModule mod_version.c> + <IfVersion < 2.4> + <Files "*"> + Order Allow,Deny + Deny from All + </Files> + </IfVersion> + <IfVersion >= 2.4> + <Files "*"> + Require all denied + </Files> + </IfVersion> +</IfModule> +<IfModule !mod_version.c> + <IfModule !mod_authz_core.c> + <Files "*"> + Order Allow,Deny + Deny from All + </Files> + </IfModule> + <IfModule mod_authz_core.c> + <Files "*"> + Require all denied + </Files> + </IfModule> +</IfModule> diff --git a/phpBB/phpbb/db/migration/data/v31x/.htaccess b/phpBB/phpbb/db/migration/data/v31x/.htaccess new file mode 100644 index 0000000000..44242b5418 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/.htaccess @@ -0,0 +1,33 @@ +# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from +# module mod_authz_host to a new module called mod_access_compat (which may be +# disabled) and a new "Require" syntax has been introduced to mod_authz_host. +# We could just conditionally provide both versions, but unfortunately Apache +# does not explicitly tell us its version if the module mod_version is not +# available. In this case, we check for the availability of module +# mod_authz_core (which should be on 2.4 or higher only) as a best guess. +<IfModule mod_version.c> + <IfVersion < 2.4> + <Files "*"> + Order Allow,Deny + Deny from All + </Files> + </IfVersion> + <IfVersion >= 2.4> + <Files "*"> + Require all denied + </Files> + </IfVersion> +</IfModule> +<IfModule !mod_version.c> + <IfModule !mod_authz_core.c> + <Files "*"> + Order Allow,Deny + Deny from All + </Files> + </IfModule> + <IfModule mod_authz_core.c> + <Files "*"> + Require all denied + </Files> + </IfModule> +</IfModule> diff --git a/phpBB/phpbb/db/migration/data/v31x/add_jabber_ssl_context_config_options.php b/phpBB/phpbb/db/migration/data/v31x/add_jabber_ssl_context_config_options.php new file mode 100644 index 0000000000..9f416fe069 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/add_jabber_ssl_context_config_options.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 add_jabber_ssl_context_config_options extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v3110'); + } + + public function update_data() + { + return array( + // See http://php.net/manual/en/context.ssl.php + array('config.add', array('jab_verify_peer', 1)), + array('config.add', array('jab_verify_peer_name', 1)), + array('config.add', array('jab_allow_self_signed', 0)), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php b/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php new file mode 100644 index 0000000000..fa2899e348 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.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\v31x; + +class add_latest_topics_index extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v3110', + ); + } + + public function update_schema() + { + return array( + 'add_index' => array( + $this->table_prefix . 'topics' => array( + 'latest_topics' => array( + 'forum_id', + 'topic_last_post_time', + 'topic_last_post_id', + 'topic_moved_id', + ), + ), + ), + ); + } + + public function revert_schema() + { + return array( + 'drop_keys' => array( + $this->table_prefix . 'topics' => array( + 'latest_topics', + ), + ), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php b/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php new file mode 100644 index 0000000000..92051dc3ca --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.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 add_smtp_ssl_context_config_options extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v3110'); + } + + public function update_data() + { + return array( + // See http://php.net/manual/en/context.ssl.php + array('config.add', array('smtp_verify_peer', 1)), + array('config.add', array('smtp_verify_peer_name', 1)), + array('config.add', array('smtp_allow_self_signed', 0)), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/update_hashes.php b/phpBB/phpbb/db/migration/data/v31x/update_hashes.php new file mode 100644 index 0000000000..aa83c3ffbf --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/update_hashes.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\v31x; + +class update_hashes extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v3110', + ); + } + + public function update_data() + { + return array( + array('config.add', array('enable_update_hashes', '1')), + array('config.add', array('update_hashes_lock', '')), + array('config.add', array('update_hashes_last_cron', '0')) + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v3111rc1.php b/phpBB/phpbb/db/migration/data/v31x/v3111rc1.php new file mode 100644 index 0000000000..259656283f --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v3111rc1.php @@ -0,0 +1,43 @@ +<?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 v3111rc1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return phpbb_version_compare($this->config['version'], '3.1.11-RC1', '>='); + } + + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v3110', + '\phpbb\db\migration\data\v31x\add_log_time_index', + '\phpbb\db\migration\data\v31x\increase_size_of_emotion', + '\phpbb\db\migration\data\v31x\add_jabber_ssl_context_config_options', + '\phpbb\db\migration\data\v31x\add_smtp_ssl_context_config_options', + '\phpbb\db\migration\data\v31x\update_hashes', + '\phpbb\db\migration\data\v31x\remove_duplicate_migrations', + '\phpbb\db\migration\data\v31x\add_latest_topics_index', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.11-RC1')), + ); + } +} diff --git a/phpBB/phpbb/di/container_builder.php b/phpBB/phpbb/di/container_builder.php index a214356ac3..5f3aa685bf 100644 --- a/phpBB/phpbb/di/container_builder.php +++ b/phpBB/phpbb/di/container_builder.php @@ -185,6 +185,7 @@ class container_builder } $this->container->set('config.php', $this->config_php_file); + $this->inject_dbal_driver(); if ($this->compile_container) { @@ -304,6 +305,18 @@ class container_builder } /** + * Inject the dbal connection driver into container + */ + protected function inject_dbal_driver() + { + $config_data = $this->config_php_file->get_all(); + if (!empty($config_data)) + { + $this->container->set('dbal.conn.driver', $this->get_dbal_connection()); + } + } + + /** * Get DB connection. * * @return \phpbb\db\driver\driver_interface @@ -320,6 +333,7 @@ class container_builder $this->config_php_file->get('dbpasswd'), $this->config_php_file->get('dbname'), $this->config_php_file->get('dbport'), + false, defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK ); } diff --git a/phpBB/phpbb/di/extension/config.php b/phpBB/phpbb/di/extension/config.php index 7984a783df..8c9de48823 100644 --- a/phpBB/phpbb/di/extension/config.php +++ b/phpBB/phpbb/di/extension/config.php @@ -43,12 +43,6 @@ class config extends Extension '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(); diff --git a/phpBB/phpbb/event/php_exporter.php b/phpBB/phpbb/event/php_exporter.php index d2ab0595c0..ae3553c558 100644 --- a/phpBB/phpbb/event/php_exporter.php +++ b/phpBB/phpbb/event/php_exporter.php @@ -510,7 +510,7 @@ class php_exporter /** * Find the "@changed" Information lines * - * @param string $tag_name Should be 'changed' or 'change' + * @param string $tag_name Should be 'change', not 'changed' * @return array Absolute line numbers * @throws \LogicException */ @@ -658,7 +658,7 @@ class php_exporter { $match = array(); $line = str_replace("\t", ' ', ltrim($line, "\t ")); - preg_match('#^\* @change(d)? (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)( (?:.*))?$#', $line, $match); + preg_match('#^\* @changed (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)( (?:.*))?$#', $line, $match); if (!isset($match[2])) { throw new \LogicException("Invalid '@changed' information for event " diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php index 76f0e3558e..e7e5f83c23 100644 --- a/phpBB/phpbb/extension/manager.php +++ b/phpBB/phpbb/extension/manager.php @@ -149,10 +149,10 @@ class manager * Instantiates the metadata manager for the extension with the given name * * @param string $name The extension name - * @param \phpbb\template\template $template The template manager + * @param \phpbb\template\template $template The template manager or null * @return \phpbb\extension\metadata_manager Instance of the metadata manager */ - public function create_extension_metadata_manager($name, \phpbb\template\template $template) + public function create_extension_metadata_manager($name, \phpbb\template\template $template = null) { return new \phpbb\extension\metadata_manager($name, $this->config, $this, $template, $this->user, $this->phpbb_root_path); } @@ -433,25 +433,11 @@ class manager if ($file_info->isFile() && $file_info->getFilename() == 'composer.json') { $ext_name = $iterator->getInnerIterator()->getSubPath(); - $composer_file = $iterator->getPath() . '/composer.json'; - - // Ignore the extension if there is no composer.json. - if (!is_readable($composer_file) || !($ext_info = file_get_contents($composer_file))) - { - continue; - } - - $ext_info = json_decode($ext_info, true); $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name); - - // Ignore the extension if directory depth is not correct or if the directory structure - // does not match the name value specified in composer.json. - if (substr_count($ext_name, '/') !== 1 || !isset($ext_info['name']) || $ext_name != $ext_info['name']) + if ($this->is_available($ext_name)) { - continue; + $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; } - - $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; } } ksort($available); @@ -524,7 +510,15 @@ class manager */ public function is_available($name) { - return file_exists($this->get_extension_path($name, true)); + $md_manager = $this->create_extension_metadata_manager($name); + try + { + return $md_manager->get_metadata('all') && $md_manager->validate_enable(); + } + catch (\phpbb\extension\exception $e) + { + return false; + } } /** diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php index 34e2910a33..a09f07bed2 100644 --- a/phpBB/phpbb/extension/metadata_manager.php +++ b/phpBB/phpbb/extension/metadata_manager.php @@ -66,17 +66,18 @@ class metadata_manager */ protected $metadata_file; + // @codingStandardsIgnoreStart /** * Creates the metadata manager * * @param string $ext_name Name (including vendor) of the extension * @param \phpbb\config\config $config phpBB Config instance * @param \phpbb\extension\manager $extension_manager An instance of the phpBB extension manager - * @param \phpbb\template\template $template phpBB Template instance + * @param \phpbb\template\template $template phpBB Template instance or null * @param \phpbb\user $user User instance * @param string $phpbb_root_path Path to the phpbb includes directory. */ - public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template, \phpbb\user $user, $phpbb_root_path) + public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template = null, \phpbb\user $user, $phpbb_root_path) { $this->config = $config; $this->extension_manager = $extension_manager; @@ -88,6 +89,7 @@ class metadata_manager $this->metadata = array(); $this->metadata_file = ''; } + // @codingStandardsIgnoreEnd /** * Processes and gets the metadata requested @@ -97,51 +99,38 @@ class metadata_manager */ public function get_metadata($element = 'all') { - $this->set_metadata_file(); - - // Fetch the metadata - $this->fetch_metadata(); - - // Clean the metadata - $this->clean_metadata_array(); + // Fetch and clean the metadata if not done yet + if ($this->metadata_file === '') + { + $this->fetch_metadata_from_file(); + } switch ($element) { case 'all': default: - // Validate the metadata - if (!$this->validate()) - { - return false; - } - + $this->validate(); return $this->metadata; break; case 'version': case 'name': - return ($this->validate($element)) ? $this->metadata[$element] : false; + $this->validate($element); + return $this->metadata[$element]; break; case 'display-name': - if (isset($this->metadata['extra']['display-name'])) - { - return $this->metadata['extra']['display-name']; - } - else - { - return ($this->validate('name')) ? $this->metadata['name'] : false; - } + return (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : $this->get_metadata('name'); break; } } /** - * Sets the filepath of the metadata file + * Sets the path of the metadata file, gets its contents and cleans loaded file * * @throws \phpbb\extension\exception */ - private function set_metadata_file() + private function fetch_metadata_from_file() { $ext_filepath = $this->extension_manager->get_extension_path($this->ext_name); $metadata_filepath = $this->phpbb_root_path . $ext_filepath . 'composer.json'; @@ -152,37 +141,19 @@ class metadata_manager { throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $this->metadata_file)); } - } - /** - * Gets the contents of the composer.json file - * - * @return bool True if success, throws an exception on failure - * @throws \phpbb\extension\exception - */ - private function fetch_metadata() - { - if (!file_exists($this->metadata_file)) + if (!($file_contents = file_get_contents($this->metadata_file))) { - throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $this->metadata_file)); + throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file)); } - else - { - if (!($file_contents = file_get_contents($this->metadata_file))) - { - throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file)); - } - - if (($metadata = json_decode($file_contents, true)) === null) - { - 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; + if (($metadata = json_decode($file_contents, true)) === null) + { + 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; } /** @@ -197,16 +168,6 @@ class metadata_manager } /** - * This array handles the cleaning of the array - * - * @return array Contains the cleaned metadata array - */ - private function clean_metadata_array() - { - return $this->metadata; - } - - /** * Validate fields * * @param string $name ("all" for display and enable validation @@ -228,10 +189,8 @@ class metadata_manager switch ($name) { case 'all': - $this->validate('display'); - $this->validate_enable(); - break; + // no break case 'display': foreach ($fields as $field => $data) @@ -288,40 +247,43 @@ class metadata_manager /** * This array handles the verification that this extension can be enabled on this board * - * @return bool True if validation succeeded, False if failed + * @return bool True if validation succeeded, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_enable() { // Check for valid directory & phpBB, PHP versions - if (!$this->validate_dir() || !$this->validate_require_phpbb() || !$this->validate_require_php()) - { - return false; - } - - return true; + return $this->validate_dir() && $this->validate_require_phpbb() && $this->validate_require_php(); } /** * Validates the most basic directory structure to ensure it follows <vendor>/<ext> convention. * - * @return boolean True when passes validation + * @return boolean True when passes validation, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_dir() { - return (substr_count($this->ext_name, '/') === 1 && $this->ext_name == $this->get_metadata('name')); + if (substr_count($this->ext_name, '/') !== 1 || $this->ext_name != $this->get_metadata('name')) + { + throw new \phpbb\extension\exception($this->user->lang('EXTENSION_DIR_INVALID')); + } + + return true; } /** * Validates the contents of the phpbb requirement field * - * @return boolean True when passes validation + * @return boolean True when passes validation, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_require_phpbb() { if (!isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) { - return false; + throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'soft-require')); } return true; @@ -330,13 +292,14 @@ class metadata_manager /** * Validates the contents of the php requirement field * - * @return boolean True when passes validation + * @return boolean True when passes validation, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_require_php() { if (!isset($this->metadata['require']['php'])) { - return false; + throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'require php')); } return true; @@ -359,10 +322,10 @@ class metadata_manager 'META_LICENSE' => $this->metadata['license'], 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? $this->metadata['require']['php'] : '', - 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(), + 'META_REQUIRE_PHP_FAIL' => (isset($this->metadata['require']['php'])) ? false : true, '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_REQUIRE_PHPBB_FAIL' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? false : true, 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '', )); diff --git a/phpBB/phpbb/feed/attachments_base.php b/phpBB/phpbb/feed/attachments_base.php index 04812f1570..df8f29a626 100644 --- a/phpBB/phpbb/feed/attachments_base.php +++ b/phpBB/phpbb/feed/attachments_base.php @@ -25,8 +25,11 @@ abstract class attachments_base extends \phpbb\feed\base /** * Retrieve the list of attachments that may be displayed + * + * @param array $post_ids Specify for which post IDs to fetch the attachments (optional) + * @param array $topic_ids Specify for which topic IDs to fetch the attachments (optional) */ - protected function fetch_attachments() + protected function fetch_attachments($post_ids = array(), $topic_ids = array()) { $sql_array = array( 'SELECT' => 'a.*', @@ -37,7 +40,20 @@ abstract class attachments_base extends \phpbb\feed\base 'ORDER_BY' => 'a.filetime DESC, a.post_msg_id ASC', ); - if (isset($this->topic_id)) + if (!empty($post_ids)) + { + $sql_array['WHERE'] .= 'AND ' . $this->db->sql_in_set('a.post_msg_id', $post_ids); + } + else if (!empty($topic_ids)) + { + if (isset($this->topic_id)) + { + $topic_ids[] = $this->topic_id; + } + + $sql_array['WHERE'] .= 'AND ' . $this->db->sql_in_set('a.topic_id', $topic_ids); + } + else if (isset($this->topic_id)) { $sql_array['WHERE'] .= 'AND a.topic_id = ' . (int) $this->topic_id; } @@ -51,6 +67,11 @@ abstract class attachments_base extends \phpbb\feed\base ); $sql_array['WHERE'] .= 'AND t.forum_id = ' . (int) $this->forum_id; } + else + { + // Do not allow querying the full attachments table + throw new \RuntimeException($this->user->lang('INVALID_FEED_ATTACHMENTS')); + } $sql = $this->db->sql_build_query('SELECT', $sql_array); $result = $this->db->sql_query($sql); @@ -64,15 +85,6 @@ abstract class attachments_base extends \phpbb\feed\base } /** - * {@inheritDoc} - */ - public function open() - { - parent::open(); - $this->fetch_attachments(); - } - - /** * Get attachments related to a given post * * @param $post_id int Post id diff --git a/phpBB/phpbb/feed/forum.php b/phpBB/phpbb/feed/forum.php index 7a2087c1cd..6aba12a147 100644 --- a/phpBB/phpbb/feed/forum.php +++ b/phpBB/phpbb/feed/forum.php @@ -112,6 +112,8 @@ class forum extends \phpbb\feed\post_base return false; } + parent::fetch_attachments(array(), $topic_ids); + $this->sql = array( 'SELECT' => 'p.post_id, p.topic_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' . 'u.username, u.user_id', diff --git a/phpBB/phpbb/feed/news.php b/phpBB/phpbb/feed/news.php index a02c199d85..5d4786518b 100644 --- a/phpBB/phpbb/feed/news.php +++ b/phpBB/phpbb/feed/news.php @@ -83,6 +83,8 @@ class news extends \phpbb\feed\topic_base return false; } + parent::fetch_attachments($post_ids); + $this->sql = array( 'SELECT' => 'f.forum_id, f.forum_name, t.topic_id, t.topic_title, t.topic_poster, t.topic_first_poster_name, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_views, t.topic_time, t.topic_last_post_time, diff --git a/phpBB/phpbb/feed/overall.php b/phpBB/phpbb/feed/overall.php index ab452f5386..1176a9c182 100644 --- a/phpBB/phpbb/feed/overall.php +++ b/phpBB/phpbb/feed/overall.php @@ -52,6 +52,8 @@ class overall extends \phpbb\feed\post_base return false; } + parent::fetch_attachments(array(), $topic_ids); + // Get the actual data $this->sql = array( 'SELECT' => 'f.forum_id, f.forum_name, ' . diff --git a/phpBB/phpbb/feed/topic.php b/phpBB/phpbb/feed/topic.php index 66c49e55cf..295bf3f795 100644 --- a/phpBB/phpbb/feed/topic.php +++ b/phpBB/phpbb/feed/topic.php @@ -91,6 +91,8 @@ class topic extends \phpbb\feed\post_base function get_sql() { + parent::fetch_attachments(); + $this->sql = array( 'SELECT' => 'p.post_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' . 'u.username, u.user_id', diff --git a/phpBB/phpbb/feed/topics.php b/phpBB/phpbb/feed/topics.php index 2b9cb3501a..e6416bc064 100644 --- a/phpBB/phpbb/feed/topics.php +++ b/phpBB/phpbb/feed/topics.php @@ -55,6 +55,8 @@ class topics extends \phpbb\feed\topic_base return false; } + parent::fetch_attachments($post_ids); + $this->sql = array( 'SELECT' => 'f.forum_id, f.forum_name, t.topic_id, t.topic_title, t.topic_poster, t.topic_first_poster_name, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_views, t.topic_time, t.topic_last_post_time, diff --git a/phpBB/phpbb/feed/topics_active.php b/phpBB/phpbb/feed/topics_active.php index 6d5eddfc16..3b751f3233 100644 --- a/phpBB/phpbb/feed/topics_active.php +++ b/phpBB/phpbb/feed/topics_active.php @@ -71,6 +71,8 @@ class topics_active extends \phpbb\feed\topic_base return false; } + parent::fetch_attachments($post_ids); + $this->sql = array( 'SELECT' => 'f.forum_id, f.forum_name, t.topic_id, t.topic_title, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_views, diff --git a/phpBB/phpbb/profilefields/type/type_date.php b/phpBB/phpbb/profilefields/type/type_date.php index 90ac9a6703..63a0c79a3d 100644 --- a/phpBB/phpbb/profilefields/type/type_date.php +++ b/phpBB/phpbb/profilefields/type/type_date.php @@ -264,7 +264,7 @@ class type_date extends type_base } $profile_row['s_year_options'] = '<option value="0"' . ((!$year) ? ' selected="selected"' : '') . '>--</option>'; - for ($i = $now['year'] - 100; $i <= $now['year'] + 100; $i++) + for ($i = 1901; $i <= $now['year'] + 50; $i++) { $profile_row['s_year_options'] .= '<option value="' . $i . '"' . (($i == $year) ? ' selected="selected"' : '') . ">$i</option>"; } diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php index 4cac6fbaea..00ff9064cb 100644 --- a/phpBB/phpbb/request/request.php +++ b/phpBB/phpbb/request/request.php @@ -169,12 +169,6 @@ class request implements \phpbb\request\request_interface $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value; } } - - if (!$this->super_globals_disabled()) - { - unset($GLOBALS[$this->super_globals[$super_global]][$var_name]); - $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value; - } } /** diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php index 9faf5ca08b..64a63e83e0 100644 --- a/phpBB/phpbb/search/fulltext_mysql.php +++ b/phpBB/phpbb/search/fulltext_mysql.php @@ -272,6 +272,27 @@ class fulltext_mysql extends \phpbb\search\base foreach ($this->split_words as $i => $word) { + // Check for not allowed search queries for InnoDB. + // We assume similar restrictions for MyISAM, which is usually even + // slower but not as restrictive as InnoDB. + // InnoDB full-text search does not support the use of a leading + // plus sign with wildcard ('+*'), a plus and minus sign + // combination ('+-'), or leading a plus and minus sign combination. + // InnoDB full-text search only supports leading plus or minus signs. + // For example, InnoDB supports '+apple' but does not support 'apple+'. + // Specifying a trailing plus or minus sign causes InnoDB to report + // a syntax error. InnoDB full-text search does not support the use + // of multiple operators on a single search word, as in this example: + // '++apple'. Use of multiple operators on a single search word + // returns a syntax error to standard out. + // Also, ensure that the wildcard character is only used at the + // end of the line as it's intended by MySQL. + if (preg_match('#^(\+[+-]|\+\*|.+[+-]$|.+\*(?!$))#', $word)) + { + unset($this->split_words[$i]); + continue; + } + $clean_word = preg_replace('#^[+\-|"]#', '', $word); // check word length @@ -942,38 +963,45 @@ class fulltext_mysql extends \phpbb\search\base $this->get_stats(); } - $alter = array(); + $alter_list = array(); if (!isset($this->stats['post_subject'])) { + $alter_entry = array(); if ($this->db->get_sql_layer() == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) { - $alter[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; + $alter_entry[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; } else { - $alter[] = 'MODIFY post_subject text NOT NULL'; + $alter_entry[] = 'MODIFY post_subject text NOT NULL'; } - $alter[] = 'ADD FULLTEXT (post_subject)'; + $alter_entry[] = 'ADD FULLTEXT (post_subject)'; + $alter_list[] = $alter_entry; } if (!isset($this->stats['post_content'])) { + $alter_entry = array(); if ($this->db->get_sql_layer() == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) { - $alter[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL'; + $alter_entry[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL'; } else { - $alter[] = 'MODIFY post_text mediumtext NOT NULL'; + $alter_entry[] = 'MODIFY post_text mediumtext NOT NULL'; } - $alter[] = 'ADD FULLTEXT post_content (post_text, post_subject)'; + $alter_entry[] = 'ADD FULLTEXT post_content (post_text, post_subject)'; + $alter_list[] = $alter_entry; } - if (sizeof($alter)) + if (sizeof($alter_list)) { - $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter)); + foreach ($alter_list as $alter) + { + $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter)); + } } $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index eb5543b50b..45e82df591 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -460,6 +460,9 @@ class session $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false; $this->data['user_lang'] = basename($this->data['user_lang']); + // Is user banned? Are they excluded? Won't return on ban, exists within method + $this->check_ban_for_current_session($config); + return true; } } @@ -666,19 +669,7 @@ class session // session exists in which case session_id will also be set // Is user banned? Are they excluded? Won't return on ban, exists within method - if ($this->data['user_type'] != USER_FOUNDER) - { - if (!$config['forwarded_for_check']) - { - $this->check_ban($this->data['user_id'], $this->ip); - } - else - { - $ips = explode(' ', $this->forwarded_for); - $ips[] = $this->ip; - $this->check_ban($this->data['user_id'], $ips); - } - } + $this->check_ban_for_current_session($config); $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; $this->data['is_bot'] = ($bot) ? true : false; @@ -1268,9 +1259,6 @@ class session $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>'; - // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again - $this->session_kill(false); - // A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page if (defined('IN_CRON')) { @@ -1279,6 +1267,9 @@ class session exit; } + // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again + $this->session_kill(false); + trigger_error($message); } @@ -1286,6 +1277,28 @@ class session } /** + * Check the current session for bans + * + * @return true if session user is banned. + */ + protected function check_ban_for_current_session($config) + { + if (!defined('SKIP_CHECK_BAN') && $this->data['user_type'] != USER_FOUNDER) + { + if (!$config['forwarded_for_check']) + { + $this->check_ban($this->data['user_id'], $this->ip); + } + else + { + $ips = explode(' ', $this->forwarded_for); + $ips[] = $this->ip; + $this->check_ban($this->data['user_id'], $ips); + } + } + } + + /** * Check if ip is blacklisted * This should be called only where absolutely necessary * @@ -1576,7 +1589,7 @@ class session } // Only update session DB a minute or so after last update or if page changes - if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) + if ($this->time_now - ((isset($this->data['session_time'])) ? $this->data['session_time'] : 0) > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) { $sql_ary = array('session_time' => $this->time_now); diff --git a/phpBB/phpbb/template/base.php b/phpBB/phpbb/template/base.php index 9a40702ba8..41c0a01ba8 100644 --- a/phpBB/phpbb/template/base.php +++ b/phpBB/phpbb/template/base.php @@ -133,6 +133,14 @@ abstract class base implements template } /** + * {@inheritdoc} + */ + public function find_key_index($blockname, $key) + { + return $this->context->find_key_index($blockname, $key); + } + + /** * Calls hook if any is defined. * * @param string $handle Template handle being displayed. diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php index 4ee48205c8..5d04a09865 100644 --- a/phpBB/phpbb/template/context.php +++ b/phpBB/phpbb/template/context.php @@ -264,6 +264,89 @@ class context } /** + * Find the index for a specified key in the innermost specified block + * + * @param string $blockname the blockname, for example 'loop' + * @param mixed $key Key to search for + * + * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] + * + * int: Position [the position to search for] + * + * If key is false the position is set to 0 + * If key is true the position is set to the last entry + * + * @return mixed false if not found, index position otherwise; be sure to test with === + */ + public function find_key_index($blockname, $key) + { + // For nested block, $blockcount > 0, for top-level block, $blockcount == 0 + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $block = $this->tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + if (($pos = strpos($blocks[$i], '[')) !== false) + { + $name = substr($blocks[$i], 0, $pos); + + if (strpos($blocks[$i], '[]') === $pos) + { + $index = sizeof($block[$name]) - 1; + } + else + { + $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); + } + } + else + { + $name = $blocks[$i]; + $index = sizeof($block[$name]) - 1; + } + if (!isset($block[$name])) + { + return false; + } + $block = $block[$name]; + if (!isset($block[$index])) + { + return false; + } + $block = $block[$index]; + } + + if (!isset($block[$blocks[$i]])) + { + return false; + } + $block = $block[$blocks[$i]]; // Traverse the last block + + // Change key to zero (change first position) if false and to last position if true + if ($key === false || $key === true) + { + return ($key === false) ? 0 : sizeof($block) - 1; + } + + // Get correct position if array given + if (is_array($key)) + { + // Search array to get correct position + list($search_key, $search_value) = @each($key); + foreach ($block as $i => $val_ary) + { + if ($val_ary[$search_key] === $search_value) + { + return $i; + } + } + } + + return (is_int($key) && ((0 <= $key) && ($key < sizeof($block)))) ? $key : false; + } + + /** * Change already assigned key variable pair (one-dimensional - single loop entry) * * An example of how to use this function: @@ -293,45 +376,49 @@ class context public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') { $this->num_rows_is_set = false; - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - $block = &$this->tpldata; - for ($i = 0; $i < $blockcount; $i++) + // For nested block, $blockcount > 0, for top-level block, $blockcount == 0 + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $block = &$this->tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + if (($pos = strpos($blocks[$i], '[')) !== false) { - if (($pos = strpos($blocks[$i], '[')) !== false) + $name = substr($blocks[$i], 0, $pos); + + if (strpos($blocks[$i], '[]') === $pos) { - $name = substr($blocks[$i], 0, $pos); - - if (strpos($blocks[$i], '[]') === $pos) - { - $index = sizeof($block[$name]) - 1; - } - else - { - $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); - } + $index = sizeof($block[$name]) - 1; } else { - $name = $blocks[$i]; - $index = sizeof($block[$name]) - 1; + $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); } - $block = &$block[$name]; - $block = &$block[$index]; } - - $block = &$block[$blocks[$i]]; // Traverse the last block + else + { + $name = $blocks[$i]; + $index = sizeof($block[$name]) - 1; + } + $block = &$block[$name]; + $block = &$block[$index]; } - else + $name = $blocks[$i]; + + // If last block does not exist and we are inserting, and not searching for key, we create it empty; otherwise, nothing to do + if (!isset($block[$name])) { - // Top-level block. - $block = &$this->tpldata[$blockname]; + if ($mode != 'insert' || is_array($key)) + { + return false; + } + $block[$name] = array(); } + $block = &$block[$name]; // Now we can traverse the last block + // Change key to zero (change first position) if false and to last position if true if ($key === false || $key === true) { @@ -365,20 +452,21 @@ class context if ($mode == 'insert') { // Make sure we are not exceeding the last iteration - if ($key >= sizeof($this->tpldata[$blockname])) + if ($key >= sizeof($block)) { - $key = sizeof($this->tpldata[$blockname]); - unset($this->tpldata[$blockname][($key - 1)]['S_LAST_ROW']); + $key = sizeof($block); + unset($block[($key - 1)]['S_LAST_ROW']); $vararray['S_LAST_ROW'] = true; } - else if ($key === 0) + if ($key <= 0) { - unset($this->tpldata[$blockname][0]['S_FIRST_ROW']); + $key = 0; + unset($block[0]['S_FIRST_ROW']); $vararray['S_FIRST_ROW'] = true; } // Assign S_BLOCK_NAME - $vararray['S_BLOCK_NAME'] = $blockname; + $vararray['S_BLOCK_NAME'] = $name; // Re-position template blocks for ($i = sizeof($block); $i > $key; $i--) @@ -398,6 +486,12 @@ class context // Which block to change? if ($mode == 'change') { + // If key is out of bounds, do not change anything + if ($key > sizeof($block) || $key < 0) + { + return false; + } + if ($key == sizeof($block)) { $key--; diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php index 041ecb12e4..9e3d658ca8 100644 --- a/phpBB/phpbb/template/template.php +++ b/phpBB/phpbb/template/template.php @@ -173,6 +173,23 @@ interface template public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert'); /** + * Find the index for a specified key in the innermost specified block + * + * @param string $blockname the blockname, for example 'loop' + * @param mixed $key Key to search for + * + * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] + * + * int: Position [the position to search for] + * + * If key is false the position is set to 0 + * If key is true the position is set to the last entry + * + * @return mixed false if not found, index position otherwise; be sure to test with === + */ + public function find_key_index($blockname, $key); + + /** * Get path to template for handle (required for BBCode parser) * * @param string $handle Handle to retrieve the source file diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php index 3a983491b9..d5b14129b5 100644 --- a/phpBB/phpbb/template/twig/extension.php +++ b/phpBB/phpbb/template/twig/extension.php @@ -169,8 +169,7 @@ class extension extends \Twig_Extension $args = func_get_args(); $key = $args[0]; - $context = $this->context->get_data_ref(); - $context_vars = $context['.'][0]; + $context_vars = $this->context->get_root_ref(); if (isset($context_vars['L_' . $key])) { diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php index 70a009ed3d..7e5edbf522 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -201,7 +201,7 @@ class version_helper $self = $this; $current_version = $this->current_version; - // Filter out any versions less than to the current version + // Filter out any versions less than the current version $versions = array_filter($versions, function($data) use ($self, $current_version) { return $self->compare($data['current'], $current_version, '>='); }); @@ -218,11 +218,117 @@ class version_helper } /** + * Gets the latest update for the current branch the user is on + * Will suggest versions from newer branches when EoL has been reached + * and/or version from newer branch is needed for having all known security + * issues fixed. + * + * @param bool $force_update Ignores cached data. Defaults to false. + * @param bool $force_cache Force the use of the cache. Override $force_update. + * @return array Version info or empty array if there are no updates + * @throws \RuntimeException + */ + public function get_update_on_branch($force_update = false, $force_cache = false) + { + $versions = $this->get_versions_matching_stability($force_update, $force_cache); + + $self = $this; + $current_version = $this->current_version; + + // Filter out any versions less than the current version + $versions = array_filter($versions, function($data) use ($self, $current_version) { + return $self->compare($data['current'], $current_version, '>='); + }); + + // Get the lowest version from the previous list. + $update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) { + if ($value === null && $self->compare($data['current'], $current_version, '>=')) + { + if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<='))) + { + return ($self->compare($data['current'], $current_version, '>')) ? $data : array(); + } + else + { + return null; + } + } + + return $value; + }); + + return $update_info === null ? array() : $update_info; + } + + /** + * Gets the latest extension update for the current phpBB branch the user is on + * Will suggest versions from newer branches when EoL has been reached + * and/or version from newer branch is needed for having all known security + * issues fixed. + * + * @param bool $force_update Ignores cached data. Defaults to false. + * @param bool $force_cache Force the use of the cache. Override $force_update. + * @return array Version info or empty array if there are no updates + * @throws \RuntimeException + */ + public function get_ext_update_on_branch($force_update = false, $force_cache = false) + { + $versions = $this->get_versions_matching_stability($force_update, $force_cache); + + $self = $this; + $current_version = $this->current_version; + + // Get current phpBB branch from version, e.g.: 3.2 + preg_match('/^(\d+\.\d+).*$/', $this->config['version'], $matches); + $current_branch = $matches[1]; + + // Filter out any versions less than the current version + $versions = array_filter($versions, function($data) use ($self, $current_version) { + return $self->compare($data['current'], $current_version, '>='); + }); + + // Filter out any phpbb branches less than the current version + $branches = array_filter(array_keys($versions), function($branch) use ($self, $current_branch) { + return $self->compare($branch, $current_branch, '>='); + }); + if (!empty($branches)) + { + $versions = array_intersect_key($versions, array_flip($branches)); + } + else + { + // If branches are empty, it means the current phpBB branch is newer than any branch the + // extension was validated against. Reverse sort the versions array so we get the newest + // validated release available. + krsort($versions); + } + + // Get the first available version from the previous list. + $update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) { + if ($value === null && $self->compare($data['current'], $current_version, '>=')) + { + if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<='))) + { + return $self->compare($data['current'], $current_version, '>') ? $data : array(); + } + else + { + return null; + } + } + + return $value; + }); + + return $update_info === null ? array() : $update_info; + } + + /** * Obtains the latest version information * * @param bool $force_update Ignores cached data. Defaults to false. * @param bool $force_cache Force the use of the cache. Override $force_update. - * @return string + * @return array * @throws \RuntimeException */ public function get_suggested_updates($force_update = false, $force_cache = false) @@ -263,7 +369,7 @@ class version_helper * * @param bool $force_update Ignores cached data. Defaults to false. * @param bool $force_cache Force the use of the cache. Override $force_update. - * @return string Version info, includes stable and unstable data + * @return array Version info, includes stable and unstable data * @throws \RuntimeException */ public function get_versions($force_update = false, $force_cache = false) |