diff options
Diffstat (limited to 'phpBB/phpbb')
55 files changed, 1182 insertions, 336 deletions
diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php index fc7cc1a0b1..dbd83f1eb0 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/avatar/driver/upload.php b/phpBB/phpbb/avatar/driver/upload.php index 2640e1ad1e..4effa4c410 100644 --- a/phpBB/phpbb/avatar/driver/upload.php +++ b/phpBB/phpbb/avatar/driver/upload.php @@ -281,12 +281,20 @@ class upload extends \phpbb\avatar\driver\driver ); extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars))); - if (!sizeof($error) && file_exists($filename)) + if (!sizeof($error) && $this->filesystem->exists($filename)) { - @unlink($filename); + try + { + $this->filesystem->remove($filename); + return true; + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Fail is covered by return statement below + } } - return true; + return false; } /** @@ -304,6 +312,6 @@ class upload extends \phpbb\avatar\driver\driver */ protected function can_upload() { - return (file_exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')); + return ($this->filesystem->exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')); } } diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php index a210d877f0..497f00c06b 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -608,6 +608,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/memcached.php b/phpBB/phpbb/cache/driver/memcached.php new file mode 100644 index 0000000000..105e763af4 --- /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) + { + $parts = explode('/', $u); + $this->memcached->addServer(trim($parts[0]), trim($parts[1])); + } + } + + /** + * {@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/extension/disable.php b/phpBB/phpbb/console/command/extension/disable.php index d022755753..b2e10fb960 100644 --- a/phpBB/phpbb/console/command/extension/disable.php +++ b/phpBB/phpbb/console/command/extension/disable.php @@ -37,6 +37,13 @@ class disable extends command $io = new SymfonyStyle($input, $output); $name = $input->getArgument('extension-name'); + + if (!$this->manager->is_enabled($name)) + { + $io->error($this->user->lang('CLI_EXTENSION_DISABLED', $name)); + return 2; + } + $this->manager->disable($name); $this->manager->load_extensions(); diff --git a/phpBB/phpbb/console/command/extension/enable.php b/phpBB/phpbb/console/command/extension/enable.php index 14077d688b..a8312d5c15 100644 --- a/phpBB/phpbb/console/command/extension/enable.php +++ b/phpBB/phpbb/console/command/extension/enable.php @@ -37,6 +37,13 @@ class enable extends command $io = new SymfonyStyle($input, $output); $name = $input->getArgument('extension-name'); + + if ($this->manager->is_enabled($name)) + { + $io->error($this->user->lang('CLI_EXTENSION_ENABLED', $name)); + return 2; + } + $this->manager->enable($name); $this->manager->load_extensions(); diff --git a/phpBB/phpbb/console/command/update/check.php b/phpBB/phpbb/console/command/update/check.php index 1f1cfa25d2..ed8ad79eea 100644 --- a/phpBB/phpbb/console/command/update/check.php +++ b/phpBB/phpbb/console/command/update/check.php @@ -134,7 +134,7 @@ class check extends \phpbb\console\command\command try { $ext_manager = $this->phpbb_container->get('ext.manager'); - $md_manager = $ext_manager->create_extension_metadata_manager($ext_name, null); + $md_manager = $ext_manager->create_extension_metadata_manager($ext_name); $updates_available = $ext_manager->version_check($md_manager, $recheck, false, $stability); $metadata = $md_manager->get_metadata('all'); 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/v320/add_help_phpbb.php b/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php index afa67fbc58..8fadb4bde4 100644 --- a/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php +++ b/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php @@ -32,10 +32,9 @@ class add_help_phpbb extends \phpbb\db\migration\migration return array( array('config.add', array('help_send_statistics', true)), array('config.add', array('help_send_statistics_time', 0)), - array('module.remove', array( - 'acp', - false, - 'ACP_SEND_STATISTICS', + array('if', array( + array('module.exists', array('acp', false, 'ACP_SEND_STATISTICS')), + array('module.remove', array('acp', false, 'ACP_SEND_STATISTICS')), )), array('module.add', array( 'acp', diff --git a/phpBB/phpbb/db/migration/data/v320/cookie_notice.php b/phpBB/phpbb/db/migration/data/v320/cookie_notice.php new file mode 100644 index 0000000000..75cb03b3ef --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v320/cookie_notice.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\v320; + +class cookie_notice extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v320\v320rc2', + ); + } + + public function update_data() + { + return array( + array('config.add', array('cookie_notice', false)), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v320/v320.php b/phpBB/phpbb/db/migration/data/v320/v320.php new file mode 100644 index 0000000000..20e741cb8b --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v320/v320.php @@ -0,0 +1,40 @@ +<?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\v320; + +use phpbb\db\migration\migration; + +class v320 extends migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.2.0', '>='); + } + + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\increase_size_of_emotion', + '\phpbb\db\migration\data\v320\cookie_notice', + ); + + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.2.0')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v32x/cookie_notice_p2.php b/phpBB/phpbb/db/migration/data/v32x/cookie_notice_p2.php new file mode 100644 index 0000000000..1a83175705 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v32x/cookie_notice_p2.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\data\v32x; + +class cookie_notice_p2 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v320\v320', + ); + } + + public function effectively_installed() + { + return isset($this->config['cookie_notice']); + } + + public function update_data() + { + return array( + array('config.add', array('cookie_notice', '0')), + ); + } +} diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php new file mode 100644 index 0000000000..4d1b91f7b4 --- /dev/null +++ b/phpBB/phpbb/db/tools.php @@ -0,0 +1,21 @@ +<?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; + +/** + * @deprecated 3.2.0-dev (To be removed 3.3.0) use \phpbb\db\tools\tools instead + */ +class tools extends \phpbb\db\tools\tools +{ +} diff --git a/phpBB/phpbb/db/tools/mssql.php b/phpBB/phpbb/db/tools/mssql.php index a132832005..d31aa2ba0b 100644 --- a/phpBB/phpbb/db/tools/mssql.php +++ b/phpBB/phpbb/db/tools/mssql.php @@ -477,7 +477,7 @@ class mssql extends tools { $statements = array(); - $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name; + $statements[] = 'DROP INDEX [' . $table_name . '].[' . $index_name . ']'; return $this->_sql_run_sql($statements); } @@ -524,7 +524,10 @@ class mssql extends tools { $statements = array(); - $this->check_index_name_length($table_name, $index_name); + if ($this->is_sql_server_2000()) + { + $this->check_index_name_length($table_name, $index_name); + } $statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])'; @@ -538,7 +541,10 @@ class mssql extends tools { $statements = array(); - $this->check_index_name_length($table_name, $index_name); + if ($this->is_sql_server_2000()) + { + $this->check_index_name_length($table_name, $index_name); + } // remove index length $column = preg_replace('#:.*$#', '', $column); @@ -601,7 +607,7 @@ class mssql extends tools // Change the column $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; - if (!empty($column_data['default'])) + if (!empty($column_data['default']) && !$this->mssql_is_column_identity($table_name, $column_name)) { // Add new default value constraint $statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $column_data['default'] . ' FOR [' . $column_name . ']'; @@ -679,6 +685,37 @@ class mssql extends tools } /** + * Checks to see if column is an identity column + * + * Identity columns cannot have defaults set for them. + * + * @param string $table_name + * @param string $column_name + * @return bool true if identity, false if not + */ + protected function mssql_is_column_identity($table_name, $column_name) + { + if ($this->mssql_is_sql_server_2000()) + { + // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx + // Deprecated in SQL Server 2005 + $sql = "SELECT COLUMNPROPERTY(object_id('{$table_name}'), '{$column_name}', 'IsIdentity') AS is_identity"; + } + else + { + $sql = "SELECT is_identity FROM sys.columns + WHERE object_id = object_id('{$table_name}') + AND name = '{$column_name}'"; + } + + $result = $this->db->sql_query($sql); + $is_identity = $this->db->sql_fetchfield('is_identity'); + $this->db->sql_freeresult($result); + + return (bool) $is_identity; + } + + /** * Get a list with existing indexes for the column * * @param string $table_name @@ -717,6 +754,7 @@ class mssql extends tools AND cols.object_id = ix.object_id WHERE ix.object_id = object_id('{$table_name}') AND cols.name = '{$column_name}' + AND ix.is_primary_key = 0 AND ix.is_unique = " . ($unique ? '1' : '0'); } diff --git a/phpBB/phpbb/di/container_builder.php b/phpBB/phpbb/di/container_builder.php index 4d5f189f12..ac1a1a1733 100644 --- a/phpBB/phpbb/di/container_builder.php +++ b/phpBB/phpbb/di/container_builder.php @@ -51,6 +51,11 @@ class container_builder protected $container; /** + * @var \phpbb\db\driver\driver_interface + */ + protected $dbal_connection = null; + + /** * Indicates whether extensions should be used (default to true). * * @var bool @@ -197,6 +202,8 @@ class container_builder $this->container->set('config.php', $this->config_php_file); } + $this->inject_dbal_driver(); + return $this->container; } catch (\Exception $e) @@ -511,7 +518,38 @@ class container_builder { $this->container->setParameter($key, $value); } + } + /** + * Inject the dbal connection driver into container + */ + protected function inject_dbal_driver() + { + if (empty($this->config_php_file)) + { + return; + } + + $config_data = $this->config_php_file->get_all(); + if (!empty($config_data)) + { + if ($this->dbal_connection === null) + { + $dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms')); + /** @var \phpbb\db\driver\driver_interface $dbal_connection */ + $this->dbal_connection = new $dbal_driver_class(); + $this->dbal_connection->sql_connect( + $this->config_php_file->get('dbhost'), + $this->config_php_file->get('dbuser'), + $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 + ); + } + $this->container->set('dbal.conn.driver', $this->dbal_connection); + } } /** 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/di/extension/core.php b/phpBB/phpbb/di/extension/core.php index 29c0b0e44e..67150f0103 100644 --- a/phpBB/phpbb/di/extension/core.php +++ b/phpBB/phpbb/di/extension/core.php @@ -24,7 +24,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension; */ class core extends Extension { - const TWIG_OPTIONS_POSITION = 6; + const TWIG_OPTIONS_POSITION = 7; /** * Config path diff --git a/phpBB/phpbb/di/proxy_instantiator.php b/phpBB/phpbb/di/proxy_instantiator.php index a388e82c0e..70295a3dec 100644 --- a/phpBB/phpbb/di/proxy_instantiator.php +++ b/phpBB/phpbb/di/proxy_instantiator.php @@ -13,8 +13,6 @@ namespace phpbb\di; -use bantu\IniGetWrapper\IniGetWrapper; -use phpbb\filesystem\filesystem; use ProxyManager\Configuration; use ProxyManager\Factory\LazyLoadingValueHolderFactory; use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy; @@ -45,11 +43,8 @@ class proxy_instantiator implements InstantiatorInterface // Prevent trying to write to system temp dir in case of open_basedir // restrictions being in effect - $ini_wrapper = new IniGetWrapper(); - $filesystem = new filesystem(); $tmp_dir = (function_exists('sys_get_temp_dir')) ? sys_get_temp_dir() : ''; - if (empty($tmp_dir) || $ini_wrapper->getString('open_basedir') && - (!$filesystem->exists($tmp_dir) || !$filesystem->is_writable($tmp_dir))) + if (empty($tmp_dir) || !@file_exists($tmp_dir) || !@is_writable($tmp_dir)) { $config->setProxiesTargetDir($cache_dir); } diff --git a/phpBB/phpbb/event/data.php b/phpBB/phpbb/event/data.php index c7365aee35..276ab027f2 100644 --- a/phpBB/phpbb/event/data.php +++ b/phpBB/phpbb/event/data.php @@ -63,4 +63,16 @@ class data extends Event implements \ArrayAccess { unset($this->data[$offset]); } + + /** + * Returns data with updated key in specified offset. + * + * @param string $subarray Data array subarray + * @param string $key Subarray key + * @param mixed $value Value to update + */ + public function update_subarray($subarray, $key, $value) + { + $this->data[$subarray][$key] = $value; + } } 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 b2b60aaa9b..4b4109bd85 100644 --- a/phpBB/phpbb/extension/manager.php +++ b/phpBB/phpbb/extension/manager.php @@ -152,7 +152,12 @@ class manager */ public function create_extension_metadata_manager($name) { - return new \phpbb\extension\metadata_manager($name, $this->config, $this, $this->phpbb_root_path); + if (!isset($this->extensions[$name]['metadata'])) + { + $metadata = new \phpbb\extension\metadata_manager($name, $this->get_extension_path($name, true)); + $this->extensions[$name]['metadata'] = $metadata; + } + return $this->extensions[$name]['metadata']; } /** @@ -168,7 +173,7 @@ class manager public function enable_step($name) { // ignore extensions that are already enabled - if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active']) + if ($this->is_enabled($name)) { return false; } @@ -257,8 +262,8 @@ class manager */ public function disable_step($name) { - // ignore extensions that are already disabled - if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active']) + // ignore extensions that are not enabled + if (!$this->is_enabled($name)) { return false; } @@ -336,8 +341,8 @@ class manager */ public function purge_step($name) { - // ignore extensions that do not exist - if (!isset($this->extensions[$name])) + // ignore extensions that are not configured + if (!$this->is_configured($name)) { return false; } @@ -431,25 +436,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->get_extension_path($ext_name, true); } - - $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; } } ksort($available); @@ -472,8 +463,12 @@ class manager $configured = array(); foreach ($this->extensions as $name => $data) { - $data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; - $configured[$name] = $data; + if ($this->is_configured($name)) + { + unset($data['metadata']); + $data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; + $configured[$name] = $data; + } } return $configured; } @@ -490,7 +485,7 @@ class manager $enabled = array(); foreach ($this->extensions as $name => $data) { - if ($data['ext_active']) + if ($this->is_enabled($name)) { $enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; } @@ -511,7 +506,7 @@ class manager $disabled = array(); foreach ($this->extensions as $name => $data) { - if (!$data['ext_active']) + if ($this->is_disabled($name)) { $disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; } @@ -527,7 +522,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; + } } /** @@ -538,7 +541,7 @@ class manager */ public function is_enabled($name) { - return isset($this->extensions[$name]) && $this->extensions[$name]['ext_active']; + return isset($this->extensions[$name]['ext_active']) && $this->extensions[$name]['ext_active']; } /** @@ -549,7 +552,7 @@ class manager */ public function is_disabled($name) { - return isset($this->extensions[$name]) && !$this->extensions[$name]['ext_active']; + return isset($this->extensions[$name]['ext_active']) && !$this->extensions[$name]['ext_active']; } /** @@ -563,7 +566,7 @@ class manager */ public function is_configured($name) { - return isset($this->extensions[$name]); + return isset($this->extensions[$name]['ext_active']); } /** @@ -573,7 +576,7 @@ class manager * @param bool $force_update Ignores cached data. Defaults to false. * @param bool $force_cache Force the use of the cache. Override $force_update. * @param string $stability Force the stability (null by default). - * @return string + * @return array * @throws runtime_exception */ public function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false, $stability = null) @@ -589,10 +592,10 @@ class manager $version_helper = new \phpbb\version_helper($this->cache, $this->config, new file_downloader()); $version_helper->set_current_version($meta['version']); - $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename']); + $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename'], isset($version_check['ssl']) ? $version_check['ssl'] : false); $version_helper->force_stability($stability); - return $updates = $version_helper->get_suggested_updates($force_update, $force_cache); + return $version_helper->get_ext_update_on_branch($force_update, $force_cache); } /** diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php index 2b8b1bbd6a..60b8db8310 100644 --- a/phpBB/phpbb/extension/metadata_manager.php +++ b/phpBB/phpbb/extension/metadata_manager.php @@ -19,24 +19,6 @@ namespace phpbb\extension; class metadata_manager { /** - * phpBB Config instance - * @var \phpbb\config\config - */ - protected $config; - - /** - * phpBB Extension Manager - * @var \phpbb\extension\manager - */ - protected $extension_manager; - - /** - * phpBB root path - * @var string - */ - protected $phpbb_root_path; - - /** * Name (including vendor) of the extension * @var string */ @@ -58,19 +40,13 @@ class metadata_manager * 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 string $phpbb_root_path Path to the phpbb includes directory. + * @param string $ext_path Path to the extension directory including root path */ - public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, $phpbb_root_path) + public function __construct($ext_name, $ext_path) { - $this->config = $config; - $this->extension_manager = $extension_manager; - $this->phpbb_root_path = $phpbb_root_path; - $this->ext_name = $ext_name; $this->metadata = array(); - $this->metadata_file = ''; + $this->metadata_file = $ext_path . 'composer.json'; } /** @@ -81,92 +57,56 @@ 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 === array()) + { + $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 + * Gets the metadata file 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'; - - $this->metadata_file = $metadata_filepath; - if (!file_exists($this->metadata_file)) { throw new \phpbb\extension\exception('FILE_NOT_FOUND', array($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('FILE_NOT_FOUND', array($this->metadata_file)); + throw new \phpbb\extension\exception('FILE_CONTENT_ERR', array($this->metadata_file)); } - else - { - if (!($file_contents = file_get_contents($this->metadata_file))) - { - throw new \phpbb\extension\exception('FILE_CONTENT_ERR', array($this->metadata_file)); - } - - if (($metadata = json_decode($file_contents, true)) === null) - { - throw new \phpbb\extension\exception('FILE_JSON_DECODE_ERR', array($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('FILE_JSON_DECODE_ERR', array($this->metadata_file)); } + + array_walk_recursive($metadata, array($this, 'sanitize_json')); + $this->metadata = $metadata; } /** @@ -181,16 +121,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 @@ -212,10 +142,8 @@ class metadata_manager switch ($name) { case 'all': - $this->validate('display'); - $this->validate_enable(); - break; + // no break case 'display': foreach ($fields as $field => $data) @@ -272,40 +200,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('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('META_FIELD_NOT_SET', array('soft-require')); } return true; @@ -314,51 +245,16 @@ 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('META_FIELD_NOT_SET', array('require php')); } return true; } - - /** - * Outputs the metadata into the template - * - * @param \phpbb\template\template $template phpBB Template instance - */ - public function output_template_data(\phpbb\template\template $template) - { - $template->assign_vars(array( - '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'])) ? $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'])) ? $this->metadata['require']['php'] : '', - 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(), - - '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'])) ? $this->metadata['extra']['display-name'] : '', - )); - - foreach ($this->metadata['authors'] as $author) - { - $template->assign_block_vars('meta_authors', array( - 'AUTHOR_NAME' => $author['name'], - 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '', - 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '', - 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '', - )); - } - } } diff --git a/phpBB/phpbb/feed/attachments_base.php b/phpBB/phpbb/feed/attachments_base.php index b14dafe15a..5d3272e0d9 100644 --- a/phpBB/phpbb/feed/attachments_base.php +++ b/phpBB/phpbb/feed/attachments_base.php @@ -25,8 +25,11 @@ abstract class attachments_base extends 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 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 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 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 f522e91169..0c142e8cc8 100644 --- a/phpBB/phpbb/feed/forum.php +++ b/phpBB/phpbb/feed/forum.php @@ -138,6 +138,8 @@ class forum extends 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 fb6fa09278..13ca82c093 100644 --- a/phpBB/phpbb/feed/news.php +++ b/phpBB/phpbb/feed/news.php @@ -90,6 +90,8 @@ class news extends 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 40cf94ace0..b083df922d 100644 --- a/phpBB/phpbb/feed/overall.php +++ b/phpBB/phpbb/feed/overall.php @@ -55,6 +55,8 @@ class overall extends 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 e5f2c41468..2504e411b1 100644 --- a/phpBB/phpbb/feed/topic.php +++ b/phpBB/phpbb/feed/topic.php @@ -126,6 +126,8 @@ class topic extends post_base */ protected 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 cf4a2e579e..183c29d11c 100644 --- a/phpBB/phpbb/feed/topics.php +++ b/phpBB/phpbb/feed/topics.php @@ -58,6 +58,8 @@ class topics extends 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 52340dc2d5..7ae0bde56b 100644 --- a/phpBB/phpbb/feed/topics_active.php +++ b/phpBB/phpbb/feed/topics_active.php @@ -77,6 +77,8 @@ class topics_active extends 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/install/helper/file_updater/ftp_file_updater.php b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php index 258a035768..5cdc331cbc 100644 --- a/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php +++ b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php @@ -47,7 +47,7 @@ class ftp_file_updater implements file_updater_interface * @param string $phpbb_root_path * @param string $php_ext */ - public function __constructor(update_helper $update_helper, $phpbb_root_path, $php_ext) + public function __construct(update_helper $update_helper, $phpbb_root_path, $php_ext) { $this->transfer = null; $this->update_helper = $update_helper; diff --git a/phpBB/phpbb/install/module/install_data/task/create_search_index.php b/phpBB/phpbb/install/module/install_data/task/create_search_index.php new file mode 100644 index 0000000000..8a2f6aa1de --- /dev/null +++ b/phpBB/phpbb/install/module/install_data/task/create_search_index.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\install\module\install_data\task; + +use phpbb\auth\auth; +use phpbb\db\driver\driver_interface; +use phpbb\event\dispatcher; +use phpbb\config\config; +use phpbb\install\helper\container_factory; +use phpbb\language\language; +use phpbb\search\fulltext_native; +use phpbb\user; + +class create_search_index extends \phpbb\install\task_base +{ + /** + * @var auth + */ + protected $auth; + + /** + * @var config + */ + protected $config; + + /** + * @var driver_interface + */ + protected $db; + + /** + * @var dispatcher + */ + protected $phpbb_dispatcher; + + /** + * @var language + */ + protected $language; + + /** + * @var user + */ + protected $user; + + /** + * @var string phpBB root path + */ + protected $phpbb_root_path; + + /** + * @var string PHP file extension + */ + protected $php_ext; + + /** + * Constructor + * + * @param config $config phpBB config + * @param container_factory $container Installer's DI container + * @param string $phpbb_root_path phpBB root path + * @param string $php_ext PHP file extension + */ + public function __construct(config $config, container_factory $container, + $phpbb_root_path, $php_ext) + { + $this->auth = $container->get('auth'); + $this->config = $config; + $this->db = $container->get('dbal.conn'); + $this->language = $container->get('language'); + $this->phpbb_dispatcher = $container->get('dispatcher'); + $this->user = $container->get('user'); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Make sure fulltext native load update is set + $this->config->set('fulltext_native_load_upd', 1); + + $error = false; + $search = new fulltext_native( + $error, + $this->phpbb_root_path, + $this->php_ext, + $this->auth, + $this->config, + $this->db, + $this->user, + $this->phpbb_dispatcher + ); + + $sql = 'SELECT post_id, post_subject, post_text, poster_id, forum_id + FROM ' . POSTS_TABLE; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + $search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']); + } + $this->db->sql_freeresult($result); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_CREATE_SEARCH_INDEX'; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php index 1cb4f04297..e8a9c971b7 100644 --- a/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php @@ -84,7 +84,7 @@ class obtain_email_data extends \phpbb\install\task_base implements \phpbb\insta $email_form = array( 'email_enable' => array( 'label' => 'ENABLE_EMAIL', - 'description' => 'COOKIE_SECURE_EXPLAIN', + 'description' => 'ENABLE_EMAIL_EXPLAIN', 'type' => 'radio', 'options' => array( array( diff --git a/phpBB/phpbb/install/module/update_database/task/update_extensions.php b/phpBB/phpbb/install/module/update_database/task/update_extensions.php index 13c1591dcd..b66847b243 100644 --- a/phpBB/phpbb/install/module/update_database/task/update_extensions.php +++ b/phpBB/phpbb/install/module/update_database/task/update_extensions.php @@ -138,7 +138,7 @@ class update_extensions extends task_base $default_update_extensions = []; foreach (self::$default_extensions_update as $version => $extensions) { - if ($this->update_helper->phpbb_version_compare($version_from, $version, '<=')) + if ($this->update_helper->phpbb_version_compare($version_from, $version, '<')) { $default_update_extensions = array_merge($default_update_extensions, $extensions); } diff --git a/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php index e3e6db6263..1792a3b723 100644 --- a/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php +++ b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php @@ -132,41 +132,62 @@ class diff_files extends task_base $file_contents = array(); // Handle the special case when user created a file with the filename that is now new in the core - $file_contents[0] = (file_exists($old_path . $filename)) ? file_get_contents($old_path . $filename) : ''; + if (file_exists($old_path . $filename)) + { + $file_contents[0] = file_get_contents($old_path . $filename); - $filenames = array( - $this->phpbb_root_path . $filename, - $new_path . $filename - ); + $filenames = array( + $this->phpbb_root_path . $filename, + $new_path . $filename + ); - foreach ($filenames as $file_to_diff) - { - $file_contents[] = file_get_contents($file_to_diff); + foreach ($filenames as $file_to_diff) + { + $file_contents[] = file_get_contents($file_to_diff); + + if ($file_contents[sizeof($file_contents) - 1] === false) + { + $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff)); + unset($file_contents); + throw new user_interaction_required_exception(); + } + } - if ($file_contents[sizeof($file_contents) - 1] === false) + $diff = new \diff3($file_contents[0], $file_contents[1], $file_contents[2]); + unset($file_contents); + + // Handle conflicts + if ($diff->get_num_conflicts() !== 0) { - $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff)); - unset($file_contents); - throw new user_interaction_required_exception(); + $merge_conflicts[] = $filename; } - } - $diff = new \diff3($file_contents[0], $file_contents[1], $file_contents[2]); - unset($file_contents); + // Save merged output + $this->cache->put( + '_file_' . md5($filename), + base64_encode(implode("\n", $diff->merged_output())) + ); - // Handle conflicts - if ($diff->get_num_conflicts() !== 0) - { - $merge_conflicts[] = $filename; + unset($diff); } + else + { + $new_file_content = file_get_contents($new_path . $filename); - // Save merged output - $this->cache->put( - '_file_' . md5($filename), - base64_encode(implode("\n", $diff->merged_output())) - ); + if ($new_file_content === false) + { + $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff)); + unset($new_file_content ); + throw new user_interaction_required_exception(); + } - unset($diff); + // Save new file content to cache + $this->cache->put( + '_file_' . md5($filename), + base64_encode($new_file_content) + ); + unset($new_file_content); + } $progress_count++; $this->iohandler->set_progress('UPDATE_FILE_DIFF', $progress_count); diff --git a/phpBB/phpbb/install/module/update_filesystem/task/file_check.php b/phpBB/phpbb/install/module/update_filesystem/task/file_check.php index 5b48350e73..47a71eb844 100644 --- a/phpBB/phpbb/install/module/update_filesystem/task/file_check.php +++ b/phpBB/phpbb/install/module/update_filesystem/task/file_check.php @@ -123,7 +123,7 @@ class file_check extends task_base $default_update_extensions = []; foreach (\phpbb\install\module\update_database\task\update_extensions::$default_extensions_update as $version => $extensions) { - if ($this->update_helper->phpbb_version_compare($update_info['version']['from'], $version, '>')) + if ($this->update_helper->phpbb_version_compare($update_info['version']['from'], $version, '>=')) { $default_update_extensions = array_merge($default_update_extensions, $extensions); } diff --git a/phpBB/phpbb/module/module_manager.php b/phpBB/phpbb/module/module_manager.php index 7ae16cdb61..67bac5b33e 100644 --- a/phpBB/phpbb/module/module_manager.php +++ b/phpBB/phpbb/module/module_manager.php @@ -208,7 +208,7 @@ class module_manager WHERE m1.module_class = '" . $this->db->sql_escape($module_class) . "' AND m2.module_class = '" . $this->db->sql_escape($module_class) . "' AND m1.module_id = $module_id - ORDER BY m2.left_id DESC"; + ORDER BY m2.left_id"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) diff --git a/phpBB/phpbb/notification/type/post.php b/phpBB/phpbb/notification/type/post.php index b9afc6d70a..03221e7c7a 100644 --- a/phpBB/phpbb/notification/type/post.php +++ b/phpBB/phpbb/notification/type/post.php @@ -456,6 +456,12 @@ class post extends \phpbb\notification\type\base return array(); } - return array('notification_data' => $serialized_data); + $data_array = array_merge(array( + 'post_time' => $post['post_time'], + 'post_id' => $post['post_id'], + 'topic_id' => $post['topic_id'] + ), $this->get_data(false)); + + return $data_array; } } diff --git a/phpBB/phpbb/pagination.php b/phpBB/phpbb/pagination.php index 7a81c25ad2..a5a95b096d 100644 --- a/phpBB/phpbb/pagination.php +++ b/phpBB/phpbb/pagination.php @@ -284,7 +284,7 @@ class pagination */ public function get_on_page($per_page, $start) { - return floor($start / $per_page) + 1; + return floor((int) $start / (int) $per_page) + 1; } /** diff --git a/phpBB/phpbb/profilefields/type/type_date.php b/phpBB/phpbb/profilefields/type/type_date.php index 414484920b..5a1a6dbd5c 100644 --- a/phpBB/phpbb/profilefields/type/type_date.php +++ b/phpBB/phpbb/profilefields/type/type_date.php @@ -72,7 +72,7 @@ class type_date extends type_base 'lang_options' => $field_data['lang_options'], ); - $always_now = $request->variable('always_now', -1); + $always_now = $this->request->variable('always_now', -1); if ($always_now == -1) { $s_checked = ($field_data['field_default_value'] == 'now') ? true : false; @@ -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 92d4213180..00be8fd381 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 73d7bc1574..d5165df016 100644 --- a/phpBB/phpbb/search/fulltext_mysql.php +++ b/phpBB/phpbb/search/fulltext_mysql.php @@ -942,38 +942,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/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index 2071a973e5..73dcfce9a5 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -120,7 +120,7 @@ class fulltext_native extends \phpbb\search\base $this->phpbb_dispatcher = $phpbb_dispatcher; $this->user = $user; - $this->word_length = array('min' => $this->config['fulltext_native_min_chars'], 'max' => $this->config['fulltext_native_max_chars']); + $this->word_length = array('min' => (int) $this->config['fulltext_native_min_chars'], 'max' => (int) $this->config['fulltext_native_max_chars']); /** * Load the UTF tools diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index cbe2f02851..cc200b1adc 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -838,7 +838,7 @@ class session $sql = 'SELECT COUNT(session_id) AS sessions FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . (int) $this->data['user_id'] . ' - AND session_time >= ' . (int) ($this->time_now - (max($config['session_length'], $config['form_token_lifetime']))); + AND session_time >= ' . (int) ($this->time_now - (max((int) $config['session_length'], (int) $config['form_token_lifetime']))); $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); 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..5e4f71a2a9 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: @@ -280,10 +363,11 @@ class context * If key is false the position is set to 0 * If key is true the position is set to the last entry * - * @param string $mode Mode to execute (valid modes are 'insert' and 'change') + * @param string $mode Mode to execute (valid modes are 'insert', 'change' and 'delete') * * If insert, the vararray is inserted at the given position (position counting from zero). * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new \value). + * If delete, the vararray is ignored, and the block at the given position (counting from zero) is removed. * * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array) * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) @@ -293,45 +377,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 +453,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 +487,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--; @@ -408,6 +503,45 @@ class context return true; } + // Delete Block + if ($mode == 'delete') + { + // If we are exceeding last iteration, do not delete anything + if ($key > sizeof($block) || $key < 0) + { + return false; + } + + // If we are positioned at the end, we remove the last element + if ($key == sizeof($block)) + { + $key--; + } + + // We are deleting the last element in the block, so remove the block + if (sizeof($block) === 1) + { + $block = null; // unset($block); does not work on references + return true; + } + + // Re-position template blocks + for ($i = $key; $i < sizeof($block)-1; $i++) + { + $block[$i] = $block[$i+1]; + $block[$i]['S_ROW_COUNT'] = $block[$i]['S_ROW_NUM'] = $i; + } + + // Remove the last element + unset($block[$i]); + + // Set first and last elements again, in case they were removed + $block[0]['S_FIRST_ROW'] = true; + $block[sizeof($block)-1]['S_LAST_ROW'] = true; + + return true; + } + return false; } diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php index 041ecb12e4..d1ec442e9a 100644 --- a/phpBB/phpbb/template/template.php +++ b/phpBB/phpbb/template/template.php @@ -160,10 +160,11 @@ interface template * If key is false the position is set to 0 * If key is true the position is set to the last entry * - * @param string $mode Mode to execute (valid modes are 'insert' and 'change') + * @param string $mode Mode to execute (valid modes are 'insert', 'change' and 'delete') * * If insert, the vararray is inserted at the given position (position counting from zero). * If change, the current block gets merged with the vararray (resulting in new \key/value pairs be added and existing keys be replaced by the new \value). + * If delete, the vararray is ignored, and the block at the given position (counting from zero) is removed. * * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array) * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) @@ -173,6 +174,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/environment.php b/phpBB/phpbb/template/twig/environment.php index 179412a2e3..ac4b16e457 100644 --- a/phpBB/phpbb/template/twig/environment.php +++ b/phpBB/phpbb/template/twig/environment.php @@ -32,6 +32,9 @@ class environment extends \Twig_Environment /** @var \phpbb\extension\manager */ protected $extension_manager; + /** @var \phpbb\event\dispatcher_interface */ + protected $phpbb_dispatcher; + /** @var string */ protected $phpbb_root_path; @@ -53,15 +56,17 @@ class environment extends \Twig_Environment * @param string $cache_path The path to the cache directory * @param \phpbb\extension\manager $extension_manager phpBB extension manager * @param \Twig_LoaderInterface $loader Twig loader interface + * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object * @param array $options Array of options to pass to Twig */ - public function __construct(\phpbb\config\config $phpbb_config, \phpbb\filesystem\filesystem $filesystem, \phpbb\path_helper $path_helper, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, $options = array()) + public function __construct(\phpbb\config\config $phpbb_config, \phpbb\filesystem\filesystem $filesystem, \phpbb\path_helper $path_helper, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, \phpbb\event\dispatcher_interface $phpbb_dispatcher = null, $options = array()) { $this->phpbb_config = $phpbb_config; $this->filesystem = $filesystem; $this->phpbb_path_helper = $path_helper; $this->extension_manager = $extension_manager; + $this->phpbb_dispatcher = $phpbb_dispatcher; $this->phpbb_root_path = $this->phpbb_path_helper->get_phpbb_root_path(); $this->web_root_path = $this->phpbb_path_helper->get_web_root_path(); @@ -202,8 +207,37 @@ class environment extends \Twig_Environment $context['definition']->set('STYLESHEETS', '__STYLESHEETS_' . $placeholder_salt . '__'); } + /** + * Allow changing the template output stream before rendering + * + * @event core.twig_environment_render_template_before + * @var array context Array with template variables + * @var string name The template name + * @since 3.2.1-RC1 + */ + if ($this->phpbb_dispatcher) + { + $vars = array('context', 'name'); + extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_before', compact($vars))); + } + $output = parent::render($name, $context); + /** + * Allow changing the template output stream after rendering + * + * @event core.twig_environment_render_template_after + * @var array context Array with template variables + * @var string name The template name + * @var string output Rendered template output stream + * @since 3.2.1-RC1 + */ + if ($this->phpbb_dispatcher) + { + $vars = array('context', 'name', 'output'); + extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_after', compact($vars))); + } + return $this->inject_assets($output, $placeholder_salt); } diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php index 92f87a0331..f0e716d697 100644 --- a/phpBB/phpbb/template/twig/extension.php +++ b/phpBB/phpbb/template/twig/extension.php @@ -170,8 +170,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/textformatter/data_access.php b/phpBB/phpbb/textformatter/data_access.php index 2103bf8e60..0d37e62c87 100644 --- a/phpBB/phpbb/textformatter/data_access.php +++ b/phpBB/phpbb/textformatter/data_access.php @@ -81,11 +81,8 @@ class data_access public function get_bbcodes() { $sql = 'SELECT bbcode_match, bbcode_tpl FROM ' . $this->bbcodes_table; - $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - return $rows; + return $this->fetch_decoded_rowset($sql, ['bbcode_match']); } /** @@ -101,11 +98,8 @@ class data_access $sql = 'SELECT code, emotion, smiley_url, smiley_width, smiley_height FROM ' . $this->smilies_table . ' ORDER BY display_on_posting DESC'; - $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - return $rows; + return $this->fetch_decoded_rowset($sql, ['code', 'emotion', 'smiley_url']); } /** @@ -116,11 +110,8 @@ class data_access protected function get_styles() { $sql = 'SELECT style_id, style_path, style_parent_id, bbcode_bitfield FROM ' . $this->styles_table; - $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - return $rows; + return $this->fetch_decoded_rowset($sql); } /** @@ -219,10 +210,43 @@ class data_access public function get_censored_words() { $sql = 'SELECT word, replacement FROM ' . $this->words_table; + + return $this->fetch_decoded_rowset($sql, ['word', 'replacement']); + } + + /** + * Decode HTML special chars in given rowset + * + * @param array $rows Original rowset + * @param array $columns List of columns to decode + * @return array Decoded rowset + */ + protected function decode_rowset(array $rows, array $columns) + { + foreach ($rows as &$row) + { + foreach ($columns as $column) + { + $row[$column] = htmlspecialchars_decode($row[$column]); + } + } + + return $rows; + } + + /** + * Fetch all rows for given query and decode plain text columns + * + * @param string $sql SELECT query + * @param array $columns List of columns to decode + * @return array + */ + protected function fetch_decoded_rowset($sql, array $columns = []) + { $result = $this->db->sql_query($sql); $rows = $this->db->sql_fetchrowset($result); $this->db->sql_freeresult($result); - return $rows; + return $this->decode_rowset($rows, $columns); } } diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php index a310c67359..7719ce5afa 100644 --- a/phpBB/phpbb/textformatter/s9e/factory.php +++ b/phpBB/phpbb/textformatter/s9e/factory.php @@ -311,7 +311,7 @@ class factory implements \phpbb\textformatter\cache_interface { $configurator->Emoticons->set( $row['code'], - '<img class="smilies" src="{$T_SMILIES_PATH}/' . htmlspecialchars($row['smiley_url']) . '" width="' . $row['smiley_width'] . '" height="' . $row['smiley_height'] . '" alt="{.}" title="' . htmlspecialchars($row['emotion']) . '"/>' + '<img class="smilies" src="{$T_SMILIES_PATH}/' . $this->escape_html_attribute($row['smiley_url']) . '" width="' . $row['smiley_width'] . '" height="' . $row['smiley_height'] . '" alt="{.}" title="' . $this->escape_html_attribute($row['emotion']) . '"/>' ); } @@ -333,8 +333,7 @@ class factory implements \phpbb\textformatter\cache_interface $configurator->plugins->load('Censor', array('tagName' => 'censor:tag')); foreach ($censor as $row) { - // NOTE: words are stored as HTML, we need to decode them to plain text - $configurator->Censor->add(htmlspecialchars_decode($row['word']), htmlspecialchars_decode($row['replacement'])); + $configurator->Censor->add($row['word'], $row['replacement']); } } @@ -348,10 +347,10 @@ class factory implements \phpbb\textformatter\cache_interface $configurator->registeredVars['max_img_width'] = 0; // Load the Emoji plugin and modify its tag's template to obey viewsmilies - $configurator->Emoji->setImageSize(18); + $configurator->Emoji->omitImageSize(); $configurator->Emoji->useSVG(); $tag = $configurator->Emoji->getTag(); - $tag->template = '<xsl:choose><xsl:when test="$S_VIEWSMILIES">' . str_replace('class="emoji"', 'class="smilies"', $tag->template) . '</xsl:when><xsl:otherwise><xsl:value-of select="."/></xsl:otherwise></xsl:choose>'; + $tag->template = '<xsl:choose><xsl:when test="$S_VIEWSMILIES">' . str_replace('class="emoji"', 'class="emoji smilies"', $tag->template) . '</xsl:when><xsl:otherwise><xsl:value-of select="."/></xsl:otherwise></xsl:choose>'; /** * Modify the s9e\TextFormatter configurator after the default settings are set @@ -443,6 +442,20 @@ class factory implements \phpbb\textformatter\cache_interface } /** + * Escape a literal to be used in an HTML attribute in an XSL template + * + * Escapes "HTML special chars" for obvious reasons and curly braces to avoid them + * being interpreted as an attribute value template + * + * @param string $value Original string + * @return string Escaped string + */ + protected function escape_html_attribute($value) + { + return htmlspecialchars(strtr($value, ['{' => '{{', '}' => '}}']), ENT_COMPAT | ENT_XML1, 'UTF-8'); + } + + /** * Return the default BBCodes configuration * * @return array 2D array. Each element has a 'usage' key, a 'template' key, and an optional 'options' key diff --git a/phpBB/phpbb/textformatter/s9e/parser.php b/phpBB/phpbb/textformatter/s9e/parser.php index e2653d60f0..05ddfffa11 100644 --- a/phpBB/phpbb/textformatter/s9e/parser.php +++ b/phpBB/phpbb/textformatter/s9e/parser.php @@ -142,6 +142,7 @@ class parser implements \phpbb\textformatter\parser_interface public function disable_smilies() { $this->parser->disablePlugin('Emoticons'); + $this->parser->disablePlugin('Emoji'); } /** @@ -183,6 +184,7 @@ class parser implements \phpbb\textformatter\parser_interface public function enable_smilies() { $this->parser->enablePlugin('Emoticons'); + $this->parser->enablePlugin('Emoji'); } /** diff --git a/phpBB/phpbb/textformatter/s9e/quote_helper.php b/phpBB/phpbb/textformatter/s9e/quote_helper.php index 24109ac8cc..86c33c7591 100644 --- a/phpBB/phpbb/textformatter/s9e/quote_helper.php +++ b/phpBB/phpbb/textformatter/s9e/quote_helper.php @@ -39,8 +39,8 @@ class quote_helper */ public function __construct(\phpbb\user $user, $root_path, $php_ext) { - $this->post_url = append_sid($root_path . 'viewtopic.' . $php_ext, 'p={POST_ID}#p{POST_ID}'); - $this->profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}'); + $this->post_url = append_sid($root_path . 'viewtopic.' . $php_ext, 'p={POST_ID}#p{POST_ID}', false); + $this->profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}', false); $this->user = $user; } diff --git a/phpBB/phpbb/textformatter/s9e/utils.php b/phpBB/phpbb/textformatter/s9e/utils.php index b317fe4a8d..a9a6d4b892 100644 --- a/phpBB/phpbb/textformatter/s9e/utils.php +++ b/phpBB/phpbb/textformatter/s9e/utils.php @@ -136,4 +136,17 @@ class utils implements \phpbb\textformatter\utils_interface { return \s9e\TextFormatter\Unparser::unparse($xml); } + + /** + * {@inheritdoc} + */ + public function is_empty($text) + { + if ($text === null || $text === '') + { + return true; + } + + return trim($this->unparse($text)) === ''; + } } diff --git a/phpBB/phpbb/textformatter/utils_interface.php b/phpBB/phpbb/textformatter/utils_interface.php index 4810453cd1..4b7392976a 100644 --- a/phpBB/phpbb/textformatter/utils_interface.php +++ b/phpBB/phpbb/textformatter/utils_interface.php @@ -62,10 +62,18 @@ interface utils_interface public function remove_bbcode($text, $bbcode_name, $depth = 0); /** - * Return a parsed text to its original form - * - * @param string $text Parsed text - * @return string Original plain text - */ + * Return a parsed text to its original form + * + * @param string $text Parsed text + * @return string Original plain text + */ public function unparse($text); + + /** + * Return whether or not a parsed text represent an empty text. + * + * @param string $text Parsed text + * @return bool Tue if the original text is empty + */ + public function is_empty($text); } diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php index 17caaa4a60..bb15dd1a74 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -181,7 +181,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, '>='); }); @@ -198,11 +198,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 version_check_exception */ public function get_suggested_updates($force_update = false, $force_cache = false) @@ -223,7 +329,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 + * @return array Version info * @throws version_check_exception */ public function get_versions_matching_stability($force_update = false, $force_cache = false) @@ -243,7 +349,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 version_check_exception */ public function get_versions($force_update = false, $force_cache = false) |