diff options
Diffstat (limited to 'phpBB/phpbb')
-rw-r--r-- | phpBB/phpbb/controller/helper.php | 26 | ||||
-rw-r--r-- | phpBB/phpbb/db/migration/data/v310/style_update_p1.php | 8 | ||||
-rw-r--r-- | phpBB/phpbb/di/container_builder.php | 496 | ||||
-rw-r--r-- | phpBB/phpbb/di/extension/core.php | 6 | ||||
-rw-r--r-- | phpBB/phpbb/event/md_exporter.php | 89 | ||||
-rw-r--r-- | phpBB/phpbb/event/php_exporter.php | 1 | ||||
-rw-r--r-- | phpBB/phpbb/log/log.php | 85 | ||||
-rw-r--r-- | phpBB/phpbb/notification/type/quote.php | 31 | ||||
-rw-r--r-- | phpBB/phpbb/routing/router.php | 59 | ||||
-rw-r--r-- | phpBB/phpbb/textformatter/parser_interface.php | 3 | ||||
-rw-r--r-- | phpBB/phpbb/textformatter/s9e/parser.php | 42 | ||||
-rw-r--r-- | phpBB/phpbb/textformatter/s9e/renderer.php | 43 | ||||
-rw-r--r-- | phpBB/phpbb/textformatter/s9e/utils.php | 63 | ||||
-rw-r--r-- | phpBB/phpbb/textformatter/utils_interface.php | 20 |
14 files changed, 597 insertions, 375 deletions
diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php index 1518169458..3782512fa4 100644 --- a/phpBB/phpbb/controller/helper.php +++ b/phpBB/phpbb/controller/helper.php @@ -13,6 +13,7 @@ namespace phpbb\controller; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RequestContext; @@ -215,12 +216,31 @@ class helper public function message($message, array $parameters = array(), $title = 'INFORMATION', $code = 200) { array_unshift($parameters, $message); + $message_text = call_user_func_array(array($this->user, 'lang'), $parameters); + $message_title = $this->user->lang($title); + + if ($this->request->is_ajax()) + { + global $refresh_data; + + return new JsonResponse( + array( + 'MESSAGE_TITLE' => $message_title, + 'MESSAGE_TEXT' => $message_text, + 'S_USER_WARNING' => false, + 'S_USER_NOTICE' => false, + 'REFRESH_DATA' => (!empty($refresh_data)) ? $refresh_data : null + ), + $code + ); + } + $this->template->assign_vars(array( - 'MESSAGE_TEXT' => call_user_func_array(array($this->user, 'lang'), $parameters), - 'MESSAGE_TITLE' => $this->user->lang($title), + 'MESSAGE_TEXT' => $message_text, + 'MESSAGE_TITLE' => $message_title, )); - return $this->render('message_body.html', $this->user->lang($title), $code); + return $this->render('message_body.html', $message_title, $code); } /** diff --git a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php index 918a565e06..3b0d53d803 100644 --- a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php +++ b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php @@ -62,8 +62,6 @@ class style_update_p1 extends \phpbb\db\migration\migration public function styles_update() { - global $config; - // Get list of valid 3.1 styles $available_styles = array('prosilver'); @@ -138,7 +136,7 @@ class style_update_p1 extends \phpbb\db\migration\migration if (!sizeof($valid_styles)) { // No valid styles: remove everything and add prosilver - $this->sql_query('DELETE FROM ' . STYLES_TABLE, $errored, $error_ary); + $this->sql_query('DELETE FROM ' . STYLES_TABLE); $sql_ary = array( 'style_name' => 'prosilver', @@ -159,13 +157,13 @@ class style_update_p1 extends \phpbb\db\migration\migration $this->sql_query($sql); $sql = 'SELECT style_id - FROM ' . $table . " + FROM ' . STYLES_TABLE . " WHERE style_name = 'prosilver'"; $result = $this->sql_query($sql); $default_style = $this->db->sql_fetchfield($result); $this->db->sql_freeresult($result); - $config->set('default_style', $default_style); + $this->config->set('default_style', $default_style); $sql = 'UPDATE ' . USERS_TABLE . ' SET user_style = 0'; $this->sql_query($sql); diff --git a/phpBB/phpbb/di/container_builder.php b/phpBB/phpbb/di/container_builder.php index 99576f9020..4a31339b9a 100644 --- a/phpBB/phpbb/di/container_builder.php +++ b/phpBB/phpbb/di/container_builder.php @@ -13,6 +13,7 @@ namespace phpbb\di; +use phpbb\filesystem\filesystem; use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -20,11 +21,17 @@ use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; +use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass; class container_builder { /** + * @var string The environment to use. + */ + protected $environment; + + /** * @var string phpBB Root Path */ protected $phpbb_root_path; @@ -35,89 +42,58 @@ class container_builder protected $php_ext; /** - * The container under construction - * - * @var ContainerBuilder - */ + * The container under construction + * + * @var ContainerBuilder + */ protected $container; /** - * @var \phpbb\db\driver\driver_interface - */ - protected $dbal_connection = null; - - /** - * @var array the installed extensions - */ - protected $installed_exts = null; - - /** - * Indicates whether the php config file should be injected into the container (default to true). - * - * @var bool - */ - protected $inject_config = true; - - /** - * Indicates whether extensions should be used (default to true). - * - * @var bool - */ + * Indicates whether extensions should be used (default to true). + * + * @var bool + */ protected $use_extensions = true; /** - * Defines a custom path to find the configuration of the container (default to $this->phpbb_root_path . 'config') - * - * @var string - */ + * Defines a custom path to find the configuration of the container (default to $this->phpbb_root_path . 'config') + * + * @var string + */ protected $config_path = null; /** - * Indicates whether the phpBB compile pass should be used (default to true). - * - * @var bool - */ - protected $use_custom_pass = true; - - /** - * Indicates whether the kernel compile pass should be used (default to true). - * - * @var bool - */ - protected $use_kernel_pass = true; - - /** - * Indicates whether the container should be dumped to the filesystem (default to true). - * - * If DEBUG_CONTAINER is set this option is ignored and a new container is build. - * - * @var bool - */ - protected $dump_container = true; + * Indicates whether the container should be dumped to the filesystem (default to true). + * + * If DEBUG_CONTAINER is set this option is ignored and a new container is build. + * + * @var bool + */ + protected $use_cache = true; /** - * Indicates if the container should be compiled automatically (default to true). - * - * @var bool - */ + * Indicates if the container should be compiled automatically (default to true). + * + * @var bool + */ protected $compile_container = true; /** - * Custom parameters to inject into the container. - * - * Default to true: - * array( - * 'core.root_path', $this->phpbb_root_path, - * 'core.php_ext', $this->php_ext, - * ); - * - * @var array - */ + * Custom parameters to inject into the container. + * + * Default to: + * array( + * 'core.root_path', $this->phpbb_root_path, + * 'core.php_ext', $this->php_ext, + * ); + * + * @var array + */ protected $custom_parameters = null; /** - * @var \phpbb\config_php_file - */ + * @var \phpbb\config_php_file + */ protected $config_php_file; /** @@ -126,74 +102,64 @@ class container_builder protected $cache_dir; /** - * Constructor - * - * @param \phpbb\config_php_file $config_php_file - * @param string $phpbb_root_path Path to the phpbb includes directory. - * @param string $php_ext php file extension - */ - function __construct(\phpbb\config_php_file $config_php_file, $phpbb_root_path, $php_ext) + * @var array + */ + private $container_extensions; + + /** + * Constructor + * + * @param string $phpbb_root_path Path to the phpbb includes directory. + * @param string $php_ext php file extension + */ + function __construct($phpbb_root_path, $php_ext) { - $this->config_php_file = $config_php_file; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; } /** - * Build and return a new Container respecting the current configuration - * - * @return \phpbb_cache_container|ContainerBuilder - */ + * Build and return a new Container respecting the current configuration + * + * @return \phpbb_cache_container|ContainerBuilder + */ public function get_container() { $container_filename = $this->get_container_filename(); $config_cache = new ConfigCache($container_filename, defined('DEBUG')); - if ($this->dump_container && $config_cache->isFresh()) + if ($this->use_cache && $config_cache->isFresh()) { require($config_cache->getPath()); $this->container = new \phpbb_cache_container(); } else { - $container_extensions = array(new \phpbb\di\extension\core($this->get_config_path())); + $this->container_extensions = array(new extension\core($this->get_config_path())); if ($this->use_extensions) { - $installed_exts = $this->get_installed_extensions(); - foreach ($installed_exts as $ext_name => $path) - { - $extension_class = '\\' . str_replace('/', '\\', $ext_name) . '\\di\\extension'; - - if (!class_exists($extension_class)) - { - $extension_class = '\phpbb\extension\di\extension_base'; - } - - $container_extensions[] = new $extension_class($ext_name, $path); - } + $this->load_extensions(); } - if ($this->inject_config) + // Inject the config + if ($this->config_php_file) { - $container_extensions[] = new \phpbb\di\extension\config($this->config_php_file); + $this->container_extensions[] = new extension\config($this->config_php_file); } - $this->container = $this->create_container($container_extensions); + $this->container = $this->create_container($this->container_extensions); - if ($this->use_custom_pass) - { - // Symfony Kernel Listeners - $this->container->addCompilerPass(new \phpbb\di\pass\collection_pass()); - $this->container->addCompilerPass(new RegisterListenersPass('dispatcher', 'event.listener_listener', 'event.listener')); + // Easy collections through tags + $this->container->addCompilerPass(new pass\collection_pass()); - if ($this->use_kernel_pass) - { - $this->container->addCompilerPass(new RegisterListenersPass('dispatcher')); - } - } + // Event listeners "phpBB style" + $this->container->addCompilerPass(new RegisterListenersPass('dispatcher', 'event.listener_listener', 'event.listener')); - $filesystem = new \phpbb\filesystem\filesystem(); - $loader = new YamlFileLoader($this->container, new FileLocator($filesystem->realpath($this->get_config_path()))); + // Event listeners "Symfony style" + $this->container->addCompilerPass(new RegisterListenersPass('dispatcher')); + + $filesystem = new filesystem(); + $loader = new YamlFileLoader($this->container, new FileLocator($filesystem->realpath($this->get_config_path()))); $loader->load($this->container->getParameter('core.environment') . '/config.yml'); $this->inject_custom_parameters(); @@ -201,124 +167,169 @@ class container_builder if ($this->compile_container) { $this->container->compile(); - } - if ($this->dump_container) - { - $this->dump_container($config_cache); + if ($this->use_cache) + { + $this->dump_container($config_cache); + } } } - $this->container->set('config.php', $this->config_php_file); - - if ($this->compile_container) + if ($this->compile_container && $this->config_php_file) { - $this->inject_dbal(); + $this->container->set('config.php', $this->config_php_file); } return $this->container; } /** - * Set if the extensions should be used. - * - * @param bool $use_extensions - */ - public function set_use_extensions($use_extensions) + * Enable the extensions. + * + * @param string $environment The environment to use + * @return $this + */ + public function with_environment($environment) + { + $this->environment = $environment; + + return $this; + } + + /** + * Enable the extensions. + * + * @return $this + */ + public function with_extensions() { - $this->use_extensions = $use_extensions; + $this->use_extensions = true; + + return $this; + } + + /** + * Disable the extensions. + * + * @return $this + */ + public function without_extensions() + { + $this->use_extensions = false; + + return $this; } /** - * Set if the phpBB compile pass have to be used. - * - * @param bool $use_custom_pass - */ - public function set_use_custom_pass($use_custom_pass) + * Enable the caching of the container. + * + * If DEBUG_CONTAINER is set this option is ignored and a new container is build. + * + * @return $this + */ + public function with_cache() { - $this->use_custom_pass = $use_custom_pass; + $this->use_cache = true; + + return $this; } /** - * Set if the kernel compile pass have to be used. - * - * @param bool $use_kernel_pass - */ - public function set_use_kernel_pass($use_kernel_pass) + * Disable the caching of the container. + * + * @return $this + */ + public function without_cache() { - $this->use_kernel_pass = $use_kernel_pass; + $this->use_cache = false; + + return $this; } /** - * Set if the php config file should be injecting into the container. - * - * @param bool $inject_config - */ - public function set_inject_config($inject_config) + * Set the cache directory. + * + * @param string $cache_dir The cache directory. + * @return $this + */ + public function with_cache_dir($cache_dir) { - $this->inject_config = $inject_config; + $this->cache_dir = $cache_dir; + + return $this; } /** - * Set if a dump container should be used. - * - * If DEBUG_CONTAINER is set this option is ignored and a new container is build. - * - * @var bool $dump_container - */ - public function set_dump_container($dump_container) + * Enable the compilation of the container. + * + * @return $this + */ + public function with_compiled_container() { - $this->dump_container = $dump_container; + $this->compile_container = true; + + return $this; } /** - * Set if the container should be compiled automatically (default to true). - * - * @var bool $dump_container - */ - public function set_compile_container($compile_container) + * Disable the compilation of the container. + * + * @return $this + */ + public function without_compiled_container() { - $this->compile_container = $compile_container; + $this->compile_container = false; + + return $this; } /** - * Set a custom path to find the configuration of the container - * - * @param string $config_path - */ - public function set_config_path($config_path) + * Set a custom path to find the configuration of the container. + * + * @param string $config_path + * @return $this + */ + public function with_config_path($config_path) { $this->config_path = $config_path; + + return $this; } /** - * Returns the path to the container configuration (default: root_path/config) + * Set custom parameters to inject into the container. * - * @return string + * @param array $custom_parameters + * @return $this */ - protected function get_config_path() + public function with_custom_parameters($custom_parameters) { - return $this->config_path ?: $this->phpbb_root_path . 'config'; + $this->custom_parameters = $custom_parameters; + + return $this; } /** - * Set custom parameters to inject into the container. - * - * @param array $custom_parameters - */ - public function set_custom_parameters($custom_parameters) + * Set custom parameters to inject into the container. + * + * @param \phpbb\config_php_file $config_php_file + * @return $this + */ + public function with_config(\phpbb\config_php_file $config_php_file) { - $this->custom_parameters = $custom_parameters; + $this->config_php_file = $config_php_file; + + return $this; } /** - * Set the path to the cache directory. + * Returns the path to the container configuration (default: root_path/config) * - * @param string $cache_dir Path to the cache directory + * @return string */ - public function set_cache_dir($cache_dir) + protected function get_config_path() { - $this->cache_dir = $cache_dir; + return $this->config_path ?: $this->phpbb_root_path . 'config'; } /** @@ -332,89 +343,85 @@ class container_builder } /** - * Dump the container to the disk. - * - * @param ConfigCache $cache The config cache - */ - protected function dump_container($cache) + * Load the enabled extensions. + */ + protected function load_extensions() { - $dumper = new PhpDumper($this->container); - $cached_container_dump = $dumper->dump(array( - 'class' => 'phpbb_cache_container', - 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder', - )); + if ($this->config_php_file !== null) + { + // Build an intermediate container to load the ext list from the database + $container_builder = new container_builder($this->phpbb_root_path, $this->php_ext); + $ext_container = $container_builder + ->without_cache() + ->without_extensions() + ->with_config($this->config_php_file) + ->with_environment('production') + ->without_compiled_container() + ->get_container() + ; + + $ext_container->register('cache.driver', '\\phpbb\\cache\\driver\\dummy'); + $ext_container->compile(); + + $extensions = $ext_container->get('ext.manager')->all_enabled(); + + // Load each extension found + foreach ($extensions as $ext_name => $path) + { + $extension_class = '\\' . str_replace('/', '\\', $ext_name) . '\\di\\extension'; - $cache->write($cached_container_dump, $this->container->getResources()); - } + if (!class_exists($extension_class)) + { + $extension_class = '\\phpbb\\extension\\di\\extension_base'; + } - /** - * Inject the connection into the container if one was opened. - */ - protected function inject_dbal() - { - if ($this->dbal_connection !== null) - { - $this->container->get('dbal.conn')->set_driver($this->dbal_connection); - } - } + $this->container_extensions[] = new $extension_class($ext_name, $path); - /** - * Get DB connection. - * - * @return \phpbb\db\driver\driver_interface - */ - protected function get_dbal_connection() - { - if ($this->dbal_connection === null) + // Load extension autoloader + $filename = $path . 'vendor/autoload.php'; + if (file_exists($filename)) + { + require $filename; + } + } + } + else { - $dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms')); - $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'), - defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK - ); + // To load the extensions we need the database credentials. + // Automatically disable the extensions if we don't have them. + $this->use_extensions = false; } - - return $this->dbal_connection; } /** - * Get enabled extensions. - * - * @return array enabled extensions - */ - protected function get_installed_extensions() + * Dump the container to the disk. + * + * @param ConfigCache $cache The config cache + */ + protected function dump_container($cache) { - $db = $this->get_dbal_connection(); - $extension_table = $this->config_php_file->get('table_prefix') . 'ext'; - - $sql = 'SELECT * - FROM ' . $extension_table . ' - WHERE ext_active = 1'; - - $result = $db->sql_query($sql); - $rows = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); + try + { + $dumper = new PhpDumper($this->container); + $cached_container_dump = $dumper->dump(array( + 'class' => 'phpbb_cache_container', + 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder', + )); - $exts = array(); - foreach ($rows as $row) + $cache->write($cached_container_dump, $this->container->getResources()); + } + catch (IOException $e) { - $exts[$row['ext_name']] = $this->phpbb_root_path . 'ext/' . $row['ext_name'] . '/'; + // Don't fail if the cache isn't writeable } - - return $exts; } /** - * Create the ContainerBuilder object - * - * @param array $extensions Array of Container extension objects - * @return ContainerBuilder object - */ + * Create the ContainerBuilder object + * + * @param array $extensions Array of Container extension objects + * @return ContainerBuilder object + */ protected function create_container(array $extensions) { $container = new ContainerBuilder(new ParameterBag($this->get_core_parameters())); @@ -425,7 +432,6 @@ class container_builder { $container->registerExtension($extension); $extensions_alias[] = $extension->getAlias(); - //$container->loadFromExtension($extension->getAlias()); } $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias)); @@ -487,10 +493,10 @@ class container_builder } /** - * Get the filename under which the dumped container will be stored. - * - * @return string Path for dumped container - */ + * Get the filename under which the dumped container will be stored. + * + * @return string Path for dumped container + */ protected function get_container_filename() { $filename = str_replace(array('/', '.'), array('slash', 'dot'), $this->phpbb_root_path); @@ -504,6 +510,6 @@ class container_builder */ protected function get_environment() { - return PHPBB_ENVIRONMENT; + return $this->environment ?: PHPBB_ENVIRONMENT; } } diff --git a/phpBB/phpbb/di/extension/core.php b/phpBB/phpbb/di/extension/core.php index c9e2d4dc5b..91b321a684 100644 --- a/phpBB/phpbb/di/extension/core.php +++ b/phpBB/phpbb/di/extension/core.php @@ -71,7 +71,7 @@ class core extends Extension // Set the Twig options if defined in the environment $definition = $container->getDefinition('template.twig.environment'); - $twig_environment_options = $definition->getArgument(6); + $twig_environment_options = $definition->getArgument(7); if ($config['twig']['debug']) { $twig_environment_options['debug'] = true; @@ -80,8 +80,8 @@ class core extends Extension { $twig_environment_options['auto_reload'] = true; } - // Replace the 6th argument, the options passed to the environment - $definition->replaceArgument(6, $twig_environment_options); + // Replace the 8th argument, the options passed to the environment + $definition->replaceArgument(7, $twig_environment_options); if ($config['twig']['enable_debug_extension']) { diff --git a/phpBB/phpbb/event/md_exporter.php b/phpBB/phpbb/event/md_exporter.php index 05e898a157..e042d0a5d1 100644 --- a/phpBB/phpbb/event/md_exporter.php +++ b/phpBB/phpbb/event/md_exporter.php @@ -157,20 +157,64 @@ class md_exporter } list($file_details, $details) = explode("\n* Since: ", $details, 2); - list($since, $description) = explode("\n* Purpose: ", $details, 2); + + $changed_versions = array(); + if (strpos($details, "\n* Changed: ") !== false) + { + list($since, $details) = explode("\n* Changed: ", $details, 2); + while (strpos($details, "\n* Changed: ") !== false) + { + list($changed, $details) = explode("\n* Changed: ", $details, 2); + $changed_versions[] = $changed; + } + list($changed, $description) = explode("\n* Purpose: ", $details, 2); + $changed_versions[] = $changed; + } + else + { + list($since, $description) = explode("\n* Purpose: ", $details, 2); + $changed_versions = array(); + } $files = $this->validate_file_list($file_details); $since = $this->validate_since($since); + $changes = array(); + foreach ($changed_versions as $changed) + { + list($changed_version, $changed_description) = $this->validate_changed($changed); + + if (isset($changes[$changed_version])) + { + throw new \LogicException("Duplicate change information found for event '{$this->current_event}'"); + } + + $changes[$changed_version] = $changed_description; + } + $description = trim($description, "\n") . "\n"; if (!$this->version_is_filtered($since)) { - continue; + $is_filtered = false; + foreach ($changes as $version => $null) + { + if ($this->version_is_filtered($version)) + { + $is_filtered = true; + break; + } + } + + if (!$is_filtered) + { + continue; + } } $this->events[$event_name] = array( 'event' => $this->current_event, 'files' => $files, 'since' => $since, + 'changed' => $changes, 'description' => $description, ); } @@ -182,6 +226,7 @@ class md_exporter * The version to check * * @param string $version + * @return bool */ protected function version_is_filtered($version) { @@ -269,7 +314,7 @@ class md_exporter */ public function validate_since($since) { - if (!preg_match('#^\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?$#', $since)) + if (!$this->validate_version($since)) { throw new \LogicException("Invalid since information found for event '{$this->current_event}'"); } @@ -278,6 +323,44 @@ class md_exporter } /** + * Validate "Changed" Information + * + * @param string $changed + * @return string + * @throws \LogicException + */ + public function validate_changed($changed) + { + if (strpos($changed, ' ') !== false) + { + list($version, $description) = explode(' ', $changed, 2); + } + else + { + $version = $changed; + $description = ''; + } + + if (!$this->validate_version($version)) + { + throw new \LogicException("Invalid changed information found for event '{$this->current_event}'"); + } + + return array($version, $description); + } + + /** + * Validate "version" Information + * + * @param string $version + * @return bool True if valid, false otherwise + */ + public function validate_version($version) + { + return preg_match('#^\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?$#', $version); + } + + /** * Validate the files list * * @param string $file_details diff --git a/phpBB/phpbb/event/php_exporter.php b/phpBB/phpbb/event/php_exporter.php index 8cffa4620f..d2ab0595c0 100644 --- a/phpBB/phpbb/event/php_exporter.php +++ b/phpBB/phpbb/event/php_exporter.php @@ -293,6 +293,7 @@ class php_exporter * The version to check * * @param string $version + * @return bool */ protected function version_is_filtered($version) { diff --git a/phpBB/phpbb/log/log.php b/phpBB/phpbb/log/log.php index 4bb2e7a75a..a1bf0f8e88 100644 --- a/phpBB/phpbb/log/log.php +++ b/phpBB/phpbb/log/log.php @@ -521,15 +521,77 @@ class log implements \phpbb\log\log_interface $sql_keywords = $this->generate_sql_keyword($keywords); } - if ($count_logs) - { - $sql = 'SELECT COUNT(l.log_id) AS total_entries - FROM ' . $this->log_table . ' l, ' . USERS_TABLE . ' u - WHERE l.log_type = ' . (int) $log_type . ' + $get_logs_sql_ary = array( + 'SELECT' => 'l.*, u.username, u.username_clean, u.user_colour', + 'FROM' => array( + $this->log_table => 'l', + USERS_TABLE => 'u', + ), + 'WHERE' => 'l.log_type = ' . (int) $log_type . " AND l.user_id = u.user_id - AND l.log_time >= ' . (int) $log_time . " $sql_keywords - $sql_additional"; + $sql_additional", + + 'ORDER_BY' => $sort_by, + ); + + if($log_time) + { + $get_logs_sql_ary['WHERE'] = 'l.log_time >= ' . (int) $log_time . ' + AND ' . $get_logs_sql_ary['WHERE']; + } + + /** + * Modify the query to obtain the logs data + * + * @event core.get_logs_main_query_before + * @var array get_logs_sql_ary The array in the format of the query builder with the query + * to get the log count and the log list + * @var string mode Mode of the entries we display + * @var bool count_logs Do we count all matching entries? + * @var int limit Limit the number of entries + * @var int offset Offset when fetching the entries + * @var mixed forum_id Limit entries to the forum_id, + * can also be an array of forum_ids + * @var int topic_id Limit entries to the topic_id + * @var int user_id Limit entries to the user_id + * @var int log_time Limit maximum age of log entries + * @var string sort_by SQL order option + * @var string keywords Will only return entries that have the + * keywords in log_operation or log_data + * @var string profile_url URL to the users profile + * @var int log_type Limit logs to a certain type. If log_type + * is false, no entries will be returned. + * @var string sql_additional Additional conditions for the entries, + * e.g.: 'AND l.forum_id = 1' + * @since 3.1.5-RC1 + */ + $vars = array( + 'get_logs_sql_ary', + 'mode', + 'count_logs', + 'limit', + 'offset', + 'forum_id', + 'topic_id', + 'user_id', + 'log_time', + 'sort_by', + 'keywords', + 'profile_url', + 'log_type', + 'sql_additional', + ); + extract($this->dispatcher->trigger_event('core.get_logs_main_query_before', compact($vars))); + + if ($count_logs) + { + $count_logs_sql_ary = $get_logs_sql_ary; + + $count_logs_sql_ary['SELECT'] = 'COUNT(l.log_id) AS total_entries'; + unset($count_logs_sql_ary['ORDER_BY']); + + $sql = $this->db->sql_build_query('SELECT', $count_logs_sql_ary); $result = $this->db->sql_query($sql); $this->entry_count = (int) $this->db->sql_fetchfield('total_entries'); $this->db->sql_freeresult($result); @@ -548,14 +610,7 @@ class log implements \phpbb\log\log_interface } } - $sql = 'SELECT l.*, u.username, u.username_clean, u.user_colour - FROM ' . $this->log_table . ' l, ' . USERS_TABLE . ' u - WHERE l.log_type = ' . (int) $log_type . ' - AND u.user_id = l.user_id - ' . (($log_time) ? 'AND l.log_time >= ' . (int) $log_time : '') . " - $sql_keywords - $sql_additional - ORDER BY $sort_by"; + $sql = $this->db->sql_build_query('SELECT', $get_logs_sql_ary); $result = $this->db->sql_query_limit($sql, $limit, $this->last_page_offset); $i = 0; diff --git a/phpBB/phpbb/notification/type/quote.php b/phpBB/phpbb/notification/type/quote.php index 141f90c7ae..51edfec6f7 100644 --- a/phpBB/phpbb/notification/type/quote.php +++ b/phpBB/phpbb/notification/type/quote.php @@ -21,6 +21,11 @@ namespace phpbb\notification\type; class quote extends \phpbb\notification\type\post { /** + * @var \phpbb\textformatter\utils_interface + */ + protected $utils; + + /** * Get notification type name * * @return string @@ -31,13 +36,6 @@ class quote extends \phpbb\notification\type\post } /** - * regular expression to match to find usernames - * - * @var string - */ - protected static $regular_expression_match = '#\[quote="(.+?)"#'; - - /** * Language key used to output the text * * @var string @@ -77,17 +75,16 @@ class quote extends \phpbb\notification\type\post 'ignore_users' => array(), ), $options); - $usernames = false; - preg_match_all(self::$regular_expression_match, $post['post_text'], $usernames); + $usernames = $this->utils->get_outermost_quote_authors($post['post_text']); - if (empty($usernames[1])) + if (empty($usernames)) { return array(); } - $usernames[1] = array_unique($usernames[1]); + $usernames = array_unique($usernames); - $usernames = array_map('utf8_clean_string', $usernames[1]); + $usernames = array_map('utf8_clean_string', $usernames); $users = array(); @@ -187,4 +184,14 @@ class quote extends \phpbb\notification\type\post 'AUTHOR_NAME' => htmlspecialchars_decode($user_data['username']), )); } + + /** + * Set the utils service used to retrieve quote authors + * + * @param \phpbb\textformatter\utils_interface $utils + */ + public function set_utils(\phpbb\textformatter\utils_interface $utils) + { + $this->utils = $utils; + } } diff --git a/phpBB/phpbb/routing/router.php b/phpBB/phpbb/routing/router.php index dd5bffe22b..2f89d4e884 100644 --- a/phpBB/phpbb/routing/router.php +++ b/phpBB/phpbb/routing/router.php @@ -14,6 +14,7 @@ namespace phpbb\routing; use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper; use Symfony\Component\Routing\Matcher\UrlMatcher; @@ -252,22 +253,29 @@ class router implements RouterInterface */ protected function create_dumped_url_matcher() { - $cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_matcher.{$this->php_ext}", defined('DEBUG')); - if (!$cache->isFresh()) + try { - $dumper = new PhpMatcherDumper($this->get_routes()); + $cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_matcher.{$this->php_ext}", defined('DEBUG')); + if (!$cache->isFresh()) + { + $dumper = new PhpMatcherDumper($this->get_routes()); - $options = array( - 'class' => 'phpbb_url_matcher', - 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', - ); + $options = array( + 'class' => 'phpbb_url_matcher', + 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', + ); - $cache->write($dumper->dump($options), $this->get_routes()->getResources()); - } + $cache->write($dumper->dump($options), $this->get_routes()->getResources()); + } - require_once($cache->getPath()); + require_once($cache->getPath()); - $this->matcher = new \phpbb_url_matcher($this->context); + $this->matcher = new \phpbb_url_matcher($this->context); + } + catch (IOException $e) + { + $this->create_new_url_matcher(); + } } /** @@ -300,22 +308,29 @@ class router implements RouterInterface */ protected function create_dumped_url_generator() { - $cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_generator.{$this->php_ext}", defined('DEBUG')); - if (!$cache->isFresh()) + try { - $dumper = new PhpGeneratorDumper($this->get_routes()); + $cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_generator.{$this->php_ext}", defined('DEBUG')); + if (!$cache->isFresh()) + { + $dumper = new PhpGeneratorDumper($this->get_routes()); - $options = array( - 'class' => 'phpbb_url_generator', - 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', - ); + $options = array( + 'class' => 'phpbb_url_generator', + 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', + ); - $cache->write($dumper->dump($options), $this->get_routes()->getResources()); - } + $cache->write($dumper->dump($options), $this->get_routes()->getResources()); + } - require_once($cache->getPath()); + require_once($cache->getPath()); - $this->generator = new \phpbb_url_generator($this->context); + $this->generator = new \phpbb_url_generator($this->context); + } + catch (IOException $e) + { + $this->create_new_url_generator(); + } } /** diff --git a/phpBB/phpbb/textformatter/parser_interface.php b/phpBB/phpbb/textformatter/parser_interface.php index 3cb9f8e977..ad611fb5b4 100644 --- a/phpBB/phpbb/textformatter/parser_interface.php +++ b/phpBB/phpbb/textformatter/parser_interface.php @@ -82,7 +82,8 @@ interface parser_interface /** * Get the list of errors that were generated during last parsing * - * @return array + * @return array[] Array of arrays. Each array contains a lang string at index 0 plus any number + * of optional parameters */ public function get_errors(); diff --git a/phpBB/phpbb/textformatter/s9e/parser.php b/phpBB/phpbb/textformatter/s9e/parser.php index e46a0578d2..838c211e56 100644 --- a/phpBB/phpbb/textformatter/s9e/parser.php +++ b/phpBB/phpbb/textformatter/s9e/parser.php @@ -32,20 +32,14 @@ class parser implements \phpbb\textformatter\parser_interface protected $parser; /** - * @var \phpbb\user User object, used for translating errors - */ - protected $user; - - /** * Constructor * * @param \phpbb\cache\driver_interface $cache * @param string $key Cache key - * @param \phpbb\user $user * @param factory $factory * @param \phpbb\event\dispatcher_interface $dispatcher */ - public function __construct(\phpbb\cache\driver\driver_interface $cache, $key, \phpbb\user $user, factory $factory, \phpbb\event\dispatcher_interface $dispatcher) + public function __construct(\phpbb\cache\driver\driver_interface $cache, $key, factory $factory, \phpbb\event\dispatcher_interface $dispatcher) { $parser = $cache->get($key); if (!$parser) @@ -56,24 +50,21 @@ class parser implements \phpbb\textformatter\parser_interface $this->dispatcher = $dispatcher; $this->parser = $parser; - $this->user = $user; $parser = $this; /** * Configure the parser service * * Can be used to: - * - toggle features according to the user's preferences, - * - toggle BBCodes according to the user's permissions, - * - register variables or custom parsers in the s9e\TextFormatter - * - configure the s9e\TextFormatter parser + * - toggle features or BBCodes + * - register variables or custom parsers in the s9e\TextFormatter parser + * - configure the s9e\TextFormatter parser's runtime settings * * @event core.text_formatter_s9e_parser_setup * @var \phpbb\textformatter\s9e\parser parser This parser service - * @var \phpbb\user user Current user * @since 3.2.0-a1 */ - $vars = array('parser', 'user'); + $vars = array('parser'); extract($dispatcher->trigger_event('core.text_formatter_s9e_parser_setup', compact($vars))); } @@ -196,13 +187,12 @@ class parser implements \phpbb\textformatter\parser_interface /** * {@inheritdoc} * - * This will translate the log entries found in s9e\TextFormatter's logger into phpBB error + * This will convert the log entries found in s9e\TextFormatter's logger into phpBB error * messages */ public function get_errors() { $errors = array(); - foreach ($this->parser->getLogger()->get() as $entry) { list($type, $msg, $context) = $entry; @@ -211,33 +201,39 @@ class parser implements \phpbb\textformatter\parser_interface { if ($context['tagName'] === 'E') { - $errors[] = $this->user->lang('TOO_MANY_SMILIES', $context['tagLimit']); + $errors[] = array('TOO_MANY_SMILIES', $context['tagLimit']); } else if ($context['tagName'] === 'URL') { - $errors[] = $this->user->lang('TOO_MANY_URLS', $context['tagLimit']); + $errors[] = array('TOO_MANY_URLS', $context['tagLimit']); } } else if ($msg === 'MAX_FONT_SIZE_EXCEEDED') { - $errors[] = $this->user->lang($msg, $context['max_size']); + $errors[] = array($msg, $context['max_size']); } else if (preg_match('/^MAX_(?:FLASH|IMG)_(HEIGHT|WIDTH)_EXCEEDED$/D', $msg, $m)) { - $errors[] = $this->user->lang($msg, $context['max_' . strtolower($m[1])]); + $errors[] = array($msg, $context['max_' . strtolower($m[1])]); } else if ($msg === 'Tag is disabled') { $name = strtolower($context['tag']->getName()); - $errors[] = $this->user->lang('UNAUTHORISED_BBCODE', '[' . $name . ']'); + $errors[] = array('UNAUTHORISED_BBCODE', '[' . $name . ']'); } else if ($msg === 'UNABLE_GET_IMAGE_SIZE') { - $errors[] = $this->user->lang($msg); + $errors[] = array($msg); } } - return array_unique($errors); + // Deduplicate error messages. array_unique() only works on strings so we have to serialize + if (!empty($errors)) + { + $errors = array_map('unserialize', array_unique(array_map('serialize', $errors))); + } + + return $errors; } /** diff --git a/phpBB/phpbb/textformatter/s9e/renderer.php b/phpBB/phpbb/textformatter/s9e/renderer.php index 8999f1d25f..51bc44f339 100644 --- a/phpBB/phpbb/textformatter/s9e/renderer.php +++ b/phpBB/phpbb/textformatter/s9e/renderer.php @@ -234,10 +234,6 @@ class renderer implements \phpbb\textformatter\renderer_interface } $html = $this->renderer->render($xml); - if (stripos($html, '<code') !== false) - { - $html = $this->replace_tabs_in_code($html); - } /** * Modify a rendered text @@ -254,45 +250,6 @@ class renderer implements \phpbb\textformatter\renderer_interface } /** - * Replace tabs in code elements - * - * @see bbcode::bbcode_second_pass_code() - * - * @param string $html Original HTML - * @return string Modified HTML - */ - protected function replace_tabs_in_code($html) - { - return preg_replace_callback( - '((<code[^>]*>)(.*?)(</code>))is', - function ($captures) - { - $code = $captures[2]; - - $code = str_replace("\t", ' ', $code); - $code = str_replace(' ', ' ', $code); - $code = str_replace(' ', ' ', $code); - $code = str_replace("\n ", "\n ", $code); - - // keep space at the beginning - if (!empty($code) && $code[0] == ' ') - { - $code = ' ' . substr($code, 1); - } - - // remove newline at the beginning - if (!empty($code) && $code[0] == "\n") - { - $code = substr($code, 1); - } - - return $captures[1] . $code . $captures[3]; - }, - $html - ); - } - - /** * {@inheritdoc} */ public function set_smilies_path($path) diff --git a/phpBB/phpbb/textformatter/s9e/utils.php b/phpBB/phpbb/textformatter/s9e/utils.php index 2018bbf519..04df589930 100644 --- a/phpBB/phpbb/textformatter/s9e/utils.php +++ b/phpBB/phpbb/textformatter/s9e/utils.php @@ -35,6 +35,69 @@ class utils implements \phpbb\textformatter\utils_interface } /** + * Return given string between quotes + * + * Will use either single- or double- quotes depending on whichever requires less escaping. + * Quotes and backslashes are escaped with backslashes where necessary + * + * @param string $str Original string + * @return string Escaped string within quotes + */ + protected function enquote($str) + { + $singleQuoted = "'" . addcslashes($str, "\\'") . "'"; + $doubleQuoted = '"' . addcslashes($str, '\\"') . '"'; + + return (strlen($singleQuoted) < strlen($doubleQuoted)) ? $singleQuoted : $doubleQuoted; + } + + /** + * {@inheritdoc} + */ + public function generate_quote($text, array $attributes = array()) + { + $quote = '[quote'; + if (isset($attributes['author'])) + { + // Add the author as the BBCode's default attribute + $quote .= '=' . $this->enquote($attributes['author']); + unset($attributes['author']); + } + foreach ($attributes as $name => $value) + { + $quote .= ' ' . $name . '=' . $this->enquote($value); + } + $quote .= ']' . $text . '[/quote]'; + + return $quote; + } + + /** + * Get a list of quote authors, limited to the outermost quotes + * + * @param string $xml Parsed text + * @return string[] List of authors + */ + public function get_outermost_quote_authors($xml) + { + $authors = array(); + if (strpos($xml, '<QUOTE ') === false) + { + return $authors; + } + + $dom = new \DOMDocument; + $dom->loadXML($xml); + $xpath = new \DOMXPath($dom); + foreach ($xpath->query('//QUOTE[not(ancestor::QUOTE)]/@author') as $author) + { + $authors[] = $author->textContent; + } + + return $authors; + } + + /** * Remove given BBCode and its content, at given nesting depth * * @param string $xml Parsed text diff --git a/phpBB/phpbb/textformatter/utils_interface.php b/phpBB/phpbb/textformatter/utils_interface.php index 132dc8ece4..41a6ba2345 100644 --- a/phpBB/phpbb/textformatter/utils_interface.php +++ b/phpBB/phpbb/textformatter/utils_interface.php @@ -29,6 +29,26 @@ interface utils_interface public function clean_formatting($text); /** + * Create a quote block for given text + * + * Possible attributes: + * - author + * + * @param string $text Quote's text + * @param array $attributes Quote's attributes + * @return string Quote block to be used in a new post/text + */ + public function generate_quote($text, array $attributes = array()); + + /** + * Get a list of quote authors, limited to the outermost quotes + * + * @param string $text Parsed text + * @return string[] List of authors + */ + public function get_outermost_quote_authors($text); + + /** * Remove given BBCode and its content, at given nesting depth * * @param string $text Parsed text |