aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/phpbb
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/phpbb')
-rw-r--r--phpBB/phpbb/auth/provider/oauth/token_storage.php6
-rw-r--r--phpBB/phpbb/cache/driver/dummy.php (renamed from phpBB/phpbb/cache/driver/null.php)4
-rw-r--r--phpBB/phpbb/captcha/plugins/captcha_abstract.php2
-rw-r--r--phpBB/phpbb/controller/exception.php2
-rw-r--r--phpBB/phpbb/controller/helper.php26
-rw-r--r--phpBB/phpbb/controller/resolver.php18
-rw-r--r--phpBB/phpbb/db/extractor/postgres_extractor.php1
-rw-r--r--phpBB/phpbb/db/migration/data/v30x/release_3_0_14.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v30x/release_3_0_14_rc1.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v310/style_update_p1.php8
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/v314.php32
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/v314rc2.php32
-rw-r--r--phpBB/phpbb/di/container_builder.php496
-rw-r--r--phpBB/phpbb/di/extension/container_configuration.php2
-rw-r--r--phpBB/phpbb/di/extension/core.php14
-rw-r--r--phpBB/phpbb/event/md_exporter.php137
-rw-r--r--phpBB/phpbb/event/php_exporter.php120
-rw-r--r--phpBB/phpbb/extension/exception.php6
-rw-r--r--phpBB/phpbb/extension/manager.php7
-rw-r--r--phpBB/phpbb/extension/metadata_manager.php26
-rw-r--r--phpBB/phpbb/filesystem/filesystem.php2
-rw-r--r--phpBB/phpbb/help/controller/bbcode.php85
-rw-r--r--phpBB/phpbb/help/controller/controller.php76
-rw-r--r--phpBB/phpbb/help/controller/faq.php165
-rw-r--r--phpBB/phpbb/help/manager.php136
-rw-r--r--phpBB/phpbb/language/exception/invalid_plural_rule_exception.php22
-rw-r--r--phpBB/phpbb/language/exception/language_exception.php22
-rw-r--r--phpBB/phpbb/language/exception/language_file_not_found.php22
-rw-r--r--phpBB/phpbb/language/language.php566
-rw-r--r--phpBB/phpbb/language/language_file_helper.php71
-rw-r--r--phpBB/phpbb/language/language_file_loader.php206
-rw-r--r--phpBB/phpbb/log/dummy.php (renamed from phpBB/phpbb/log/null.php)4
-rw-r--r--phpBB/phpbb/log/log.php85
-rw-r--r--phpBB/phpbb/notification/exception.php6
-rw-r--r--phpBB/phpbb/notification/manager.php2
-rw-r--r--phpBB/phpbb/notification/type/quote.php31
-rw-r--r--phpBB/phpbb/permissions.php3
-rw-r--r--phpBB/phpbb/routing/router.php76
-rw-r--r--phpBB/phpbb/template/asset.php27
-rw-r--r--phpBB/phpbb/template/exception/user_object_not_available.php22
-rw-r--r--phpBB/phpbb/template/twig/environment.php27
-rw-r--r--phpBB/phpbb/template/twig/extension.php12
-rw-r--r--phpBB/phpbb/template/twig/loader.php3
-rw-r--r--phpBB/phpbb/template/twig/node/definenode.php3
-rw-r--r--phpBB/phpbb/template/twig/node/includeasset.php2
-rw-r--r--phpBB/phpbb/template/twig/node/includephp.php6
-rw-r--r--phpBB/phpbb/template/twig/tokenparser/defineparser.php7
-rw-r--r--phpBB/phpbb/template/twig/tokenparser/includephp.php3
-rw-r--r--phpBB/phpbb/template/twig/twig.php19
-rw-r--r--phpBB/phpbb/textformatter/parser_interface.php3
-rw-r--r--phpBB/phpbb/textformatter/s9e/parser.php42
-rw-r--r--phpBB/phpbb/textformatter/s9e/renderer.php43
-rw-r--r--phpBB/phpbb/textformatter/s9e/utils.php63
-rw-r--r--phpBB/phpbb/textformatter/utils_interface.php20
-rw-r--r--phpBB/phpbb/user.php336
55 files changed, 2526 insertions, 705 deletions
diff --git a/phpBB/phpbb/auth/provider/oauth/token_storage.php b/phpBB/phpbb/auth/provider/oauth/token_storage.php
index 023cf402ca..f488c2022d 100644
--- a/phpBB/phpbb/auth/provider/oauth/token_storage.php
+++ b/phpBB/phpbb/auth/provider/oauth/token_storage.php
@@ -117,7 +117,8 @@ class token_storage implements TokenStorageInterface
{
$service = $this->get_service_name_for_db($service);
- if ($this->cachedToken) {
+ if ($this->cachedToken)
+ {
return true;
}
@@ -232,7 +233,8 @@ class token_storage implements TokenStorageInterface
{
$service = $this->get_service_name_for_db($service);
- if ($this->cachedToken instanceof TokenInterface) {
+ if ($this->cachedToken instanceof TokenInterface)
+ {
return $this->cachedToken;
}
diff --git a/phpBB/phpbb/cache/driver/null.php b/phpBB/phpbb/cache/driver/dummy.php
index 298731ea54..1f74f6dd77 100644
--- a/phpBB/phpbb/cache/driver/null.php
+++ b/phpBB/phpbb/cache/driver/dummy.php
@@ -14,9 +14,9 @@
namespace phpbb\cache\driver;
/**
-* ACM Null Caching
+* ACM dummy Caching
*/
-class null extends \phpbb\cache\driver\base
+class dummy extends \phpbb\cache\driver\base
{
/**
* Set cache path
diff --git a/phpBB/phpbb/captcha/plugins/captcha_abstract.php b/phpBB/phpbb/captcha/plugins/captcha_abstract.php
index 799947a84e..b29f144f97 100644
--- a/phpBB/phpbb/captcha/plugins/captcha_abstract.php
+++ b/phpBB/phpbb/captcha/plugins/captcha_abstract.php
@@ -195,7 +195,7 @@ abstract class captcha_abstract
{
global $config, $db, $user;
- if (empty($user->lang))
+ if (!$user->is_setup())
{
$user->setup();
}
diff --git a/phpBB/phpbb/controller/exception.php b/phpBB/phpbb/controller/exception.php
index 437558b06a..e227c7c37b 100644
--- a/phpBB/phpbb/controller/exception.php
+++ b/phpBB/phpbb/controller/exception.php
@@ -16,6 +16,6 @@ namespace phpbb\controller;
/**
* Controller exception class
*/
-class exception extends \RuntimeException
+class exception extends \phpbb\exception\runtime_exception
{
}
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/controller/resolver.php b/phpBB/phpbb/controller/resolver.php
index 948a6a218c..4f432c3323 100644
--- a/phpBB/phpbb/controller/resolver.php
+++ b/phpBB/phpbb/controller/resolver.php
@@ -23,12 +23,6 @@ use Symfony\Component\HttpFoundation\Request;
class resolver implements ControllerResolverInterface
{
/**
- * User object
- * @var \phpbb\user
- */
- protected $user;
-
- /**
* ContainerInterface object
* @var ContainerInterface
*/
@@ -55,14 +49,12 @@ class resolver implements ControllerResolverInterface
/**
* Construct method
*
- * @param \phpbb\user $user User Object
* @param ContainerInterface $container ContainerInterface object
* @param string $phpbb_root_path Relative path to phpBB root
* @param \phpbb\template\template $template
*/
- public function __construct(\phpbb\user $user, ContainerInterface $container, $phpbb_root_path, \phpbb\template\template $template = null)
+ public function __construct(ContainerInterface $container, $phpbb_root_path, \phpbb\template\template $template = null)
{
- $this->user = $user;
$this->container = $container;
$this->template = $template;
$this->type_cast_helper = new \phpbb\request\type_cast_helper();
@@ -82,20 +74,20 @@ class resolver implements ControllerResolverInterface
if (!$controller)
{
- throw new \phpbb\controller\exception($this->user->lang['CONTROLLER_NOT_SPECIFIED']);
+ throw new \phpbb\controller\exception('CONTROLLER_NOT_SPECIFIED');
}
// Require a method name along with the service name
if (stripos($controller, ':') === false)
{
- throw new \phpbb\controller\exception($this->user->lang['CONTROLLER_METHOD_NOT_SPECIFIED']);
+ throw new \phpbb\controller\exception('CONTROLLER_METHOD_NOT_SPECIFIED');
}
list($service, $method) = explode(':', $controller);
if (!$this->container->has($service))
{
- throw new \phpbb\controller\exception($this->user->lang('CONTROLLER_SERVICE_UNDEFINED', $service));
+ throw new \phpbb\controller\exception('CONTROLLER_SERVICE_UNDEFINED', array($service));
}
$controller_object = $this->container->get($service);
@@ -166,7 +158,7 @@ class resolver implements ControllerResolverInterface
}
else
{
- throw new \phpbb\controller\exception($this->user->lang('CONTROLLER_ARGUMENT_VALUE_MISSING', $param->getPosition() + 1, get_class($object) . ':' . $method, $param->name));
+ throw new \phpbb\controller\exception('CONTROLLER_ARGUMENT_VALUE_MISSING', array($param->getPosition() + 1, get_class($object) . ':' . $method, $param->name));
}
}
diff --git a/phpBB/phpbb/db/extractor/postgres_extractor.php b/phpBB/phpbb/db/extractor/postgres_extractor.php
index 9eff1f568d..a98e39621c 100644
--- a/phpBB/phpbb/db/extractor/postgres_extractor.php
+++ b/phpBB/phpbb/db/extractor/postgres_extractor.php
@@ -72,6 +72,7 @@ class postgres_extractor extends base_extractor
$this->flush($sql_data . ";\n");
}
}
+ $this->db->sql_freeresult($result);
$sql_data = '-- Table: ' . $table_name . "\n";
$sql_data .= "DROP TABLE $table_name;\n";
diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_14.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_14.php
new file mode 100644
index 0000000000..51475f5a05
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_14.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v30x;
+
+class release_3_0_14 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.0.14', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<');
+ }
+
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v30x\release_3_0_14_rc1');
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('if', array(
+ phpbb_version_compare($this->config['version'], '3.0.14', '<'),
+ array('config.update', array('version', '3.0.14')),
+ )),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_14_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_14_rc1.php
new file mode 100644
index 0000000000..421ef06dd3
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_14_rc1.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v30x;
+
+class release_3_0_14_rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.0.14-RC1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<');
+ }
+
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v30x\release_3_0_13');
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('if', array(
+ phpbb_version_compare($this->config['version'], '3.0.14-RC1', '<'),
+ array('config.update', array('version', '3.0.14-RC1')),
+ )),
+ );
+ }
+}
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/db/migration/data/v31x/v314.php b/phpBB/phpbb/db/migration/data/v31x/v314.php
new file mode 100644
index 0000000000..b7793ca569
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/v314.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 v314 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v30x\release_3_0_14',
+ '\phpbb\db\migration\data\v31x\v314rc2',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.1.4')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v31x/v314rc2.php b/phpBB/phpbb/db/migration/data/v31x/v314rc2.php
new file mode 100644
index 0000000000..b75b7a9be8
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/v314rc2.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 v314rc2 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v30x\release_3_0_14_rc1',
+ '\phpbb\db\migration\data\v31x\v314rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.1.4-RC2')),
+ );
+ }
+}
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/container_configuration.php b/phpBB/phpbb/di/extension/container_configuration.php
index ee58ec2b74..4cc7c7c0d1 100644
--- a/phpBB/phpbb/di/extension/container_configuration.php
+++ b/phpBB/phpbb/di/extension/container_configuration.php
@@ -34,6 +34,8 @@ class container_configuration implements ConfigurationInterface
->arrayNode('twig')
->addDefaultsIfNotSet()
->children()
+ ->booleanNode('debug')->defaultValue(null)->end()
+ ->booleanNode('auto_reload')->defaultValue(null)->end()
->booleanNode('enable_debug_extension')->defaultValue(false)->end()
->end()
->end()
diff --git a/phpBB/phpbb/di/extension/core.php b/phpBB/phpbb/di/extension/core.php
index c71dc61280..91b321a684 100644
--- a/phpBB/phpbb/di/extension/core.php
+++ b/phpBB/phpbb/di/extension/core.php
@@ -69,6 +69,20 @@ class core extends Extension
}
}
+ // Set the Twig options if defined in the environment
+ $definition = $container->getDefinition('template.twig.environment');
+ $twig_environment_options = $definition->getArgument(7);
+ if ($config['twig']['debug'])
+ {
+ $twig_environment_options['debug'] = true;
+ }
+ if ($config['twig']['auto_reload'])
+ {
+ $twig_environment_options['auto_reload'] = true;
+ }
+ // Replace the 8th argument, the options passed to the environment
+ $definition->replaceArgument(7, $twig_environment_options);
+
if ($config['twig']['enable_debug_extension'])
{
$definition = $container->getDefinition('template.twig.extensions.debug');
diff --git a/phpBB/phpbb/event/md_exporter.php b/phpBB/phpbb/event/md_exporter.php
index 84b10e79c1..e042d0a5d1 100644
--- a/phpBB/phpbb/event/md_exporter.php
+++ b/phpBB/phpbb/event/md_exporter.php
@@ -24,6 +24,12 @@ class md_exporter
/** @var string phpBB Root Path */
protected $root_path;
+ /** @var string The minimum version for the events to return */
+ protected $min_version;
+
+ /** @var string The maximum version for the events to return */
+ protected $max_version;
+
/** @var string */
protected $filter;
@@ -36,8 +42,10 @@ class md_exporter
/**
* @param string $phpbb_root_path
* @param mixed $extension String 'vendor/ext' to filter, null for phpBB core
+ * @param string $min_version
+ * @param string $max_version
*/
- public function __construct($phpbb_root_path, $extension = null)
+ public function __construct($phpbb_root_path, $extension = null, $min_version = null, $max_version = null)
{
$this->root_path = $phpbb_root_path;
$this->path = $this->root_path;
@@ -49,6 +57,8 @@ class md_exporter
$this->events = array();
$this->events_by_file = array();
$this->filter = $this->current_event = '';
+ $this->min_version = $min_version;
+ $this->max_version = $max_version;
}
/**
@@ -147,15 +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))
+ {
+ $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,
);
}
@@ -164,20 +223,48 @@ class md_exporter
}
/**
+ * The version to check
+ *
+ * @param string $version
+ * @return bool
+ */
+ protected function version_is_filtered($version)
+ {
+ return (!$this->min_version || phpbb_version_compare($this->min_version, $version, '<='))
+ && (!$this->max_version || phpbb_version_compare($this->max_version, $version, '>='));
+ }
+
+ /**
* Format the php events as a wiki table
+ *
+ * @param string $action
* @return string Number of events found
*/
- public function export_events_for_wiki()
+ public function export_events_for_wiki($action = '')
{
if ($this->filter === 'adm')
{
- $wiki_page = '= ACP Template Events =' . "\n";
+ if ($action === 'diff')
+ {
+ $wiki_page = '=== ACP Template Events ===' . "\n";
+ }
+ else
+ {
+ $wiki_page = '= ACP Template Events =' . "\n";
+ }
$wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n";
$wiki_page .= '! Identifier !! Placement !! Added in Release !! Explanation' . "\n";
}
else
{
- $wiki_page = '= Template Events =' . "\n";
+ if ($action === 'diff')
+ {
+ $wiki_page = '=== Template Events ===' . "\n";
+ }
+ else
+ {
+ $wiki_page = '= Template Events =' . "\n";
+ }
$wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n";
$wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Added in Release !! Explanation' . "\n";
}
@@ -227,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}'");
}
@@ -236,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 35144eeeec..d2ab0595c0 100644
--- a/phpBB/phpbb/event/php_exporter.php
+++ b/phpBB/phpbb/event/php_exporter.php
@@ -25,6 +25,12 @@ class php_exporter
/** @var string phpBB Root Path */
protected $root_path;
+ /** @var string The minimum version for the events to return */
+ protected $min_version;
+
+ /** @var string The maximum version for the events to return */
+ protected $max_version;
+
/** @var string */
protected $current_file;
@@ -43,14 +49,18 @@ class php_exporter
/**
* @param string $phpbb_root_path
* @param mixed $extension String 'vendor/ext' to filter, null for phpBB core
+ * @param string $min_version
+ * @param string $max_version
*/
- public function __construct($phpbb_root_path, $extension = null)
+ public function __construct($phpbb_root_path, $extension = null, $min_version = null, $max_version = null)
{
$this->root_path = $phpbb_root_path;
$this->path = $phpbb_root_path;
$this->events = $this->file_lines = array();
$this->current_file = $this->current_event = '';
$this->current_event_line = 0;
+ $this->min_version = $min_version;
+ $this->max_version = $max_version;
$this->path = $this->root_path;
if ($extension)
@@ -148,11 +158,20 @@ class php_exporter
/**
* Format the php events as a wiki table
+ *
+ * @param string $action
* @return string
*/
- public function export_events_for_wiki()
+ public function export_events_for_wiki($action = '')
{
- $wiki_page = '= PHP Events (Hook Locations) =' . "\n";
+ if ($action === 'diff')
+ {
+ $wiki_page = '=== PHP Events (Hook Locations) ===' . "\n";
+ }
+ else
+ {
+ $wiki_page = '= PHP Events (Hook Locations) =' . "\n";
+ }
$wiki_page .= '{| class="sortable zebra" cellspacing="0" cellpadding="5"' . "\n";
$wiki_page .= '! Identifier !! Placement !! Arguments !! Added in Release !! Explanation' . "\n";
foreach ($this->events as $event)
@@ -215,6 +234,34 @@ class php_exporter
$since_line_num = $this->find_since();
$since = $this->validate_since($this->file_lines[$since_line_num]);
+ $changed_line_nums = $this->find_changed('changed');
+ if (empty($changed_line_nums))
+ {
+ $changed_line_nums = $this->find_changed('change');
+ }
+ $changed_versions = array();
+ if (!empty($changed_line_nums))
+ {
+ foreach ($changed_line_nums as $changed_line_num)
+ {
+ $changed_versions[] = $this->validate_changed($this->file_lines[$changed_line_num]);
+ }
+ }
+
+ if (!$this->version_is_filtered($since))
+ {
+ $valid_version = false;
+ foreach ($changed_versions as $changed)
+ {
+ $valid_version = $valid_version || $this->version_is_filtered($changed);
+ }
+
+ if (!$valid_version)
+ {
+ continue;
+ }
+ }
+
// Find event description line
$description_line_num = $this->find_description();
$description = substr(trim($this->file_lines[$description_line_num]), strlen('* '));
@@ -243,6 +290,18 @@ class php_exporter
}
/**
+ * The version to check
+ *
+ * @param string $version
+ * @return bool
+ */
+ protected function version_is_filtered($version)
+ {
+ return (!$this->min_version || phpbb_version_compare($this->min_version, $version, '<='))
+ && (!$this->max_version || phpbb_version_compare($this->max_version, $version, '>='));
+ }
+
+ /**
* Find the name of the event inside the dispatch() line
*
* @param int $event_line
@@ -449,6 +508,33 @@ class php_exporter
}
/**
+ * Find the "@changed" Information lines
+ *
+ * @param string $tag_name Should be 'changed' or 'change'
+ * @return array Absolute line numbers
+ * @throws \LogicException
+ */
+ public function find_changed($tag_name)
+ {
+ $lines = array();
+ $last_line = 0;
+ try
+ {
+ while ($line = $this->find_tag($tag_name, array('since'), $last_line))
+ {
+ $lines[] = $line;
+ $last_line = $line;
+ }
+ }
+ catch (\LogicException $e)
+ {
+ // Not changed? No problem!
+ }
+
+ return $lines;
+ }
+
+ /**
* Find the "@event" Information line
*
* @return int Absolute line number
@@ -464,13 +550,14 @@ class php_exporter
* @param string $find_tag Name of the tag we are trying to find
* @param array $disallowed_tags List of tags that must not appear between
* the tag and the actual event
+ * @param int $skip_to_line Skip lines until this one
* @return int Absolute line number
* @throws \LogicException
*/
- public function find_tag($find_tag, $disallowed_tags)
+ public function find_tag($find_tag, $disallowed_tags, $skip_to_line = 0)
{
- $find_tag_line = 0;
- $found_comment_end = false;
+ $find_tag_line = $skip_to_line ? $this->current_event_line - $skip_to_line + 1 : 0;
+ $found_comment_end = ($skip_to_line) ? true : false;
while (strpos(ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t "), '* @' . $find_tag . ' ') !== 0)
{
if ($found_comment_end && ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t") === '/**')
@@ -561,6 +648,27 @@ class php_exporter
}
/**
+ * Validate "@changed" Information
+ *
+ * @param string $line
+ * @return string
+ * @throws \LogicException
+ */
+ public function validate_changed($line)
+ {
+ $match = array();
+ $line = str_replace("\t", ' ', ltrim($line, "\t "));
+ preg_match('#^\* @change(d)? (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)( (?:.*))?$#', $line, $match);
+ if (!isset($match[2]))
+ {
+ throw new \LogicException("Invalid '@changed' information for event "
+ . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'");
+ }
+
+ return $match[2];
+ }
+
+ /**
* Validate "@event" Information
*
* @param string $event_name
diff --git a/phpBB/phpbb/extension/exception.php b/phpBB/phpbb/extension/exception.php
index 3f7d251a4e..9050449bf1 100644
--- a/phpBB/phpbb/extension/exception.php
+++ b/phpBB/phpbb/extension/exception.php
@@ -16,10 +16,6 @@ namespace phpbb\extension;
/**
* Exception class for metadata
*/
-class exception extends \UnexpectedValueException
+class exception extends \phpbb\exception\runtime_exception
{
- public function __toString()
- {
- return $this->getMessage();
- }
}
diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php
index 40fda74065..98d2d27278 100644
--- a/phpBB/phpbb/extension/manager.php
+++ b/phpBB/phpbb/extension/manager.php
@@ -26,7 +26,6 @@ class manager
protected $db;
protected $config;
protected $cache;
- protected $user;
protected $php_ext;
protected $extensions;
protected $extension_table;
@@ -40,14 +39,13 @@ class manager
* @param \phpbb\db\driver\driver_interface $db A database connection
* @param \phpbb\config\config $config Config object
* @param \phpbb\filesystem\filesystem_interface $filesystem
- * @param \phpbb\user $user User object
* @param string $extension_table The name of the table holding extensions
* @param string $phpbb_root_path Path to the phpbb includes directory.
* @param string $php_ext php file extension, defaults to php
* @param \phpbb\cache\driver\driver_interface $cache A cache instance or null
* @param string $cache_name The name of the cache variable, defaults to _ext
*/
- public function __construct(ContainerInterface $container, \phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\filesystem\filesystem_interface $filesystem, \phpbb\user $user, $extension_table, $phpbb_root_path, $php_ext = 'php', \phpbb\cache\driver\driver_interface $cache = null, $cache_name = '_ext')
+ public function __construct(ContainerInterface $container, \phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\filesystem\filesystem_interface $filesystem, $extension_table, $phpbb_root_path, $php_ext = 'php', \phpbb\cache\driver\driver_interface $cache = null, $cache_name = '_ext')
{
$this->cache = $cache;
$this->cache_name = $cache_name;
@@ -58,7 +56,6 @@ class manager
$this->filesystem = $filesystem;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
- $this->user = $user;
$this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false;
@@ -154,7 +151,7 @@ class manager
*/
public function create_extension_metadata_manager($name, \phpbb\template\template $template)
{
- return new \phpbb\extension\metadata_manager($name, $this->config, $this, $template, $this->user, $this->phpbb_root_path);
+ return new \phpbb\extension\metadata_manager($name, $this->config, $this, $template, $this->phpbb_root_path);
}
/**
diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php
index a64d88fe39..4f080647c8 100644
--- a/phpBB/phpbb/extension/metadata_manager.php
+++ b/phpBB/phpbb/extension/metadata_manager.php
@@ -37,12 +37,6 @@ class metadata_manager
protected $template;
/**
- * phpBB User instance
- * @var \phpbb\user
- */
- protected $user;
-
- /**
* phpBB root path
* @var string
*/
@@ -73,15 +67,13 @@ class metadata_manager
* @param \phpbb\config\config $config phpBB Config instance
* @param \phpbb\extension\manager $extension_manager An instance of the phpBB extension manager
* @param \phpbb\template\template $template phpBB Template instance
- * @param \phpbb\user $user User instance
* @param string $phpbb_root_path Path to the phpbb includes directory.
*/
- public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template, \phpbb\user $user, $phpbb_root_path)
+ public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template, $phpbb_root_path)
{
$this->config = $config;
$this->extension_manager = $extension_manager;
$this->template = $template;
- $this->user = $user;
$this->phpbb_root_path = $phpbb_root_path;
$this->ext_name = $ext_name;
@@ -149,7 +141,7 @@ class metadata_manager
if (!file_exists($this->metadata_file))
{
- throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $this->metadata_file));
+ throw new \phpbb\extension\exception('FILE_NOT_FOUND', array($this->metadata_file));
}
}
@@ -163,18 +155,18 @@ class metadata_manager
{
if (!file_exists($this->metadata_file))
{
- throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $this->metadata_file));
+ throw new \phpbb\extension\exception('FILE_NOT_FOUND', array($this->metadata_file));
}
else
{
if (!($file_contents = file_get_contents($this->metadata_file)))
{
- throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file));
+ 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($this->user->lang('FILE_JSON_DECODE_ERR', $this->metadata_file));
+ throw new \phpbb\extension\exception('FILE_JSON_DECODE_ERR', array($this->metadata_file));
}
array_walk_recursive($metadata, array($this, 'sanitize_json'));
@@ -246,12 +238,12 @@ class metadata_manager
{
if (!isset($this->metadata[$name]))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', $name));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array($name));
}
if (!preg_match($fields[$name], $this->metadata[$name]))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_INVALID', $name));
+ throw new \phpbb\extension\exception('META_FIELD_INVALID', array($name));
}
}
break;
@@ -270,14 +262,14 @@ class metadata_manager
{
if (empty($this->metadata['authors']))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'authors'));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('authors'));
}
foreach ($this->metadata['authors'] as $author)
{
if (!isset($author['name']))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'author name'));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('author name'));
}
}
diff --git a/phpBB/phpbb/filesystem/filesystem.php b/phpBB/phpbb/filesystem/filesystem.php
index 370dff77e5..2112882d1d 100644
--- a/phpBB/phpbb/filesystem/filesystem.php
+++ b/phpBB/phpbb/filesystem/filesystem.php
@@ -613,7 +613,7 @@ class filesystem implements filesystem_interface
}
else
{
- $handle = @fopen($file, 'w');
+ $handle = @fopen($file, 'c');
if (is_resource($handle))
{
diff --git a/phpBB/phpbb/help/controller/bbcode.php b/phpBB/phpbb/help/controller/bbcode.php
new file mode 100644
index 0000000000..e16f99023d
--- /dev/null
+++ b/phpBB/phpbb/help/controller/bbcode.php
@@ -0,0 +1,85 @@
+<?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\help\controller;
+
+/**
+ * BBCode help page
+ */
+class bbcode extends controller
+{
+ /**
+ * @return string The title of the page
+ */
+ public function display()
+ {
+ $this->language->add_lang('help/bbcode');
+
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_INTRO',
+ false,
+ array(
+ 'HELP_BBCODE_INTRO_BBCODE_QUESTION' => 'HELP_BBCODE_INTRO_BBCODE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_TEXT',
+ false,
+ array(
+ 'HELP_BBCODE_TEXT_BASIC_QUESTION' => 'HELP_BBCODE_TEXT_BASIC_ANSWER',
+ 'HELP_BBCODE_TEXT_COLOR_QUESTION' => 'HELP_BBCODE_TEXT_COLOR_ANSWER',
+ 'HELP_BBCODE_TEXT_COMBINE_QUESTION' => 'HELP_BBCODE_TEXT_COMBINE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_QUOTES',
+ false,
+ array(
+ 'HELP_BBCODE_QUOTES_TEXT_QUESTION' => 'HELP_BBCODE_QUOTES_TEXT_ANSWER',
+ 'HELP_BBCODE_QUOTES_CODE_QUESTION' => 'HELP_BBCODE_QUOTES_CODE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_LISTS',
+ false,
+ array(
+ 'HELP_BBCODE_LISTS_UNORDERER_QUESTION' => 'HELP_BBCODE_LISTS_UNORDERER_ANSWER',
+ 'HELP_BBCODE_LISTS_ORDERER_QUESTION' => 'HELP_BBCODE_LISTS_ORDERER_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_LINKS',
+ true,
+ array(
+ 'HELP_BBCODE_LINKS_BASIC_QUESTION' => 'HELP_BBCODE_LINKS_BASIC_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_IMAGES',
+ false,
+ array(
+ 'HELP_BBCODE_IMAGES_BASIC_QUESTION' => 'HELP_BBCODE_IMAGES_BASIC_ANSWER',
+ 'HELP_BBCODE_IMAGES_ATTACHMENT_QUESTION' => 'HELP_BBCODE_IMAGES_ATTACHMENT_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_OTHERS',
+ false,
+ array(
+ 'HELP_BBCODE_OTHERS_CUSTOM_QUESTION' => 'HELP_BBCODE_OTHERS_CUSTOM_ANSWER',
+ )
+ );
+
+ return $this->language->lang('BBCODE_GUIDE');
+ }
+}
diff --git a/phpBB/phpbb/help/controller/controller.php b/phpBB/phpbb/help/controller/controller.php
new file mode 100644
index 0000000000..29494205a9
--- /dev/null
+++ b/phpBB/phpbb/help/controller/controller.php
@@ -0,0 +1,76 @@
+<?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\help\controller;
+
+/**
+ * BBCode help page
+ */
+abstract class controller
+{
+ /** @var \phpbb\controller\helper */
+ protected $helper;
+
+ /** @var \phpbb\help\manager */
+ protected $manager;
+
+ /** @var \phpbb\template\template */
+ protected $template;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var string */
+ protected $root_path;
+
+ /** @var string */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\controller\helper $helper
+ * @param \phpbb\help\manager $manager
+ * @param \phpbb\template\template $template
+ * @param \phpbb\language\language $language
+ * @param string $root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\controller\helper $helper, \phpbb\help\manager $manager, \phpbb\template\template $template, \phpbb\language\language $language, $root_path, $php_ext)
+ {
+ $this->helper = $helper;
+ $this->manager = $manager;
+ $this->template = $template;
+ $this->language = $language;
+ $this->root_path = $root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * @return string
+ */
+ abstract protected function display();
+
+ public function handle()
+ {
+ $title = $this->display();
+
+ $this->template->assign_vars(array(
+ 'L_FAQ_TITLE' => $title,
+ 'S_IN_FAQ' => true,
+ ));
+
+ make_jumpbox(append_sid("{$this->root_path}viewforum.{$this->php_ext}"));
+ return $this->helper->render('faq_body.html', $title);
+ }
+}
diff --git a/phpBB/phpbb/help/controller/faq.php b/phpBB/phpbb/help/controller/faq.php
new file mode 100644
index 0000000000..5e45cfe667
--- /dev/null
+++ b/phpBB/phpbb/help/controller/faq.php
@@ -0,0 +1,165 @@
+<?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\help\controller;
+
+/**
+ * FAQ help page
+ */
+class faq extends controller
+{
+ /**
+ * @return string The title of the page
+ */
+ public function display()
+ {
+ $this->language->add_lang('help/faq');
+
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_LOGIN',
+ false,
+ array(
+ 'HELP_FAQ_LOGIN_REGISTER_QUESTION' => 'HELP_FAQ_LOGIN_REGISTER_ANSWER',
+ 'HELP_FAQ_LOGIN_COPPA_QUESTION' => 'HELP_FAQ_LOGIN_COPPA_ANSWER',
+ 'HELP_FAQ_LOGIN_CANNOT_REGISTER_QUESTION' => 'HELP_FAQ_LOGIN_CANNOT_REGISTER_ANSWER',
+ 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_QUESTION' => 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_ANSWER',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_QUESTION' => 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANSWER',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_QUESTION' => 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_ANSWER',
+ 'HELP_FAQ_LOGIN_LOST_PASSWORD_QUESTION' => 'HELP_FAQ_LOGIN_LOST_PASSWORD_ANSWER',
+ 'HELP_FAQ_LOGIN_AUTO_LOGOUT_QUESTION' => 'HELP_FAQ_LOGIN_AUTO_LOGOUT_ANSWER',
+ 'HELP_FAQ_LOGIN_DELETE_COOKIES_QUESTION' => 'HELP_FAQ_LOGIN_DELETE_COOKIES_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_USERSETTINGS',
+ false,
+ array(
+ 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_QUESTION' => 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_QUESTION' => 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_TIMEZONE_QUESTION' => 'HELP_FAQ_USERSETTINGS_TIMEZONE_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_SERVERTIME_QUESTION' => 'HELP_FAQ_USERSETTINGS_SERVERTIME_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_LANGUAGE_QUESTION' => 'HELP_FAQ_USERSETTINGS_LANGUAGE_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_AVATAR_QUESTION' => 'HELP_FAQ_USERSETTINGS_AVATAR_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_QUESTION' => 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_RANK_QUESTION' => 'HELP_FAQ_USERSETTINGS_RANK_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_QUESTION' => 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_POSTING',
+ false,
+ array(
+ 'HELP_FAQ_POSTING_CREATE_QUESTION' => 'HELP_FAQ_POSTING_CREATE_ANSWER',
+ 'HELP_FAQ_POSTING_EDIT_DELETE_QUESTION' => 'HELP_FAQ_POSTING_EDIT_DELETE_ANSWER',
+ 'HELP_FAQ_POSTING_SIGNATURE_QUESTION' => 'HELP_FAQ_POSTING_SIGNATURE_ANSWER',
+ 'HELP_FAQ_POSTING_POLL_CREATE_QUESTION' => 'HELP_FAQ_POSTING_POLL_CREATE_ANSWER',
+ 'HELP_FAQ_POSTING_POLL_ADD_QUESTION' => 'HELP_FAQ_POSTING_POLL_ADD_ANSWER',
+ 'HELP_FAQ_POSTING_POLL_EDIT_QUESTION' => 'HELP_FAQ_POSTING_POLL_EDIT_ANSWER',
+ 'HELP_FAQ_POSTING_FORUM_RESTRICTED_QUESTION' => 'HELP_FAQ_POSTING_FORUM_RESTRICTED_ANSWER',
+ 'HELP_FAQ_POSTING_NO_ATTACHMENTS_QUESTION' => 'HELP_FAQ_POSTING_NO_ATTACHMENTS_ANSWER',
+ 'HELP_FAQ_POSTING_WARNING_QUESTION' => 'HELP_FAQ_POSTING_WARNING_ANSWER',
+ 'HELP_FAQ_POSTING_REPORT_QUESTION' => 'HELP_FAQ_POSTING_REPORT_ANSWER',
+ 'HELP_FAQ_POSTING_DRAFT_QUESTION' => 'HELP_FAQ_POSTING_DRAFT_ANSWER',
+ 'HELP_FAQ_POSTING_QUEUE_QUESTION' => 'HELP_FAQ_POSTING_QUEUE_ANSWER',
+ 'HELP_FAQ_POSTING_BUMP_QUESTION' => 'HELP_FAQ_POSTING_BUMP_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_FORMATTING',
+ false,
+ array(
+ 'HELP_FAQ_FORMATTING_BBOCDE_QUESTION' => 'HELP_FAQ_FORMATTING_BBOCDE_ANSWER',
+ 'HELP_FAQ_FORMATTING_HTML_QUESTION' => 'HELP_FAQ_FORMATTING_HTML_ANSWER',
+ 'HELP_FAQ_FORMATTING_SMILIES_QUESTION' => 'HELP_FAQ_FORMATTING_SMILIES_ANSWER',
+ 'HELP_FAQ_FORMATTING_IMAGES_QUESTION' => 'HELP_FAQ_FORMATTING_IMAGES_ANSWER',
+ 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_QUESTION' => 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_ANSWER',
+ 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_QUESTION' => 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_ANSWER',
+ 'HELP_FAQ_FORMATTING_STICKIES_QUESTION' => 'HELP_FAQ_FORMATTING_STICKIES_ANSWER',
+ 'HELP_FAQ_FORMATTING_LOCKED_QUESTION' => 'HELP_FAQ_FORMATTING_LOCKED_ANSWER',
+ 'HELP_FAQ_FORMATTING_ICONS_QUESTION' => 'HELP_FAQ_FORMATTING_ICONS_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_GROUPS',
+ true,
+ array(
+ 'HELP_FAQ_GROUPS_ADMINISTRATORS_QUESTION' => 'HELP_FAQ_GROUPS_ADMINISTRATORS_ANSWER',
+ 'HELP_FAQ_GROUPS_MODERATORS_QUESTION' => 'HELP_FAQ_GROUPS_MODERATORS_ANSWER',
+ 'HELP_FAQ_GROUPS_USERGROUPS_QUESTION' => 'HELP_FAQ_GROUPS_USERGROUPS_ANSWER',
+ 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_QUESTION' => 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_ANSWER',
+ 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_QUESTION' => 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_ANSWER',
+ 'HELP_FAQ_GROUPS_COLORS_QUESTION' => 'HELP_FAQ_GROUPS_COLORS_ANSWER',
+ 'HELP_FAQ_GROUPS_DEFAULT_QUESTION' => 'HELP_FAQ_GROUPS_DEFAULT_ANSWER',
+ 'HELP_FAQ_GROUPS_TEAM_QUESTION' => 'HELP_FAQ_GROUPS_TEAM_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_PMS',
+ false,
+ array(
+ 'HELP_FAQ_PMS_CANNOT_SEND_QUESTION' => 'HELP_FAQ_PMS_CANNOT_SEND_ANSWER',
+ 'HELP_FAQ_PMS_UNWANTED_QUESTION' => 'HELP_FAQ_PMS_UNWANTED_ANSWER',
+ 'HELP_FAQ_PMS_SPAM_QUESTION' => 'HELP_FAQ_PMS_SPAM_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_FRIENDS',
+ false,
+ array(
+ 'HELP_FAQ_FRIENDS_BASIC_QUESTION' => 'HELP_FAQ_FRIENDS_BASIC_ANSWER',
+ 'HELP_FAQ_FRIENDS_MANAGE_QUESTION' => 'HELP_FAQ_FRIENDS_MANAGE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_SEARCH',
+ false,
+ array(
+ 'HELP_FAQ_SEARCH_FORUM_QUESTION' => 'HELP_FAQ_SEARCH_FORUM_ANSWER',
+ 'HELP_FAQ_SEARCH_NO_RESULT_QUESTION' => 'HELP_FAQ_SEARCH_NO_RESULT_ANSWER',
+ 'HELP_FAQ_SEARCH_BLANK_QUESTION' => 'HELP_FAQ_SEARCH_BLANK_ANSWER',
+ 'HELP_FAQ_SEARCH_MEMBERS_QUESTION' => 'HELP_FAQ_SEARCH_MEMBERS_ANSWER',
+ 'HELP_FAQ_SEARCH_OWN_QUESTION' => 'HELP_FAQ_SEARCH_OWN_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_BOOKMARKS',
+ false,
+ array(
+ 'HELP_FAQ_BOOKMARKS_DIFFERENCE_QUESTION' => 'HELP_FAQ_BOOKMARKS_DIFFERENCE_ANSWER',
+ 'HELP_FAQ_BOOKMARKS_TOPIC_QUESTION' => 'HELP_FAQ_BOOKMARKS_TOPIC_ANSWER',
+ 'HELP_FAQ_BOOKMARKS_FORUM_QUESTION' => 'HELP_FAQ_BOOKMARKS_FORUM_ANSWER',
+ 'HELP_FAQ_BOOKMARKS_REMOVE_QUESTION' => 'HELP_FAQ_BOOKMARKS_REMOVE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_ATTACHMENTS',
+ false,
+ array(
+ 'HELP_FAQ_ATTACHMENTS_ALLOWED_QUESTION' => 'HELP_FAQ_ATTACHMENTS_ALLOWED_ANSWER',
+ 'HELP_FAQ_ATTACHMENTS_OWN_QUESTION' => 'HELP_FAQ_ATTACHMENTS_OWN_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_ISSUES',
+ false,
+ array(
+ 'HELP_FAQ_ISSUES_WHOIS_PHPBB_QUESTION' => 'HELP_FAQ_ISSUES_WHOIS_PHPBB_ANSWER',
+ 'HELP_FAQ_ISSUES_FEATURE_QUESTION' => 'HELP_FAQ_ISSUES_FEATURE_ANSWER',
+ 'HELP_FAQ_ISSUES_LEGAL_QUESTION' => 'HELP_FAQ_ISSUES_LEGAL_ANSWER',
+ 'HELP_FAQ_ISSUES_ADMIN_QUESTION' => 'HELP_FAQ_ISSUES_ADMIN_ANSWER',
+ )
+ );
+
+ return $this->language->lang('FAQ_EXPLAIN');
+ }
+}
diff --git a/phpBB/phpbb/help/manager.php b/phpBB/phpbb/help/manager.php
new file mode 100644
index 0000000000..d6991c0733
--- /dev/null
+++ b/phpBB/phpbb/help/manager.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\help;
+
+/**
+ * Class help page manager
+ */
+class manager
+{
+ /** @var \phpbb\event\dispatcher */
+ protected $dispatcher;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\template\template */
+ protected $template;
+
+ /** @var bool */
+ protected $switched_column;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\event\dispatcher $dispatcher
+ * @param \phpbb\language\language $language
+ * @param \phpbb\template\template $template
+ */
+ public function __construct(\phpbb\event\dispatcher $dispatcher, \phpbb\language\language $language, \phpbb\template\template $template)
+ {
+ $this->dispatcher = $dispatcher;
+ $this->language = $language;
+ $this->template = $template;
+ }
+
+ /**
+ * Add a new faq block
+ *
+ * @param string $block_name Name or language key with the name of the block
+ * @param bool $switch_column Switch the column of the menu
+ */
+ public function add_block($block_name, $switch_column = false, $questions = array())
+ {
+ /**
+ * You can use this event to add a block before the current one.
+ *
+ * @event core.help_manager_add_block_before
+ * @var string block_name Language key of the block headline
+ * @var bool switch_column Should we switch the menu column before this headline
+ * @var array questions Array with questions
+ * @since 3.2.0-a1
+ */
+ $vars = array('block_name', 'switch_column', 'questions');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_block_before', compact($vars)));
+
+ $this->template->assign_block_vars('faq_block', array(
+ 'BLOCK_TITLE' => $this->language->lang($block_name),
+ 'SWITCH_COLUMN' => !$this->switched_column && $switch_column,
+ ));
+
+ foreach ($questions as $question => $answer)
+ {
+ $this->add_question($question, $answer);
+ }
+
+ $this->switched_column = $this->switched_column || $switch_column;
+
+ /**
+ * You can use this event to add a block after the current one.
+ *
+ * @event core.help_manager_add_block_after
+ * @var string block_name Language key of the block headline
+ * @var bool switch_column Should we switch the menu column before this headline
+ * @var array questions Array with questions
+ * @since 3.2.0-a1
+ */
+ $vars = array('block_name', 'switch_column', 'questions');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_block_after', compact($vars)));
+ }
+
+ /**
+ * Add a new faq question
+ *
+ * @param string $question Question or language key with the question of the block
+ * @param string $answer Answer or language key with the answer of the block
+ */
+ public function add_question($question, $answer)
+ {
+ /**
+ * You can use this event to add a question before the current one.
+ *
+ * @event core.help_manager_add_question_before
+ * @var string question Language key of the question
+ * @var string answer Language key of the answer
+ * @since 3.2.0-a1
+ */
+ $vars = array('question', 'answer');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_question_before', compact($vars)));
+
+ $this->template->assign_block_vars('faq_block.faq_row', array(
+ 'FAQ_QUESTION' => $this->language->lang($question),
+ 'FAQ_ANSWER' => $this->language->lang($answer),
+ ));
+
+ /**
+ * You can use this event to add a question after the current one.
+ *
+ * @event core.help_manager_add_question_after
+ * @var string question Language key of the question
+ * @var string answer Language key of the answer
+ * @since 3.2.0-a1
+ */
+ $vars = array('question', 'answer');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_question_after', compact($vars)));
+ }
+
+ /**
+ * Returns whether the block titles switched side
+ * @return bool
+ */
+ public function switched_column()
+ {
+ return $this->switched_column;
+ }
+}
diff --git a/phpBB/phpbb/language/exception/invalid_plural_rule_exception.php b/phpBB/phpbb/language/exception/invalid_plural_rule_exception.php
new file mode 100644
index 0000000000..94e3466208
--- /dev/null
+++ b/phpBB/phpbb/language/exception/invalid_plural_rule_exception.php
@@ -0,0 +1,22 @@
+<?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\language\exception;
+
+/**
+ * Thrown when nonexistent plural rule is specified
+ */
+class invalid_plural_rule_exception extends language_exception
+{
+
+}
diff --git a/phpBB/phpbb/language/exception/language_exception.php b/phpBB/phpbb/language/exception/language_exception.php
new file mode 100644
index 0000000000..b1258414aa
--- /dev/null
+++ b/phpBB/phpbb/language/exception/language_exception.php
@@ -0,0 +1,22 @@
+<?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\language\exception;
+
+/**
+ * Base exception class for language exceptions
+ */
+class language_exception extends \phpbb\exception\runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/language/exception/language_file_not_found.php b/phpBB/phpbb/language/exception/language_file_not_found.php
new file mode 100644
index 0000000000..89364267eb
--- /dev/null
+++ b/phpBB/phpbb/language/exception/language_file_not_found.php
@@ -0,0 +1,22 @@
+<?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\language\exception;
+
+/**
+ * This exception is thrown when the language file is not found
+ */
+class language_file_not_found extends language_exception
+{
+
+}
diff --git a/phpBB/phpbb/language/language.php b/phpBB/phpbb/language/language.php
new file mode 100644
index 0000000000..b2b9f5ce12
--- /dev/null
+++ b/phpBB/phpbb/language/language.php
@@ -0,0 +1,566 @@
+<?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\language;
+
+use phpbb\language\exception\invalid_plural_rule_exception;
+
+/**
+ * Wrapper class for loading translations
+ */
+class language
+{
+ /**
+ * Global fallback language
+ *
+ * ISO code of the language to fallback to when the specified language entries
+ * cannot be found.
+ *
+ * @var string
+ */
+ const FALLBACK_LANGUAGE = 'en';
+
+ /**
+ * @var array List of common language files
+ */
+ protected $common_language_files;
+
+ /**
+ * @var bool
+ */
+ protected $common_language_files_loaded;
+
+ /**
+ * @var string ISO code of the default board language
+ */
+ protected $default_language;
+
+ /**
+ * @var string ISO code of the User's language
+ */
+ protected $user_language;
+
+ /**
+ * @var array Language fallback array (the order is important)
+ */
+ protected $language_fallback;
+
+ /**
+ * @var array Array of language variables
+ */
+ protected $lang;
+
+ /**
+ * @var array Loaded language sets
+ */
+ protected $loaded_language_sets;
+
+ /**
+ * @var \phpbb\language\language_file_loader Language file loader
+ */
+ protected $loader;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\language\language_file_loader $loader Language file loader
+ * @param array|null $common_modules Array of common language modules to load (optional)
+ */
+ public function __construct(language_file_loader $loader, $common_modules = null)
+ {
+ $this->loader = $loader;
+
+ // Set up default information
+ $this->user_language = false;
+ $this->default_language = false;
+ $this->lang = array();
+ $this->loaded_language_sets = array(
+ 'core' => array(),
+ 'ext' => array(),
+ );
+
+ // Common language files
+ if (is_array($common_modules))
+ {
+ $this->common_language_files = $common_modules;
+ }
+ else
+ {
+ $this->common_language_files = array(
+ 'common',
+ );
+ }
+
+ $this->common_language_files_loaded = false;
+
+ $this->language_fallback = array(self::FALLBACK_LANGUAGE);
+ }
+
+ /**
+ * Function to set user's language to display.
+ *
+ * @param string $user_lang_iso ISO code of the User's language
+ */
+ public function set_user_language($user_lang_iso)
+ {
+ $this->user_language = $user_lang_iso;
+
+ $this->set_fallback_array();
+ }
+
+ /**
+ * Function to set the board's default language to display.
+ *
+ * @param string $default_lang_iso ISO code of the board's default language
+ */
+ public function set_default_language($default_lang_iso)
+ {
+ $this->default_language = $default_lang_iso;
+
+ $this->set_fallback_array();
+ }
+
+ /**
+ * Returns language array
+ *
+ * Note: This function is needed for the BC purposes, until \phpbb\user::lang[] is
+ * not removed.
+ *
+ * @return array Array of loaded language strings
+ */
+ public function get_lang_array()
+ {
+ // Load common language files if they not loaded yet
+ if (!$this->common_language_files_loaded)
+ {
+ $this->load_common_language_files();
+ }
+
+ return $this->lang;
+ }
+
+ /**
+ * Add Language Items
+ *
+ * Examples:
+ * <code>
+ * $component = array('posting');
+ * $component = array('posting', 'viewtopic')
+ * $component = 'posting'
+ * </code>
+ *
+ * @param string|array $component The name of the language component to load
+ * @param string|null $extension_name Name of the extension to load component from, or null for core file
+ */
+ public function add_lang($component, $extension_name = null)
+ {
+ // Load common language files if they not loaded yet
+ // This needs to be here to correctly merge language arrays
+ if (!$this->common_language_files_loaded)
+ {
+ $this->load_common_language_files();
+ }
+
+ if (!is_array($component))
+ {
+ if (!is_null($extension_name))
+ {
+ $this->load_extension($extension_name, $component);
+ }
+ else
+ {
+ $this->load_core_file($component);
+ }
+ }
+ else
+ {
+ foreach ($component as $lang_file)
+ {
+ $this->add_lang($lang_file, $extension_name);
+ }
+ }
+ }
+
+ /**
+ * Advanced language substitution
+ *
+ * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms.
+ * Params are the language key and the parameters to be substituted.
+ * This function/functionality is inspired by SHS` and Ashe.
+ *
+ * Example call: <samp>$user->lang('NUM_POSTS_IN_QUEUE', 1);</samp>
+ *
+ * If the first parameter is an array, the elements are used as keys and subkeys to get the language entry:
+ * Example: <samp>$user->lang(array('datetime', 'AGO'), 1)</samp> uses $user->lang['datetime']['AGO'] as language entry.
+ *
+ * @return string Return localized string or the language key if the translation is not available
+ */
+ public function lang()
+ {
+ // Load common language files if they not loaded yet
+ if (!$this->common_language_files_loaded)
+ {
+ $this->load_common_language_files();
+ }
+
+ $args = func_get_args();
+ $key = $args[0];
+
+ if (is_array($key))
+ {
+ $lang = &$this->lang[array_shift($key)];
+
+ foreach ($key as $_key)
+ {
+ $lang = &$lang[$_key];
+ }
+ }
+ else
+ {
+ $lang = &$this->lang[$key];
+ }
+
+ // Return if language string does not exist
+ if (!isset($lang) || (!is_string($lang) && !is_array($lang)))
+ {
+ return $key;
+ }
+
+ // If the language entry is a string, we simply mimic sprintf() behaviour
+ if (is_string($lang))
+ {
+ if (sizeof($args) == 1)
+ {
+ return $lang;
+ }
+
+ // Replace key with language entry and simply pass along...
+ $args[0] = $lang;
+ return call_user_func_array('sprintf', $args);
+ }
+ else if (sizeof($lang) == 0)
+ {
+ // If the language entry is an empty array, we just return the language key
+ return $args[0];
+ }
+
+ // It is an array... now handle different nullar/singular/plural forms
+ $key_found = false;
+
+ // We now get the first number passed and will select the key based upon this number
+ for ($i = 1, $num_args = sizeof($args); $i < $num_args; $i++)
+ {
+ if (is_int($args[$i]) || is_float($args[$i]))
+ {
+ if ($args[$i] == 0 && isset($lang[0]))
+ {
+ // We allow each translation using plural forms to specify a version for the case of 0 things,
+ // so that "0 users" may be displayed as "No users".
+ $key_found = 0;
+ break;
+ }
+ else
+ {
+ $use_plural_form = $this->get_plural_form($args[$i]);
+ if (isset($lang[$use_plural_form]))
+ {
+ // The key we should use exists, so we use it.
+ $key_found = $use_plural_form;
+ }
+ else
+ {
+ // If the key we need to use does not exist, we fall back to the previous one.
+ $numbers = array_keys($lang);
+
+ foreach ($numbers as $num)
+ {
+ if ($num > $use_plural_form)
+ {
+ break;
+ }
+
+ $key_found = $num;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form)
+ if ($key_found === false)
+ {
+ $numbers = array_keys($lang);
+ $key_found = end($numbers);
+ }
+
+ // Use the language string we determined and pass it to sprintf()
+ $args[0] = $lang[$key_found];
+ return call_user_func_array('sprintf', $args);
+ }
+
+ /**
+ * Loads common language files
+ */
+ protected function load_common_language_files()
+ {
+ if (!$this->common_language_files_loaded)
+ {
+ foreach ($this->common_language_files as $lang_file)
+ {
+ $this->load_core_file($lang_file);
+ }
+
+ $this->common_language_files_loaded = true;
+ }
+ }
+
+ /**
+ * Determine which plural form we should use.
+ *
+ * For some languages this is not as simple as for English.
+ *
+ * @param int|float $number The number we want to get the plural case for. Float numbers are floored.
+ * @param int|bool $force_rule False to use the plural rule of the language package
+ * or an integer to force a certain plural rule
+ *
+ * @return int The plural-case we need to use for the number plural-rule combination
+ *
+ * @throws \phpbb\language\exception\invalid_plural_rule_exception When $force_rule has an invalid value
+ */
+ public function get_plural_form($number, $force_rule = false)
+ {
+ $number = (int) $number;
+ $plural_rule = ($force_rule !== false) ? $force_rule : ((isset($this->lang['PLURAL_RULE'])) ? $this->lang['PLURAL_RULE'] : 1);
+
+ if ($plural_rule > 15 || $plural_rule < 0)
+ {
+ throw new invalid_plural_rule_exception('INVALID_PLURAL_RULE', array(
+ 'plural_rule' => $plural_rule,
+ ));
+ }
+
+ /**
+ * The following plural rules are based on a list published by the Mozilla Developer Network
+ * https://developer.mozilla.org/en/Localization_and_Plurals
+ */
+ switch ($plural_rule)
+ {
+ case 0:
+ /**
+ * Families: Asian (Chinese, Japanese, Korean, Vietnamese), Persian, Turkic/Altaic (Turkish), Thai, Lao
+ * 1 - everything: 0, 1, 2, ...
+ */
+ return 1;
+
+ case 1:
+ /**
+ * Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan)
+ * 1 - 1
+ * 2 - everything else: 0, 2, 3, ...
+ */
+ return ($number === 1) ? 1 : 2;
+
+ case 2:
+ /**
+ * Families: Romanic (French, Brazilian Portuguese)
+ * 1 - 0, 1
+ * 2 - everything else: 2, 3, ...
+ */
+ return (($number === 0) || ($number === 1)) ? 1 : 2;
+
+ case 3:
+ /**
+ * Families: Baltic (Latvian)
+ * 1 - 0
+ * 2 - ends in 1, not 11: 1, 21, ... 101, 121, ...
+ * 3 - everything else: 2, 3, ... 10, 11, 12, ... 20, 22, ...
+ */
+ return ($number === 0) ? 1 : ((($number % 10 === 1) && ($number % 100 != 11)) ? 2 : 3);
+
+ case 4:
+ /**
+ * Families: Celtic (Scottish Gaelic)
+ * 1 - is 1 or 11: 1, 11
+ * 2 - is 2 or 12: 2, 12
+ * 3 - others between 3 and 19: 3, 4, ... 10, 13, ... 18, 19
+ * 4 - everything else: 0, 20, 21, ...
+ */
+ return ($number === 1 || $number === 11) ? 1 : (($number === 2 || $number === 12) ? 2 : (($number >= 3 && $number <= 19) ? 3 : 4));
+
+ case 5:
+ /**
+ * Families: Romanic (Romanian)
+ * 1 - 1
+ * 2 - is 0 or ends in 01-19: 0, 2, 3, ... 19, 101, 102, ... 119, 201, ...
+ * 3 - everything else: 20, 21, ...
+ */
+ return ($number === 1) ? 1 : ((($number === 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 2 : 3);
+
+ case 6:
+ /**
+ * Families: Baltic (Lithuanian)
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
+ * 2 - ends in 0 or ends in 10-20: 0, 10, 11, 12, ... 19, 20, 30, 40, ...
+ * 3 - everything else: 2, 3, ... 8, 9, 22, 23, ... 29, 32, 33, ...
+ */
+ return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 < 2) || (($number % 100 >= 10) && ($number % 100 < 20))) ? 2 : 3);
+
+ case 7:
+ /**
+ * Families: Slavic (Croatian, Serbian, Russian, Ukrainian)
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
+ * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ...
+ * 3 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26, ...
+ */
+ return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 2 : 3);
+
+ case 8:
+ /**
+ * Families: Slavic (Slovak, Czech)
+ * 1 - 1
+ * 2 - 2, 3, 4
+ * 3 - everything else: 0, 5, 6, 7, ...
+ */
+ return ($number === 1) ? 1 : ((($number >= 2) && ($number <= 4)) ? 2 : 3);
+
+ case 9:
+ /**
+ * Families: Slavic (Polish)
+ * 1 - 1
+ * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... 104, 122, ...
+ * 3 - everything else: 0, 5, 6, ... 11, 12, 13, 14, 15, ... 20, 21, 25, ...
+ */
+ return ($number === 1) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 2 : 3);
+
+ case 10:
+ /**
+ * Families: Slavic (Slovenian, Sorbian)
+ * 1 - ends in 01: 1, 101, 201, ...
+ * 2 - ends in 02: 2, 102, 202, ...
+ * 3 - ends in 03-04: 3, 4, 103, 104, 203, 204, ...
+ * 4 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, ...
+ */
+ return ($number % 100 === 1) ? 1 : (($number % 100 === 2) ? 2 : ((($number % 100 === 3) || ($number % 100 === 4)) ? 3 : 4));
+
+ case 11:
+ /**
+ * Families: Celtic (Irish Gaeilge)
+ * 1 - 1
+ * 2 - 2
+ * 3 - is 3-6: 3, 4, 5, 6
+ * 4 - is 7-10: 7, 8, 9, 10
+ * 5 - everything else: 0, 11, 12, ...
+ */
+ return ($number === 1) ? 1 : (($number === 2) ? 2 : (($number >= 3 && $number <= 6) ? 3 : (($number >= 7 && $number <= 10) ? 4 : 5)));
+
+ case 12:
+ /**
+ * Families: Semitic (Arabic)
+ * 1 - 1
+ * 2 - 2
+ * 3 - ends in 03-10: 3, 4, ... 10, 103, 104, ... 110, 203, 204, ...
+ * 4 - ends in 11-99: 11, ... 99, 111, 112, ...
+ * 5 - everything else: 100, 101, 102, 200, 201, 202, ...
+ * 6 - 0
+ */
+ return ($number === 1) ? 1 : (($number === 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : (($number != 0) ? 5 : 6))));
+
+ case 13:
+ /**
+ * Families: Semitic (Maltese)
+ * 1 - 1
+ * 2 - is 0 or ends in 01-10: 0, 2, 3, ... 9, 10, 101, 102, ...
+ * 3 - ends in 11-19: 11, 12, ... 18, 19, 111, 112, ...
+ * 4 - everything else: 20, 21, ...
+ */
+ return ($number === 1) ? 1 : ((($number === 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 2 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 3 : 4));
+
+ case 14:
+ /**
+ * Families: Slavic (Macedonian)
+ * 1 - ends in 1: 1, 11, 21, ...
+ * 2 - ends in 2: 2, 12, 22, ...
+ * 3 - everything else: 0, 3, 4, ... 10, 13, 14, ... 20, 23, ...
+ */
+ return ($number % 10 === 1) ? 1 : (($number % 10 === 2) ? 2 : 3);
+
+ case 15:
+ /**
+ * Families: Icelandic
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, 131, ...
+ * 2 - everything else: 0, 2, 3, ... 10, 11, 12, ... 20, 22, ...
+ */
+ return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : 2;
+ }
+ }
+
+ /**
+ * Returns language fallback data
+ *
+ * @return array
+ */
+ protected function set_fallback_array()
+ {
+ $fallback_array = array();
+
+ if ($this->user_language !== false)
+ {
+ $fallback_array[] = $this->user_language;
+ }
+
+ if ($this->default_language !== false)
+ {
+ $fallback_array[] = $this->default_language;
+ }
+
+ $fallback_array[] = self::FALLBACK_LANGUAGE;
+
+ $this->language_fallback = $fallback_array;
+ }
+
+ /**
+ * Load core language file
+ *
+ * @param string $component Name of the component to load
+ */
+ protected function load_core_file($component)
+ {
+ // Check if the component is already loaded
+ if (isset($this->loaded_language_sets['core'][$component]))
+ {
+ return;
+ }
+
+ $this->loader->load($component, $this->language_fallback, $this->lang);
+ $this->loaded_language_sets['core'][$component] = true;
+ }
+
+ /**
+ * Load extension language file
+ *
+ * @param string $extension_name Name of the extension to load language from
+ * @param string $component Name of the component to load
+ */
+ protected function load_extension($extension_name, $component)
+ {
+ // Check if the component is already loaded
+ if (isset($this->loaded_language_sets['ext'][$extension_name][$component]))
+ {
+ return;
+ }
+
+ $this->loader->load_extension($extension_name, $component, $this->language_fallback, $this->lang);
+ $this->loaded_language_sets['ext'][$extension_name][$component] = true;
+ }
+}
diff --git a/phpBB/phpbb/language/language_file_helper.php b/phpBB/phpbb/language/language_file_helper.php
new file mode 100644
index 0000000000..18d7b62e21
--- /dev/null
+++ b/phpBB/phpbb/language/language_file_helper.php
@@ -0,0 +1,71 @@
+<?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\language;
+
+use Symfony\Component\Finder\Finder;
+
+/**
+ * Helper class for language file related functions
+ */
+class language_file_helper
+{
+ /**
+ * @var string Path to phpBB's root
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param string $phpbb_root_path Path to phpBB's root
+ */
+ public function __construct($phpbb_root_path)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * Returns available languages
+ *
+ * @return array
+ */
+ public function get_available_languages()
+ {
+ // Find available language packages
+ $finder = new Finder();
+ $finder->files()
+ ->name('iso.txt')
+ ->depth('== 1')
+ ->in($this->phpbb_root_path . 'language');
+
+ $available_languages = array();
+ foreach ($finder as $file)
+ {
+ $path = $file->getRelativePath();
+ $info = explode("\n", $file->getContents());
+
+ $available_languages[] = array(
+ // Get the name of the directory containing iso.txt
+ 'iso' => $path,
+
+ // Recover data from file
+ 'name' => trim($info[0]),
+ 'local_name' => trim($info[1]),
+ 'author' => trim($info[2])
+ );
+ }
+
+ return $available_languages;
+ }
+}
diff --git a/phpBB/phpbb/language/language_file_loader.php b/phpBB/phpbb/language/language_file_loader.php
new file mode 100644
index 0000000000..9862cfc3aa
--- /dev/null
+++ b/phpBB/phpbb/language/language_file_loader.php
@@ -0,0 +1,206 @@
+<?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\language;
+
+use \phpbb\language\exception\language_file_not_found;
+
+/**
+ * Language file loader
+ */
+class language_file_loader
+{
+ /**
+ * @var string Path to phpBB's root
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string Extension of PHP files
+ */
+ protected $php_ext;
+
+ /**
+ * @var \phpbb\extension\manager Extension manager
+ */
+ protected $extension_manager;
+
+ /**
+ * Constructor
+ *
+ * @param string $phpbb_root_path Path to phpBB's root
+ * @param string $php_ext Extension of PHP files
+ */
+ public function __construct($phpbb_root_path, $php_ext)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->extension_manager = null;
+ }
+
+ /**
+ * Extension manager setter
+ *
+ * @param \phpbb\extension\manager $extension_manager Extension manager
+ */
+ public function set_extension_manager(\phpbb\extension\manager $extension_manager)
+ {
+ $this->extension_manager = $extension_manager;
+ }
+
+ /**
+ * Loads language array for the given component
+ *
+ * @param string $component Name of the language component
+ * @param string|array $locale ISO code of the language to load, or array of ISO codes if you want to
+ * specify additional language fallback steps
+ * @param array $lang Array reference containing language strings
+ */
+ public function load($component, $locale, &$lang)
+ {
+ $locale = (array) $locale;
+
+ // Determine path to language directory
+ $path = $this->phpbb_root_path . 'language/';
+
+ $this->load_file($path, $component, $locale, $lang);
+ }
+
+ /**
+ * Loads language array for the given extension component
+ *
+ * @param string $extension Name of the extension
+ * @param string $component Name of the language component
+ * @param string|array $locale ISO code of the language to load, or array of ISO codes if you want to
+ * specify additional language fallback steps
+ * @param array $lang Array reference containing language strings
+ */
+ public function load_extension($extension, $component, $locale, &$lang)
+ {
+ // Check if extension manager was loaded
+ if ($this->extension_manager === null)
+ {
+ // If not, let's return
+ return;
+ }
+
+ $locale = (array) $locale;
+
+ // Determine path to language directory
+ $path = $this->extension_manager->get_extension_path($extension, true) . 'language/';
+
+ $this->load_file($path, $component, $locale, $lang);
+ }
+
+ /**
+ * Prepares language file loading
+ *
+ * @param string $path Path to search for file in
+ * @param string $component Name of the language component
+ * @param array $locale Array containing language fallback options
+ * @param array $lang Array reference of language strings
+ */
+ protected function load_file($path, $component, $locale, &$lang)
+ {
+ // This is BC stuff and not the best idea as it makes language fallback
+ // implementation quite hard like below.
+ if (strpos($this->phpbb_root_path . $component, $path) === 0)
+ {
+ // Filter out the path
+ $path_diff = str_replace($path, '', dirname($this->phpbb_root_path . $component));
+ $language_file = basename($component, '.' . $this->php_ext);
+ $component = '';
+
+ // This step is needed to resolve language/en/subdir style $component
+ // $path already points to the language base directory so we need to eliminate
+ // the first directory from the path (that should be the language directory)
+ $path_diff_parts = explode('/', $path_diff);
+
+ if (sizeof($path_diff_parts) > 1)
+ {
+ array_shift($path_diff_parts);
+ $component = implode('/', $path_diff_parts) . '/';
+ }
+
+ $component .= $language_file;
+ }
+
+ // Determine filename
+ $filename = $component . '.' . $this->php_ext;
+
+ // Determine path to file
+ $file_path = $this->get_language_file_path($path, $filename, $locale);
+
+ // Load language array
+ $this->load_language_file($file_path, $lang);
+ }
+
+ /**
+ * This function implements language fallback logic
+ *
+ * @param string $path Path to language directory
+ * @param string $filename Filename to load language strings from
+ *
+ * @return string Relative path to language file
+ *
+ * @throws \phpbb\language\exception\language_file_not_found When the path to the file cannot be resolved
+ */
+ protected function get_language_file_path($path, $filename, $locales)
+ {
+ $language_file_path = $filename;
+
+ // Language fallback logic
+ foreach ($locales as $locale)
+ {
+ $language_file_path = $path . $locale . '/' . $filename;
+
+ // If we are in install, try to use the updated version, when available
+ if (defined('IN_INSTALL'))
+ {
+ $install_language_path = str_replace('language/', 'install/update/new/language/', $language_file_path);
+ if (file_exists($install_language_path))
+ {
+ return $install_language_path;
+ }
+ }
+
+ if (file_exists($language_file_path))
+ {
+ return $language_file_path;
+ }
+ }
+
+ // The language file is not exist
+ throw new language_file_not_found('Language file ' . $language_file_path . ' couldn\'t be opened.');
+ }
+
+ /**
+ * Loads language file
+ *
+ * @param string $path Path to language file to load
+ * @param array $lang Reference of the array of language strings
+ */
+ protected function load_language_file($path, &$lang)
+ {
+ // Do not suppress error if in DEBUG mode
+ if (defined('DEBUG'))
+ {
+ include $path;
+ }
+ else
+ {
+ @include $path;
+ }
+ }
+}
diff --git a/phpBB/phpbb/log/null.php b/phpBB/phpbb/log/dummy.php
index baa78895ea..5c2d145e15 100644
--- a/phpBB/phpbb/log/null.php
+++ b/phpBB/phpbb/log/dummy.php
@@ -14,9 +14,9 @@
namespace phpbb\log;
/**
-* Null logger
+* Dummy logger
*/
-class null implements log_interface
+class dummy implements log_interface
{
/**
* {@inheritdoc}
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/exception.php b/phpBB/phpbb/notification/exception.php
index 83c4526df7..e416438061 100644
--- a/phpBB/phpbb/notification/exception.php
+++ b/phpBB/phpbb/notification/exception.php
@@ -17,10 +17,6 @@ namespace phpbb\notification;
* Notifications exception
*/
-class exception extends \Exception
+class exception extends \phpbb\exception\runtime_exception
{
- public function __toString()
- {
- return $this->getMessage();
- }
}
diff --git a/phpBB/phpbb/notification/manager.php b/phpBB/phpbb/notification/manager.php
index db92170dd8..38d7a13165 100644
--- a/phpBB/phpbb/notification/manager.php
+++ b/phpBB/phpbb/notification/manager.php
@@ -943,7 +943,7 @@ class manager
{
if (!isset($this->notification_types[$notification_type_name]) && !isset($this->notification_types['notification.type.' . $notification_type_name]))
{
- throw new \phpbb\notification\exception($this->user->lang('NOTIFICATION_TYPE_NOT_EXIST', $notification_type_name));
+ throw new \phpbb\notification\exception('NOTIFICATION_TYPE_NOT_EXIST', array($notification_type_name));
}
$sql = 'INSERT INTO ' . $this->notification_types_table . ' ' . $this->db->sql_build_array('INSERT', array(
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=&quot;(.+?)&quot;#';
-
- /**
* 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/permissions.php b/phpBB/phpbb/permissions.php
index 9b3dcadf32..82f59b5c20 100644
--- a/phpBB/phpbb/permissions.php
+++ b/phpBB/phpbb/permissions.php
@@ -277,13 +277,14 @@ class permissions
'm_approve' => array('lang' => 'ACL_M_APPROVE', 'cat' => 'post_actions'),
'm_report' => array('lang' => 'ACL_M_REPORT', 'cat' => 'post_actions'),
'm_chgposter' => array('lang' => 'ACL_M_CHGPOSTER', 'cat' => 'post_actions'),
+ 'm_info' => array('lang' => 'ACL_M_INFO', 'cat' => 'post_actions'),
+ 'm_softdelete' => array('lang' => 'ACL_M_SOFTDELETE', 'cat' => 'post_actions'),
'm_move' => array('lang' => 'ACL_M_MOVE', 'cat' => 'topic_actions'),
'm_lock' => array('lang' => 'ACL_M_LOCK', 'cat' => 'topic_actions'),
'm_split' => array('lang' => 'ACL_M_SPLIT', 'cat' => 'topic_actions'),
'm_merge' => array('lang' => 'ACL_M_MERGE', 'cat' => 'topic_actions'),
- 'm_info' => array('lang' => 'ACL_M_INFO', 'cat' => 'misc'),
'm_warn' => array('lang' => 'ACL_M_WARN', 'cat' => 'misc'),
'm_ban' => array('lang' => 'ACL_M_BAN', 'cat' => 'misc'),
diff --git a/phpBB/phpbb/routing/router.php b/phpBB/phpbb/routing/router.php
index 7444f06253..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;
@@ -94,13 +95,14 @@ class router implements RouterInterface
* Construct method
*
* @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem helper
- * @param manager $extension_manager Extension manager
- * @param string $phpbb_root_path phpBB root path
- * @param string $php_ext PHP file extension
- * @param string $environment Name of the current environment
- * @param array $routing_files Array of strings containing paths to YAML files holding route information
+ * @param string $phpbb_root_path phpBB root path
+ * @param string $php_ext PHP file extension
+ * @param string $environment Name of the current environment
+ * @param manager|null $extension_manager Extension manager
+ * @param array $routing_files Array of strings containing paths to YAML files
+ * holding route information
*/
- public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, manager $extension_manager, $phpbb_root_path, $php_ext, $environment, $routing_files = array())
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path, $php_ext, $environment, manager $extension_manager = null, $routing_files = array())
{
$this->filesystem = $filesystem;
$this->extension_manager = $extension_manager;
@@ -172,7 +174,9 @@ class router implements RouterInterface
{
if ($this->route_collection == null || empty($this->routing_files))
{
- $this->find_routing_files($this->extension_manager->all_enabled(false))
+ $this->find_routing_files(
+ ($this->extension_manager !== null) ? $this->extension_manager->all_enabled(false) : array()
+ )
->find($this->phpbb_root_path);
}
@@ -249,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();
+ }
}
/**
@@ -297,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/template/asset.php b/phpBB/phpbb/template/asset.php
index 4729685459..cb00f16549 100644
--- a/phpBB/phpbb/template/asset.php
+++ b/phpBB/phpbb/template/asset.php
@@ -20,15 +20,20 @@ class asset
/** @var \phpbb\path_helper **/
protected $path_helper;
+ /** @var \phpbb\filesystem\filesystem */
+ protected $filesystem;
+
/**
* Constructor
*
* @param string $url URL
* @param \phpbb\path_helper $path_helper Path helper object
+ * @param \phpbb\filesystem\filesystem $filesystem
*/
- public function __construct($url, \phpbb\path_helper $path_helper)
+ public function __construct($url, \phpbb\path_helper $path_helper, \phpbb\filesystem\filesystem $filesystem)
{
$this->path_helper = $path_helper;
+ $this->filesystem = $filesystem;
$this->set_url($url);
}
@@ -152,10 +157,22 @@ class asset
*/
public function set_path($path, $urlencode = false)
{
- // Since 1.7.0 Twig returns the real path of the file. We need it to be relative to the working directory.
- $real_root_path = realpath('.') . DIRECTORY_SEPARATOR;
- if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path) {
- $path = str_replace('\\', '/', substr($path, strlen($real_root_path)));
+ // Since 1.7.0 Twig returns the real path of the file. We need it to be relative.
+ $real_root_path = $this->filesystem->realpath($this->path_helper->get_phpbb_root_path()) . DIRECTORY_SEPARATOR;
+
+ // If the asset is under the phpBB root path we need to remove its path and then prepend $phpbb_root_path
+ if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path)
+ {
+ $path = $this->path_helper->get_phpbb_root_path() . str_replace('\\', '/', substr($path, strlen($real_root_path)));
+ }
+ else
+ {
+ // Else we make the path relative to the current working directory
+ $real_root_path = $this->filesystem->realpath('.') . DIRECTORY_SEPARATOR;
+ if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path)
+ {
+ $path = str_replace('\\', '/', substr($path, strlen($real_root_path)));
+ }
}
if ($urlencode)
diff --git a/phpBB/phpbb/template/exception/user_object_not_available.php b/phpBB/phpbb/template/exception/user_object_not_available.php
new file mode 100644
index 0000000000..62fd2743c1
--- /dev/null
+++ b/phpBB/phpbb/template/exception/user_object_not_available.php
@@ -0,0 +1,22 @@
+<?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\template\exception;
+
+/**
+ * This exception is thrown when the user object was not set but it is required by the called method
+ */
+class user_object_not_available extends \phpbb\exception\runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/template/twig/environment.php b/phpBB/phpbb/template/twig/environment.php
index 0ba7a265e4..6e75403159 100644
--- a/phpBB/phpbb/template/twig/environment.php
+++ b/phpBB/phpbb/template/twig/environment.php
@@ -18,6 +18,9 @@ class environment extends \Twig_Environment
/** @var \phpbb\config\config */
protected $phpbb_config;
+ /** @var \phpbb\filesystem\filesystem */
+ protected $filesystem;
+
/** @var \phpbb\path_helper */
protected $phpbb_path_helper;
@@ -40,6 +43,7 @@ class environment extends \Twig_Environment
* Constructor
*
* @param \phpbb\config\config $phpbb_config The phpBB configuration
+ * @param \phpbb\filesystem\filesystem $filesystem
* @param \phpbb\path_helper $path_helper phpBB path helper
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container The dependency injection container
* @param string $cache_path The path to the cache directory
@@ -47,10 +51,11 @@ class environment extends \Twig_Environment
* @param \Twig_LoaderInterface $loader Twig loader interface
* @param array $options Array of options to pass to Twig
*/
- public function __construct($phpbb_config, \phpbb\path_helper $path_helper, \Symfony\Component\DependencyInjection\ContainerInterface $container, $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, \Symfony\Component\DependencyInjection\ContainerInterface $container, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, $options = array())
{
$this->phpbb_config = $phpbb_config;
+ $this->filesystem = $filesystem;
$this->phpbb_path_helper = $path_helper;
$this->extension_manager = $extension_manager;
$this->container = $container;
@@ -60,7 +65,7 @@ class environment extends \Twig_Environment
$options = array_merge(array(
'cache' => (defined('IN_INSTALL')) ? false : $cache_path,
- 'debug' => defined('DEBUG'),
+ 'debug' => false,
'auto_reload' => (bool) $this->phpbb_config['load_tplcompile'],
'autoescape' => false,
), $options);
@@ -106,16 +111,26 @@ class environment extends \Twig_Environment
}
/**
- * Get the phpBB root path
- *
- * @return string
- */
+ * Get the phpBB root path
+ *
+ * @return string
+ */
public function get_phpbb_root_path()
{
return $this->phpbb_root_path;
}
/**
+ * Get the filesystem object
+ *
+ * @return \phpbb\filesystem\filesystem
+ */
+ public function get_filesystem()
+ {
+ return $this->filesystem;
+ }
+
+ /**
* Get the web root path
*
* @return string
diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php
index 14d1258c09..92f87a0331 100644
--- a/phpBB/phpbb/template/twig/extension.php
+++ b/phpBB/phpbb/template/twig/extension.php
@@ -18,20 +18,20 @@ class extension extends \Twig_Extension
/** @var \phpbb\template\context */
protected $context;
- /** @var \phpbb\user */
- protected $user;
+ /** @var \phpbb\language\language */
+ protected $language;
/**
* Constructor
*
* @param \phpbb\template\context $context
- * @param \phpbb\user $user
+ * @param \phpbb\language\language $language
* @return \phpbb\template\twig\extension
*/
- public function __construct(\phpbb\template\context $context, $user)
+ public function __construct(\phpbb\template\context $context, $language)
{
$this->context = $context;
- $this->user = $user;
+ $this->language = $language;
}
/**
@@ -181,6 +181,6 @@ class extension extends \Twig_Extension
// LA_ is transformed into lang(\'$1\')|escape('js'), so we should not
// need to check for it
- return call_user_func_array(array($this->user, 'lang'), $args);
+ return call_user_func_array(array($this->language, 'lang'), $args);
}
}
diff --git a/phpBB/phpbb/template/twig/loader.php b/phpBB/phpbb/template/twig/loader.php
index df8183c019..8b12188a77 100644
--- a/phpBB/phpbb/template/twig/loader.php
+++ b/phpBB/phpbb/template/twig/loader.php
@@ -115,7 +115,8 @@ class loader extends \Twig_Loader_Filesystem
// If this is in the cache we can skip the entire process below
// as it should have already been validated
- if (isset($this->cache[$name])) {
+ if (isset($this->cache[$name]))
+ {
return $this->cache[$name];
}
diff --git a/phpBB/phpbb/template/twig/node/definenode.php b/phpBB/phpbb/template/twig/node/definenode.php
index 695ec4281f..c110785c4b 100644
--- a/phpBB/phpbb/template/twig/node/definenode.php
+++ b/phpBB/phpbb/template/twig/node/definenode.php
@@ -31,7 +31,8 @@ class definenode extends \Twig_Node
{
$compiler->addDebugInfo($this);
- if ($this->getAttribute('capture')) {
+ if ($this->getAttribute('capture'))
+ {
$compiler
->write("ob_start();\n")
->subcompile($this->getNode('value'))
diff --git a/phpBB/phpbb/template/twig/node/includeasset.php b/phpBB/phpbb/template/twig/node/includeasset.php
index 15195a226b..324823b8d7 100644
--- a/phpBB/phpbb/template/twig/node/includeasset.php
+++ b/phpBB/phpbb/template/twig/node/includeasset.php
@@ -39,7 +39,7 @@ abstract class includeasset extends \Twig_Node
->write("\$asset_file = ")
->subcompile($this->getNode('expr'))
->raw(";\n")
- ->write("\$asset = new \phpbb\\template\\asset(\$asset_file, \$this->getEnvironment()->get_path_helper());\n")
+ ->write("\$asset = new \phpbb\\template\\asset(\$asset_file, \$this->getEnvironment()->get_path_helper(), \$this->getEnvironment()->get_filesystem());\n")
->write("if (substr(\$asset_file, 0, 2) !== './' && \$asset->is_relative()) {\n")
->indent()
->write("\$asset_path = \$asset->get_path();")
diff --git a/phpBB/phpbb/template/twig/node/includephp.php b/phpBB/phpbb/template/twig/node/includephp.php
index 826617e8e8..659495fd9e 100644
--- a/phpBB/phpbb/template/twig/node/includephp.php
+++ b/phpBB/phpbb/template/twig/node/includephp.php
@@ -47,7 +47,8 @@ class includephp extends \Twig_Node
return;
}
- if ($this->getAttribute('ignore_missing')) {
+ if ($this->getAttribute('ignore_missing'))
+ {
$compiler
->write("try {\n")
->indent()
@@ -76,7 +77,8 @@ class includephp extends \Twig_Node
->write("}\n")
;
- if ($this->getAttribute('ignore_missing')) {
+ if ($this->getAttribute('ignore_missing'))
+ {
$compiler
->outdent()
->write("} catch (\Twig_Error_Loader \$e) {\n")
diff --git a/phpBB/phpbb/template/twig/tokenparser/defineparser.php b/phpBB/phpbb/template/twig/tokenparser/defineparser.php
index cfee84a363..2b88d61118 100644
--- a/phpBB/phpbb/template/twig/tokenparser/defineparser.php
+++ b/phpBB/phpbb/template/twig/tokenparser/defineparser.php
@@ -33,7 +33,8 @@ class defineparser extends \Twig_TokenParser
$name = $this->parser->getExpressionParser()->parseExpression();
$capture = false;
- if ($stream->test(\Twig_Token::OPERATOR_TYPE, '=')) {
+ if ($stream->test(\Twig_Token::OPERATOR_TYPE, '='))
+ {
$stream->next();
$value = $this->parser->getExpressionParser()->parseExpression();
@@ -45,7 +46,9 @@ class defineparser extends \Twig_TokenParser
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
- } else {
+ }
+ else
+ {
$capture = true;
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
diff --git a/phpBB/phpbb/template/twig/tokenparser/includephp.php b/phpBB/phpbb/template/twig/tokenparser/includephp.php
index 38196c5290..c09f7729b0 100644
--- a/phpBB/phpbb/template/twig/tokenparser/includephp.php
+++ b/phpBB/phpbb/template/twig/tokenparser/includephp.php
@@ -31,7 +31,8 @@ class includephp extends \Twig_TokenParser
$stream = $this->parser->getStream();
$ignoreMissing = false;
- if ($stream->test(\Twig_Token::NAME_TYPE, 'ignore')) {
+ if ($stream->test(\Twig_Token::NAME_TYPE, 'ignore'))
+ {
$stream->next();
$stream->expect(\Twig_Token::NAME_TYPE, 'missing');
diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php
index 0e4c619029..6b3cf32bc8 100644
--- a/phpBB/phpbb/template/twig/twig.php
+++ b/phpBB/phpbb/template/twig/twig.php
@@ -13,6 +13,8 @@
namespace phpbb\template\twig;
+use phpbb\template\exception\user_object_not_available;
+
/**
* Twig Template class.
*/
@@ -76,14 +78,14 @@ class twig extends \phpbb\template\base
*
* @param \phpbb\path_helper $path_helper
* @param \phpbb\config\config $config
- * @param \phpbb\user $user
* @param \phpbb\template\context $context template context
* @param \phpbb\template\twig\environment $twig_environment
* @param string $cache_path
+ * @param \phpbb\user|null $user
* @param array|\ArrayAccess $extensions
* @param \phpbb\extension\manager $extension_manager extension manager, if null then template events will not be invoked
*/
- public function __construct(\phpbb\path_helper $path_helper, $config, $user, \phpbb\template\context $context, \phpbb\template\twig\environment $twig_environment, $cache_path, $extensions = array(), \phpbb\extension\manager $extension_manager = null)
+ public function __construct(\phpbb\path_helper $path_helper, $config, \phpbb\template\context $context, \phpbb\template\twig\environment $twig_environment, $cache_path, \phpbb\user $user = null, $extensions = array(), \phpbb\extension\manager $extension_manager = null)
{
$this->path_helper = $path_helper;
$this->phpbb_root_path = $path_helper->get_phpbb_root_path();
@@ -126,9 +128,16 @@ class twig extends \phpbb\template\base
* Get the style tree of the style preferred by the current user
*
* @return array Style tree, most specific first
+ *
+ * @throws \phpbb\template\exception\user_object_not_available When user service was not set
*/
public function get_user_style()
{
+ if ($this->user === null)
+ {
+ throw new user_object_not_available();
+ }
+
$style_list = array(
$this->user->style['style_path'],
);
@@ -344,11 +353,15 @@ class twig extends \phpbb\template\base
$context_vars['.'][0], // To get normal vars
array(
'definition' => new \phpbb\template\twig\definition(),
- 'user' => $this->user,
'loops' => $context_vars, // To get loops
)
);
+ if ($this->user instanceof \phpbb\user)
+ {
+ $vars['user'] = $this->user;
+ }
+
// cleanup
unset($vars['loops']['.']);
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", '&nbsp; &nbsp;', $code);
- $code = str_replace(' ', '&nbsp; ', $code);
- $code = str_replace(' ', ' &nbsp;', $code);
- $code = str_replace("\n ", "\n&nbsp;", $code);
-
- // keep space at the beginning
- if (!empty($code) && $code[0] == ' ')
- {
- $code = '&nbsp;' . 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
diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php
index 882e9cef26..c33070d6f4 100644
--- a/phpBB/phpbb/user.php
+++ b/phpBB/phpbb/user.php
@@ -21,8 +21,11 @@ namespace phpbb;
*/
class user extends \phpbb\session
{
- var $lang = array();
- var $help = array();
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
var $style = array();
var $date_format;
@@ -42,35 +45,63 @@ class user extends \phpbb\session
var $img_lang;
var $img_array = array();
+ /** @var bool */
+ protected $is_setup_flag;
+
// Able to add new options (up to id 31)
var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'sig_bbcode' => 15, 'sig_smilies' => 16, 'sig_links' => 17);
/**
* Constructor to set the lang path
+ *
* @param string $datetime_class Class name of datetime class
+ * @param \phpbb\language\language $lang phpBB's Language loader
*/
- function __construct($datetime_class)
+ function __construct(\phpbb\language\language $lang, $datetime_class)
{
global $phpbb_root_path;
$this->lang_path = $phpbb_root_path . 'language/';
+ $this->language = $lang;
$this->datetime = $datetime_class;
+
+ $this->is_setup_flag = false;
}
/**
- * Function to set custom language path (able to use directory outside of phpBB)
- *
- * @param string $lang_path New language path used.
- * @access public
- */
- function set_custom_lang_path($lang_path)
+ * Returns whether user::setup was called
+ *
+ * @return bool
+ */
+ public function is_setup()
{
- $this->lang_path = $lang_path;
+ return $this->is_setup_flag;
+ }
- if (substr($this->lang_path, -1) != '/')
+ /**
+ * Magic getter for BC compatibility
+ *
+ * Implement array access for user::lang.
+ *
+ * @param string $param_name Name of the BC component the user want to access
+ *
+ * @return array The appropriate array
+ *
+ * @deprecated 3.2.0-dev (To be removed: 4.0.0)
+ */
+ public function __get($param_name)
+ {
+ if ($param_name === 'lang')
+ {
+ return $this->language->get_lang_array();
+ }
+ else if ($param_name === 'help')
{
- $this->lang_path .= '/';
+ $help_array = $this->language->get_lang_array();
+ return $help_array['__help'];
}
+
+ return array();
}
/**
@@ -81,6 +112,8 @@ class user extends \phpbb\session
global $db, $request, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
global $phpbb_dispatcher;
+ $this->language->set_default_language($config['default_lang']);
+
if ($this->data['user_id'] != ANONYMOUS)
{
$user_lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
@@ -98,6 +131,7 @@ class user extends \phpbb\session
{
$lang_override = $request->variable($config['cookie_name'] . '_lang', '', true, \phpbb\request\request_interface::COOKIE);
}
+
if ($lang_override)
{
$use_lang = basename($lang_override);
@@ -108,6 +142,7 @@ class user extends \phpbb\session
{
$user_lang_name = basename($config['default_lang']);
}
+
$user_date_format = $config['default_dateformat'];
$user_timezone = $config['board_timezone'];
@@ -187,6 +222,8 @@ class user extends \phpbb\session
$this->lang_name = $user_lang_name;
$this->date_format = $user_date_format;
+ $this->language->set_user_language($user_lang_name);
+
try
{
$this->timezone = new \DateTimeZone($user_timezone);
@@ -197,17 +234,6 @@ class user extends \phpbb\session
$this->timezone = new \DateTimeZone('UTC');
}
- // We include common language file here to not load it every time a custom language file is included
- $lang = &$this->lang;
-
- // Do not suppress error if in DEBUG mode
- $include_result = (defined('DEBUG')) ? (include $this->lang_path . $this->lang_name . "/common.$phpEx") : (@include $this->lang_path . $this->lang_name . "/common.$phpEx");
-
- if ($include_result === false)
- {
- die('Language file ' . $this->lang_path . $this->lang_name . "/common.$phpEx" . " couldn't be opened.");
- }
-
$this->add_lang($lang_set);
unset($lang_set);
@@ -393,6 +419,8 @@ class user extends \phpbb\session
}
}
+ $this->is_setup_flag = true;
+
return;
}
@@ -406,103 +434,13 @@ class user extends \phpbb\session
*
* If the first parameter is an array, the elements are used as keys and subkeys to get the language entry:
* Example: <samp>$user->lang(array('datetime', 'AGO'), 1)</samp> uses $user->lang['datetime']['AGO'] as language entry.
+ *
+ * @deprecated 3.2.0-dev (To be removed 4.0.0)
*/
function lang()
{
$args = func_get_args();
- $key = $args[0];
-
- if (is_array($key))
- {
- $lang = &$this->lang[array_shift($key)];
-
- foreach ($key as $_key)
- {
- $lang = &$lang[$_key];
- }
- }
- else
- {
- $lang = &$this->lang[$key];
- }
-
- // Return if language string does not exist
- if (!isset($lang) || (!is_string($lang) && !is_array($lang)))
- {
- return $key;
- }
-
- // If the language entry is a string, we simply mimic sprintf() behaviour
- if (is_string($lang))
- {
- if (sizeof($args) == 1)
- {
- return $lang;
- }
-
- // Replace key with language entry and simply pass along...
- $args[0] = $lang;
- return call_user_func_array('sprintf', $args);
- }
- else if (sizeof($lang) == 0)
- {
- // If the language entry is an empty array, we just return the language key
- return $args[0];
- }
-
- // It is an array... now handle different nullar/singular/plural forms
- $key_found = false;
-
- // We now get the first number passed and will select the key based upon this number
- for ($i = 1, $num_args = sizeof($args); $i < $num_args; $i++)
- {
- if (is_int($args[$i]) || is_float($args[$i]))
- {
- if ($args[$i] == 0 && isset($lang[0]))
- {
- // We allow each translation using plural forms to specify a version for the case of 0 things,
- // so that "0 users" may be displayed as "No users".
- $key_found = 0;
- break;
- }
- else
- {
- $use_plural_form = $this->get_plural_form($args[$i]);
- if (isset($lang[$use_plural_form]))
- {
- // The key we should use exists, so we use it.
- $key_found = $use_plural_form;
- }
- else
- {
- // If the key we need to use does not exist, we fall back to the previous one.
- $numbers = array_keys($lang);
-
- foreach ($numbers as $num)
- {
- if ($num > $use_plural_form)
- {
- break;
- }
-
- $key_found = $num;
- }
- }
- break;
- }
- }
- }
-
- // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form)
- if ($key_found === false)
- {
- $numbers = array_keys($lang);
- $key_found = end($numbers);
- }
-
- // Use the language string we determined and pass it to sprintf()
- $args[0] = $lang[$key_found];
- return call_user_func_array('sprintf', $args);
+ return call_user_func_array(array($this->language, 'lang'), $args);
}
/**
@@ -512,24 +450,22 @@ class user extends \phpbb\session
* @param $number int|float The number we want to get the plural case for. Float numbers are floored.
* @param $force_rule mixed False to use the plural rule of the language package
* or an integer to force a certain plural rule
- * @return int The plural-case we need to use for the number plural-rule combination
+ * @return int|bool The plural-case we need to use for the number plural-rule combination, false if $force_rule
+ * was invalid.
+ *
+ * @deprecated: 3.2.0-dev (To be removed: 3.3.0)
*/
function get_plural_form($number, $force_rule = false)
{
- $number = (int) $number;
-
- // Default to English system
- $plural_rule = ($force_rule !== false) ? $force_rule : ((isset($this->lang['PLURAL_RULE'])) ? $this->lang['PLURAL_RULE'] : 1);
-
- return phpbb_get_plural_form($plural_rule, $number);
+ return $this->language->get_plural_form($number, $force_rule);
}
/**
* Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
*
* @param mixed $lang_set specifies the language entries to include
- * @param bool $use_db internal variable for recursion, do not use
- * @param bool $use_help internal variable for recursion, do not use
+ * @param bool $use_db internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 3.3.0)
+ * @param bool $use_help internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 3.3.0)
* @param string $ext_name The extension to load language from, or empty for core files
*
* Examples:
@@ -540,11 +476,14 @@ class user extends \phpbb\session
* $lang_set = 'posting'
* $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
* </code>
+ *
+ * Note: $use_db and $use_help should be removed. The old function was kept for BC purposes,
+ * so the BC logic is handled here.
+ *
+ * @deprecated: 3.2.0-dev (To be removed: 3.3.0)
*/
function add_lang($lang_set, $use_db = false, $use_help = false, $ext_name = '')
{
- global $phpEx;
-
if (is_array($lang_set))
{
foreach ($lang_set as $key => $lang_file)
@@ -555,6 +494,7 @@ class user extends \phpbb\session
if ($key == 'db')
{
+ // This is never used
$this->add_lang($lang_file, true, $use_help, $ext_name);
}
else if ($key == 'help')
@@ -563,7 +503,7 @@ class user extends \phpbb\session
}
else if (!is_array($lang_file))
{
- $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help, $ext_name);
+ $this->set_lang($lang_file, $use_help, $ext_name);
}
else
{
@@ -574,8 +514,37 @@ class user extends \phpbb\session
}
else if ($lang_set)
{
- $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help, $ext_name);
+ $this->set_lang($lang_set, $use_help, $ext_name);
+ }
+ }
+
+ /**
+ * BC function for loading language files
+ *
+ * @deprecated 3.2.0-dev (To be removed: 3.3.0)
+ */
+ private function set_lang($lang_set, $use_help, $ext_name)
+ {
+ if (empty($ext_name))
+ {
+ $ext_name = null;
+ }
+
+ if ($use_help && strpos($lang_set, '/') !== false)
+ {
+ $component = dirname($lang_set) . '/help_' . basename($lang_set);
+
+ if ($component[0] === '/')
+ {
+ $component = substr($component, 1);
+ }
+ }
+ else
+ {
+ $component = (($use_help) ? 'help_' : '') . $lang_set;
}
+
+ $this->language->add_lang($component, $ext_name);
}
/**
@@ -585,6 +554,10 @@ class user extends \phpbb\session
* @param mixed $lang_set specifies the language entries to include
* @param bool $use_db internal variable for recursion, do not use
* @param bool $use_help internal variable for recursion, do not use
+ *
+ * Note: $use_db and $use_help should be removed. Kept for BC purposes.
+ *
+ * @deprecated: 3.2.0-dev (To be removed: 3.3.0)
*/
function add_lang_ext($ext_name, $lang_set, $use_db = false, $use_help = false)
{
@@ -597,109 +570,6 @@ class user extends \phpbb\session
}
/**
- * Set language entry (called by add_lang)
- * @access private
- */
- function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false, $ext_name = '')
- {
- global $phpbb_root_path, $phpEx;
-
- // Make sure the language name is set (if the user setup did not happen it is not set)
- if (!$this->lang_name)
- {
- global $config;
- $this->lang_name = basename($config['default_lang']);
- }
-
- // $lang == $this->lang
- // $help == $this->help
- // - add appropriate variables here, name them as they are used within the language file...
- if (!$use_db)
- {
- if ($use_help && strpos($lang_file, '/') !== false)
- {
- $filename = dirname($lang_file) . '/help_' . basename($lang_file);
- }
- else
- {
- $filename = (($use_help) ? 'help_' : '') . $lang_file;
- }
-
- if ($ext_name)
- {
- global $phpbb_extension_manager;
- $ext_path = $phpbb_extension_manager->get_extension_path($ext_name, true);
-
- $lang_path = $ext_path . 'language/';
- }
- else
- {
- $lang_path = $this->lang_path;
- }
-
- if (strpos($phpbb_root_path . $filename, $lang_path . $this->lang_name . '/') === 0)
- {
- $language_filename = $phpbb_root_path . $filename;
- }
- else
- {
- $language_filename = $lang_path . $this->lang_name . '/' . $filename . '.' . $phpEx;
- }
-
- // If we are in install, try to use the updated version, when available
- $install_language_filename = str_replace('language/', 'install/update/new/language/', $language_filename);
- if (defined('IN_INSTALL') && file_exists($install_language_filename))
- {
- $language_filename = $install_language_filename;
- }
-
- if (!file_exists($language_filename))
- {
- global $config;
-
- if ($this->lang_name == 'en')
- {
- // The user's selected language is missing the file, the board default's language is missing the file, and the file doesn't exist in /en.
- $language_filename = str_replace($lang_path . 'en', $lang_path . $this->data['user_lang'], $language_filename);
- trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR);
- }
- else if ($this->lang_name == basename($config['default_lang']))
- {
- // Fall back to the English Language
- $reset_lang_name = $this->lang_name;
- $this->lang_name = 'en';
- $this->set_lang($lang, $help, $lang_file, $use_db, $use_help, $ext_name);
- $this->lang_name = $reset_lang_name;
- }
- else if ($this->lang_name == $this->data['user_lang'])
- {
- // Fall back to the board default language
- $reset_lang_name = $this->lang_name;
- $this->lang_name = basename($config['default_lang']);
- $this->set_lang($lang, $help, $lang_file, $use_db, $use_help, $ext_name);
- $this->lang_name = $reset_lang_name;
- }
-
- return;
- }
-
- // Do not suppress error if in DEBUG mode
- $include_result = (defined('DEBUG')) ? (include $language_filename) : (@include $language_filename);
-
- if ($include_result === false)
- {
- trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR);
- }
- }
- else if ($use_db)
- {
- // Get Database Language Strings
- // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed
- // For example: help:faq, posting
- }
- }
-
- /**
* Format user date
*
* @param int $gmepoch unix timestamp
@@ -808,7 +678,7 @@ class user extends \phpbb\session
if ($alt)
{
- $alt = $this->lang($alt);
+ $alt = $this->language->lang($alt);
$title = ' title="' . $alt . '"';
}
return '<span class="imageset ' . $img . '"' . $title . '>' . $alt . '</span>';