aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/phpbb
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/phpbb')
-rw-r--r--phpBB/phpbb/auth/provider/apache.php4
-rw-r--r--phpBB/phpbb/auth/provider/db.php8
-rw-r--r--phpBB/phpbb/avatar/manager.php40
-rw-r--r--phpBB/phpbb/captcha/plugins/recaptcha.php6
-rw-r--r--phpBB/phpbb/config/db.php4
-rw-r--r--phpBB/phpbb/content_visibility.php69
-rw-r--r--phpBB/phpbb/controller/helper.php11
-rw-r--r--phpBB/phpbb/db/migration/data/v310/captcha_plugins.php8
-rw-r--r--phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php41
-rw-r--r--phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php41
-rw-r--r--phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php3
-rw-r--r--phpBB/phpbb/db/migration/data/v310/style_update_p1.php2
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/plupload_last_gc_dynamic.php31
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/profilefield_remove_underscore_from_alpha.php47
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/profilefield_yahoo_update_url.php38
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php70
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/v312.php31
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/v312rc1.php32
-rw-r--r--phpBB/phpbb/db/migration/tool/module.php1
-rw-r--r--phpBB/phpbb/db/tools.php2
-rw-r--r--phpBB/phpbb/di/extension/config.php28
-rw-r--r--phpBB/phpbb/error_collector.php17
-rw-r--r--phpBB/phpbb/extension/metadata_manager.php34
-rw-r--r--phpBB/phpbb/file_downloader.php120
-rw-r--r--phpBB/phpbb/log/log.php44
-rw-r--r--phpBB/phpbb/message/topic_form.php2
-rw-r--r--phpBB/phpbb/notification/manager.php29
-rw-r--r--phpBB/phpbb/path_helper.php48
-rw-r--r--phpBB/phpbb/profilefields/type/type_base.php14
-rw-r--r--phpBB/phpbb/profilefields/type/type_bool.php2
-rw-r--r--phpBB/phpbb/profilefields/type/type_string_common.php10
-rw-r--r--phpBB/phpbb/profilefields/type/type_url.php2
-rw-r--r--phpBB/phpbb/request/request.php25
-rw-r--r--phpBB/phpbb/request/request_interface.php10
-rw-r--r--phpBB/phpbb/search/fulltext_native.php2
-rw-r--r--phpBB/phpbb/session.php31
-rw-r--r--phpBB/phpbb/symfony_request.php24
-rw-r--r--phpBB/phpbb/template/twig/twig.php37
-rw-r--r--phpBB/phpbb/version_helper.php40
39 files changed, 885 insertions, 123 deletions
diff --git a/phpBB/phpbb/auth/provider/apache.php b/phpBB/phpbb/auth/provider/apache.php
index 9137a77210..aa5bf64335 100644
--- a/phpBB/phpbb/auth/provider/apache.php
+++ b/phpBB/phpbb/auth/provider/apache.php
@@ -137,7 +137,7 @@ class apache extends \phpbb\auth\provider\base
return array(
'status' => LOGIN_SUCCESS_CREATE_PROFILE,
'error_msg' => false,
- 'user_row' => user_row_apache($php_auth_user, $php_auth_pw),
+ 'user_row' => $this->user_row($php_auth_user, $php_auth_pw),
);
}
@@ -185,7 +185,7 @@ class apache extends \phpbb\auth\provider\base
}
// create the user if he does not exist yet
- user_add(user_row_apache($php_auth_user, $php_auth_pw));
+ user_add($this->user_row($php_auth_user, $php_auth_pw));
$sql = 'SELECT *
FROM ' . USERS_TABLE . "
diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php
index 722eeffa9a..d8c5fb72de 100644
--- a/phpBB/phpbb/auth/provider/db.php
+++ b/phpBB/phpbb/auth/provider/db.php
@@ -87,7 +87,7 @@ class db extends \phpbb\auth\provider\base
$username_clean = utf8_clean_string($username);
- $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts
+ $sql = 'SELECT *
FROM ' . USERS_TABLE . "
WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'";
$result = $this->db->sql_query($sql);
@@ -123,7 +123,7 @@ class db extends \phpbb\auth\provider\base
'username_clean' => $username_clean,
);
$sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data);
- $result = $this->db->sql_query($sql);
+ $this->db->sql_query($sql);
}
else
{
@@ -175,7 +175,7 @@ class db extends \phpbb\auth\provider\base
}
// Check password ...
- if ($this->passwords_manager->check($password, $row['user_password']))
+ if ($this->passwords_manager->check($password, $row['user_password'], $row))
{
// Check for old password hash...
if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32)
@@ -232,7 +232,7 @@ class db extends \phpbb\auth\provider\base
// Give status about wrong password...
return array(
'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD,
- 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD',
+ 'error_msg' => 'LOGIN_ERROR_PASSWORD',
'user_row' => $row,
);
}
diff --git a/phpBB/phpbb/avatar/manager.php b/phpBB/phpbb/avatar/manager.php
index 42ae61a9a2..8d83152ed6 100644
--- a/phpBB/phpbb/avatar/manager.php
+++ b/phpBB/phpbb/avatar/manager.php
@@ -326,17 +326,41 @@ class manager
$driver->delete($avatar_data);
}
- $result = self::$default_row;
+ $result = $this->prefix_avatar_columns($prefix, self::$default_row);
- foreach ($result as $key => $value)
+ $sql = 'UPDATE ' . $table . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id'];
+ $db->sql_query($sql);
+
+ // Make sure we also delete this avatar from the users
+ if ($prefix === 'group_')
{
- $result[$prefix . $key] = $value;
- unset($result[$key]);
+ $result = $this->prefix_avatar_columns('user_', self::$default_row);
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . "
+ WHERE user_avatar = '" . $db->sql_escape($avatar_data['avatar']) . "'";
+ $db->sql_query($sql);
}
+ }
- $sql = 'UPDATE ' . $table . '
- SET ' . $db->sql_build_array('UPDATE', $result) . '
- WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id'];
- $db->sql_query($sql);
+ /**
+ * Prefix avatar columns
+ *
+ * @param string $prefix Column prefix
+ * @param array $data Column data
+ *
+ * @return array Column data with prefixed column names
+ */
+ public function prefix_avatar_columns($prefix, $data)
+ {
+ foreach ($data as $key => $value)
+ {
+ $data[$prefix . $key] = $value;
+ unset($data[$key]);
+ }
+
+ return $data;
}
}
diff --git a/phpBB/phpbb/captcha/plugins/recaptcha.php b/phpBB/phpbb/captcha/plugins/recaptcha.php
index ea446d7bc3..584f3afec1 100644
--- a/phpBB/phpbb/captcha/plugins/recaptcha.php
+++ b/phpBB/phpbb/captcha/plugins/recaptcha.php
@@ -26,8 +26,10 @@ class recaptcha extends captcha_abstract
var $challenge;
var $response;
- // PHP4 Constructor
- function phpbb_recaptcha()
+ /**
+ * Constructor
+ */
+ public function __construct()
{
global $request;
$this->recaptcha_server = $request->is_secure() ? $this->recaptcha_server_secure : $this->recaptcha_server;
diff --git a/phpBB/phpbb/config/db.php b/phpBB/phpbb/config/db.php
index ef20ebf62a..26489bdd34 100644
--- a/phpBB/phpbb/config/db.php
+++ b/phpBB/phpbb/config/db.php
@@ -145,9 +145,9 @@ class db extends \phpbb\config\config
$sql .= " AND config_value = '" . $this->db->sql_escape($old_value) . "'";
}
- $result = $this->db->sql_query($sql);
+ $this->db->sql_query($sql);
- if (!$this->db->sql_affectedrows($result) && isset($this->config[$key]))
+ if (!$this->db->sql_affectedrows() && isset($this->config[$key]))
{
return false;
}
diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php
index 8bd537586e..c8516d6c85 100644
--- a/phpBB/phpbb/content_visibility.php
+++ b/phpBB/phpbb/content_visibility.php
@@ -44,6 +44,12 @@ class content_visibility
protected $config;
/**
+ * Event dispatcher object
+ * @var \phpbb\event\dispatcher
+ */
+ protected $phpbb_dispatcher;
+
+ /**
* phpBB root path
* @var string
*/
@@ -60,6 +66,7 @@ class content_visibility
*
* @param \phpbb\auth\auth $auth Auth object
* @param \phpbb\config\config $config Config object
+ * @param \phpbb\event\dispatcher $phpbb_dispatcher Event dispatcher object
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbb\user $user User object
* @param string $phpbb_root_path Root path
@@ -69,10 +76,11 @@ class content_visibility
* @param string $topics_table Topics table name
* @param string $users_table Users table name
*/
- public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table)
+ public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table)
{
$this->auth = $auth;
$this->config = $config;
+ $this->phpbb_dispatcher = $phpbb_dispatcher;
$this->db = $db;
$this->user = $user;
$this->phpbb_root_path = $phpbb_root_path;
@@ -160,6 +168,36 @@ class content_visibility
$approve_forums = array_intersect($forum_ids, array_keys($this->auth->acl_getf('m_approve', true)));
+ $get_forums_visibility_sql_overwrite = false;
+ /**
+ * Allow changing the result of calling get_forums_visibility_sql
+ *
+ * @event core.phpbb_content_visibility_get_forums_visibility_before
+ * @var string where_sql The action the user tried to execute
+ * @var string mode Either "topic" or "post" depending on the query this is being used in
+ * @var array forum_ids Array of forum ids which the posts/topics are limited to
+ * @var string table_alias Table alias to prefix in SQL queries
+ * @var array approve_forums Array of forums where the user has m_approve permissions
+ * @var mixed get_forums_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event
+ * If false, get_forums_visibility_sql continues normally
+ * It must be either boolean or string
+ * @since 3.1.3-RC1
+ */
+ $vars = array(
+ 'where_sql',
+ 'mode',
+ 'forum_ids',
+ 'table_alias',
+ 'approve_forums',
+ 'get_forums_visibility_sql_overwrite',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_forums_visibility_before', compact($vars)));
+
+ if ($get_forums_visibility_sql_overwrite !== false)
+ {
+ return $get_forums_visibility_sql_overwrite;
+ }
+
if (sizeof($approve_forums))
{
// Remove moderator forums from the rest
@@ -206,6 +244,35 @@ class content_visibility
$approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids);
+ $visibility_sql_overwrite = null;
+
+ /**
+ * Allow changing the result of calling get_global_visibility_sql
+ *
+ * @event core.phpbb_content_visibility_get_global_visibility_before
+ * @var array where_sqls The action the user tried to execute
+ * @var string mode Either "topic" or "post" depending on the query this is being used in
+ * @var array forum_ids Array of forum ids which the posts/topics are limited to
+ * @var string table_alias Table alias to prefix in SQL queries
+ * @var array approve_forums Array of forums where the user has m_approve permissions
+ * @var string visibility_sql_overwrite Forces the function to return an implosion of where_sqls (joined by "OR")
+ * @since 3.1.3-RC1
+ */
+ $vars = array(
+ 'where_sqls',
+ 'mode',
+ 'forum_ids',
+ 'table_alias',
+ 'approve_forums',
+ 'visibility_sql_overwrite',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_global_visibility_before', compact($vars)));
+
+ if ($visibility_sql_overwrite)
+ {
+ return $visibility_sql_overwrite;
+ }
+
if (sizeof($exclude_forum_ids))
{
$where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true) . '
diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php
index 187e455d48..52e6947c2c 100644
--- a/phpBB/phpbb/controller/helper.php
+++ b/phpBB/phpbb/controller/helper.php
@@ -44,6 +44,9 @@ class helper
/* @var \phpbb\symfony_request */
protected $symfony_request;
+ /* @var \phpbb\request\request_interface */
+ protected $request;
+
/**
* @var \phpbb\filesystem The filesystem object
*/
@@ -70,16 +73,18 @@ class helper
* @param \phpbb\controller\provider $provider Path provider
* @param \phpbb\extension\manager $manager Extension manager object
* @param \phpbb\symfony_request $symfony_request Symfony Request object
+ * @param \phpbb\request\request_interface $request phpBB request object
* @param \phpbb\filesystem $filesystem The filesystem object
* @param string $phpbb_root_path phpBB root path
* @param string $php_ext PHP file extension
*/
- public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext)
+ public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext)
{
$this->template = $template;
$this->user = $user;
$this->config = $config;
$this->symfony_request = $symfony_request;
+ $this->request = $request;
$this->filesystem = $filesystem;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
@@ -153,7 +158,7 @@ class helper
}
}
- $base_url = $this->filesystem->clean_path($base_url);
+ $base_url = $this->request->escape($this->filesystem->clean_path($base_url), true);
$context->setBaseUrl($base_url);
@@ -197,6 +202,6 @@ class helper
*/
public function get_current_url()
{
- return generate_board_url(true) . $this->symfony_request->getRequestUri();
+ return generate_board_url(true) . $this->request->escape($this->symfony_request->getRequestUri(), true);
}
}
diff --git a/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php
index 13071e9891..328c08f1ec 100644
--- a/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php
+++ b/phpBB/phpbb/db/migration/data/v310/captcha_plugins.php
@@ -25,9 +25,13 @@ class captcha_plugins extends \phpbb\db\migration\migration
public function update_data()
{
$captcha_plugin = $this->config['captcha_plugin'];
- if (strpos($this->config['captcha_plugin'], 'phpbb_captcha_') === 0)
+ if (strpos($captcha_plugin, 'phpbb_captcha_') === 0)
{
- $captcha_plugin = substr($this->config['captcha_plugin'], strlen('phpbb_captcha_'));
+ $captcha_plugin = substr($captcha_plugin, strlen('phpbb_captcha_'));
+ }
+ else if (strpos($captcha_plugin, 'phpbb_') === 0)
+ {
+ $captcha_plugin = substr($captcha_plugin, strlen('phpbb_'));
}
return array(
diff --git a/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php b/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php
index 4530ebe285..e04a705c91 100644
--- a/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php
+++ b/phpBB/phpbb/db/migration/data/v310/mysql_fulltext_drop.php
@@ -15,10 +15,18 @@ namespace phpbb\db\migration\data\v310;
class mysql_fulltext_drop extends \phpbb\db\migration\migration
{
+ protected $indexes;
+
public function effectively_installed()
{
// This migration is irrelevant for all non-MySQL DBMSes.
- return strpos($this->db->get_sql_layer(), 'mysql') === false;
+ if (strpos($this->db->get_sql_layer(), 'mysql') === false)
+ {
+ return true;
+ }
+
+ $this->find_indexes_to_drop();
+ return empty($this->indexes);
}
static public function depends_on()
@@ -30,6 +38,11 @@ class mysql_fulltext_drop extends \phpbb\db\migration\migration
public function update_schema()
{
+ if (empty($this->indexes))
+ {
+ return array();
+ }
+
/*
* Drop FULLTEXT indexes related to MySQL fulltext search.
* Doing so is equivalent to dropping the search index from the ACP.
@@ -40,12 +53,28 @@ class mysql_fulltext_drop extends \phpbb\db\migration\migration
*/
return array(
'drop_keys' => array(
- $this->table_prefix . 'posts' => array(
- 'post_subject',
- 'post_text',
- 'post_content',
- ),
+ $this->table_prefix . 'posts' => $this->indexes,
),
);
}
+
+ public function find_indexes_to_drop()
+ {
+ if ($this->indexes !== null)
+ {
+ return $this->indexes;
+ }
+
+ $this->indexes = array();
+ $potential_keys = array('post_subject', 'post_text', 'post_content');
+ foreach ($potential_keys as $key)
+ {
+ if ($this->db_tools->sql_index_exists($this->table_prefix . 'posts', $key))
+ {
+ $this->indexes[] = $key;
+ }
+ }
+
+ return $this->indexes;
+ }
}
diff --git a/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php b/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php
index ea442dfb1b..3457c19478 100644
--- a/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php
+++ b/phpBB/phpbb/db/migration/data/v310/postgres_fulltext_drop.php
@@ -15,10 +15,18 @@ namespace phpbb\db\migration\data\v310;
class postgres_fulltext_drop extends \phpbb\db\migration\migration
{
+ protected $indexes;
+
public function effectively_installed()
{
// This migration is irrelevant for all non-PostgreSQL DBMSes.
- return strpos($this->db->get_sql_layer(), 'postgres') === false;
+ if (strpos($this->db->get_sql_layer(), 'postgres') === false)
+ {
+ return true;
+ }
+
+ $this->find_indexes_to_drop();
+ return empty($this->indexes);
}
static public function depends_on()
@@ -30,6 +38,11 @@ class postgres_fulltext_drop extends \phpbb\db\migration\migration
public function update_schema()
{
+ if (empty($this->indexes))
+ {
+ return array();
+ }
+
/*
* Drop FULLTEXT indexes related to PostgreSQL fulltext search.
* Doing so is equivalent to dropping the search index from the ACP.
@@ -40,12 +53,28 @@ class postgres_fulltext_drop extends \phpbb\db\migration\migration
*/
return array(
'drop_keys' => array(
- $this->table_prefix . 'posts' => array(
- 'post_subject',
- 'post_text',
- 'post_content',
- ),
+ $this->table_prefix . 'posts' => $this->indexes,
),
);
}
+
+ public function find_indexes_to_drop()
+ {
+ if ($this->indexes !== null)
+ {
+ return $this->indexes;
+ }
+
+ $this->indexes = array();
+ $potential_keys = array('post_subject', 'post_text', 'post_content');
+ foreach ($potential_keys as $key)
+ {
+ if ($this->db_tools->sql_index_exists($this->table_prefix . 'posts', $key))
+ {
+ $this->indexes[] = $key;
+ }
+ }
+
+ return $this->indexes;
+ }
}
diff --git a/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php b/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php
index d5f9076196..8211457dc6 100644
--- a/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php
+++ b/phpBB/phpbb/db/migration/data/v310/reset_missing_captcha_plugin.php
@@ -29,7 +29,8 @@ class reset_missing_captcha_plugin extends \phpbb\db\migration\migration
{
return array(
array('if', array(
- (!is_file($this->phpbb_root_path . "includes/captcha/plugins/{$this->config['captcha_plugin']}_plugin." . $this->php_ext)),
+ (is_dir($this->phpbb_root_path . 'includes/captcha/plugins/') &&
+ !is_file($this->phpbb_root_path . "includes/captcha/plugins/{$this->config['captcha_plugin']}_plugin." . $this->php_ext)),
array('config.update', array('captcha_plugin', 'phpbb_captcha_nogd')),
)),
);
diff --git a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php
index 5a3a1d5de7..e8d3a3af64 100644
--- a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php
+++ b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php
@@ -92,7 +92,7 @@ class style_update_p1 extends \phpbb\db\migration\migration
else
{
$sql = 'SELECT s.style_id, t.template_path, t.template_id, t.bbcode_bitfield, t.template_inherits_id, t.template_inherit_path, c.theme_path, c.theme_id
- FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . "stles_theme c
+ FROM ' . STYLES_TABLE . ' s, ' . $this->table_prefix . 'styles_template t, ' . $this->table_prefix . "styles_theme c
WHERE t.template_id = s.template_id
AND c.theme_id = s.theme_id";
}
diff --git a/phpBB/phpbb/db/migration/data/v31x/plupload_last_gc_dynamic.php b/phpBB/phpbb/db/migration/data/v31x/plupload_last_gc_dynamic.php
new file mode 100644
index 0000000000..0783d707c5
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/plupload_last_gc_dynamic.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class plupload_last_gc_dynamic extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v31x\v312');
+ }
+
+ public function update_data()
+ {
+ return array(
+ // Make plupload_last_gc dynamic.
+ array('config.remove', array('plupload_last_gc')),
+ array('config.add', array('plupload_last_gc', 0, 1)),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v31x/profilefield_remove_underscore_from_alpha.php b/phpBB/phpbb/db/migration/data/v31x/profilefield_remove_underscore_from_alpha.php
new file mode 100644
index 0000000000..60491f8de8
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/profilefield_remove_underscore_from_alpha.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v31x;
+
+class profilefield_remove_underscore_from_alpha extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v31x\v311');
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'remove_underscore_from_alpha_validations'))),
+ );
+ }
+
+ public function remove_underscore_from_alpha_validations()
+ {
+ $this->update_validation_rule('[\w]+', '[a-zA-Z0-9]+');
+ $this->update_validation_rule('[\w_]+', '[\w]+');
+ $this->update_validation_rule('[\w.]+', '[a-zA-Z0-9.]+');
+ $this->update_validation_rule('[\w\x20_+\-\[\]]+', '[\w\x20+\-\[\]]+');
+ $this->update_validation_rule('[a-zA-Z][\w\.,\-_]+', '[a-zA-Z][\w\.,\-]+');
+ }
+
+ public function update_validation_rule($old_validation, $new_validation)
+ {
+ $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . "
+ SET field_validation = '" . $this->db->sql_escape($new_validation) . "'
+ WHERE field_validation = '" . $this->db->sql_escape($old_validation) . "'";
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v31x/profilefield_yahoo_update_url.php b/phpBB/phpbb/db/migration/data/v31x/profilefield_yahoo_update_url.php
new file mode 100644
index 0000000000..4df9083bdf
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/profilefield_yahoo_update_url.php
@@ -0,0 +1,38 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class profilefield_yahoo_update_url extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v31x\v312');
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'update_contact_url'))),
+ );
+ }
+
+ public function update_contact_url()
+ {
+ $sql = 'UPDATE ' . $this->table_prefix . "profile_fields
+ SET field_contact_url = 'ymsgr:sendim?%s'
+ WHERE field_name = 'phpbb_yahoo'
+ AND field_contact_url = 'http://edit.yahoo.com/config/send_webmesg?.target=%s&amp;.src=pg'";
+ $this->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php
new file mode 100644
index 0000000000..854ed1f568
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php
@@ -0,0 +1,70 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class update_custom_bbcodes_with_idn extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v312',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'update_bbcodes_table'))),
+ );
+ }
+
+ public function update_bbcodes_table()
+ {
+ if (!class_exists('acp_bbcodes'))
+ {
+ include($this->phpbb_root_path . 'includes/acp/acp_bbcodes.' . $this->php_ext);
+ }
+
+ $bbcodes = new \acp_bbcodes();
+
+ $sql = 'SELECT bbcode_id, bbcode_match, bbcode_tpl
+ FROM ' . BBCODES_TABLE;
+ $result = $this->sql_query($sql);
+
+ $sql_ary = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $data = array();
+ if (preg_match('/(URL|LOCAL_URL|RELATIVE_URL)/', $row['bbcode_match']))
+ {
+ $data = $bbcodes->build_regexp($row['bbcode_match'], $row['bbcode_tpl']);
+ $sql_ary[$row['bbcode_id']] = array(
+ 'first_pass_match' => $data['first_pass_match'],
+ 'first_pass_replace' => $data['first_pass_replace'],
+ 'second_pass_match' => $data['second_pass_match'],
+ 'second_pass_replace' => $data['second_pass_replace']
+ );
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ foreach ($sql_ary as $bbcode_id => $bbcode_data)
+ {
+ $sql = 'UPDATE ' . BBCODES_TABLE . '
+ SET ' . $this->db->sql_build_array('UPDATE', $bbcode_data) . '
+ WHERE bbcode_id = ' . (int) $bbcode_id;
+ $this->sql_query($sql);
+ }
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v31x/v312.php b/phpBB/phpbb/db/migration/data/v31x/v312.php
new file mode 100644
index 0000000000..bf49935f4d
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/v312.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class v312 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v312rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.1.2')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v31x/v312rc1.php b/phpBB/phpbb/db/migration/data/v31x/v312rc1.php
new file mode 100644
index 0000000000..d4b133fc01
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/v312rc1.php
@@ -0,0 +1,32 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class v312rc1 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v311',
+ '\phpbb\db\migration\data\v31x\m_softdelete_global',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.1.2-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/tool/module.php b/phpBB/phpbb/db/migration/tool/module.php
index db43046a95..035625b095 100644
--- a/phpBB/phpbb/db/migration/tool/module.php
+++ b/phpBB/phpbb/db/migration/tool/module.php
@@ -475,6 +475,7 @@ class module implements \phpbb\db\migration\tool\tool_interface
if (!class_exists('acp_modules'))
{
include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
+ $this->user->add_lang('acp/modules');
}
$acp_modules = new \acp_modules();
$module = $acp_modules->get_module_infos($basename, $class, true);
diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php
index c8d25f23a2..f523b39fb3 100644
--- a/phpBB/phpbb/db/tools.php
+++ b/phpBB/phpbb/db/tools.php
@@ -2175,7 +2175,7 @@ class tools
}
// no break
case 'mysql_41':
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . '(' . implode(', ', $column) . ')';
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . ' (' . implode(', ', $column) . ')';
break;
case 'mssql':
diff --git a/phpBB/phpbb/di/extension/config.php b/phpBB/phpbb/di/extension/config.php
index 27ebc94bae..7984a783df 100644
--- a/phpBB/phpbb/di/extension/config.php
+++ b/phpBB/phpbb/di/extension/config.php
@@ -39,16 +39,24 @@ class config extends Extension
*/
public function load(array $config, ContainerBuilder $container)
{
- $container->setParameter('core.adm_relative_path', ($this->config_php->get('phpbb_adm_relative_path') ? $this->config_php->get('phpbb_adm_relative_path') : 'adm/'));
- $container->setParameter('core.table_prefix', $this->config_php->get('table_prefix'));
- $container->setParameter('cache.driver.class', $this->convert_30_acm_type($this->config_php->get('acm_type')));
- $container->setParameter('dbal.driver.class', $this->config_php->convert_30_dbms_to_31($this->config_php->get('dbms')));
- $container->setParameter('dbal.dbhost', $this->config_php->get('dbhost'));
- $container->setParameter('dbal.dbuser', $this->config_php->get('dbuser'));
- $container->setParameter('dbal.dbpasswd', $this->config_php->get('dbpasswd'));
- $container->setParameter('dbal.dbname', $this->config_php->get('dbname'));
- $container->setParameter('dbal.dbport', $this->config_php->get('dbport'));
- $container->setParameter('dbal.new_link', defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK);
+ $parameters = array(
+ 'core.adm_relative_path' => $this->config_php->get('phpbb_adm_relative_path') ? $this->config_php->get('phpbb_adm_relative_path') : 'adm/',
+ 'core.table_prefix' => $this->config_php->get('table_prefix'),
+ 'cache.driver.class' => $this->convert_30_acm_type($this->config_php->get('acm_type')),
+ 'dbal.driver.class' => $this->config_php->convert_30_dbms_to_31($this->config_php->get('dbms')),
+ 'dbal.dbhost' => $this->config_php->get('dbhost'),
+ 'dbal.dbuser' => $this->config_php->get('dbuser'),
+ 'dbal.dbpasswd' => $this->config_php->get('dbpasswd'),
+ 'dbal.dbname' => $this->config_php->get('dbname'),
+ 'dbal.dbport' => $this->config_php->get('dbport'),
+ 'dbal.new_link' => defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK,
+ );
+ $parameter_bag = $container->getParameterBag();
+
+ foreach ($parameters as $parameter => $value)
+ {
+ $container->setParameter($parameter, $parameter_bag->escapeValue($value));
+ }
}
/**
diff --git a/phpBB/phpbb/error_collector.php b/phpBB/phpbb/error_collector.php
index 7141f83174..bf8efd1065 100644
--- a/phpBB/phpbb/error_collector.php
+++ b/phpBB/phpbb/error_collector.php
@@ -16,15 +16,28 @@ namespace phpbb;
class error_collector
{
var $errors;
+ var $error_types;
- function __construct()
+ /**
+ * Constructor.
+ *
+ * The variable $error_types may be set to a mask of PHP error types that
+ * the collector should keep, e.g. `E_ALL`. If unset, the current value of
+ * the error_reporting() function will be used to determine which errors
+ * the collector will keep.
+ *
+ * @see PHPBB3-13306
+ * @param int|null $error_types
+ */
+ function __construct($error_types = null)
{
$this->errors = array();
+ $this->error_types = $error_types;
}
function install()
{
- set_error_handler(array(&$this, 'error_handler'));
+ set_error_handler(array(&$this, 'error_handler'), ($this->error_types !== null) ? $this->error_types : error_reporting());
}
function uninstall()
diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php
index edca8ee1af..a64d88fe39 100644
--- a/phpBB/phpbb/extension/metadata_manager.php
+++ b/phpBB/phpbb/extension/metadata_manager.php
@@ -177,6 +177,7 @@ class metadata_manager
throw new \phpbb\extension\exception($this->user->lang('FILE_JSON_DECODE_ERR', $this->metadata_file));
}
+ array_walk_recursive($metadata, array($this, 'sanitize_json'));
$this->metadata = $metadata;
return true;
@@ -184,6 +185,17 @@ class metadata_manager
}
/**
+ * Sanitize input from JSON array using htmlspecialchars()
+ *
+ * @param mixed $value Value of array row
+ * @param string $key Key of array row
+ */
+ public function sanitize_json(&$value, $key)
+ {
+ $value = htmlspecialchars($value);
+ }
+
+ /**
* This array handles the cleaning of the array
*
* @return array Contains the cleaned metadata array
@@ -337,30 +349,30 @@ class metadata_manager
public function output_template_data()
{
$this->template->assign_vars(array(
- 'META_NAME' => htmlspecialchars($this->metadata['name']),
- 'META_TYPE' => htmlspecialchars($this->metadata['type']),
- 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? htmlspecialchars($this->metadata['description']) : '',
+ 'META_NAME' => $this->metadata['name'],
+ 'META_TYPE' => $this->metadata['type'],
+ 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? $this->metadata['description'] : '',
'META_HOMEPAGE' => (isset($this->metadata['homepage'])) ? $this->metadata['homepage'] : '',
- 'META_VERSION' => (isset($this->metadata['version'])) ? htmlspecialchars($this->metadata['version']) : '',
- 'META_TIME' => (isset($this->metadata['time'])) ? htmlspecialchars($this->metadata['time']) : '',
- 'META_LICENSE' => htmlspecialchars($this->metadata['license']),
+ 'META_VERSION' => (isset($this->metadata['version'])) ? $this->metadata['version'] : '',
+ 'META_TIME' => (isset($this->metadata['time'])) ? $this->metadata['time'] : '',
+ 'META_LICENSE' => $this->metadata['license'],
- 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? htmlspecialchars($this->metadata['require']['php']) : '',
+ 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? $this->metadata['require']['php'] : '',
'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(),
- 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? htmlspecialchars($this->metadata['extra']['soft-require']['phpbb/phpbb']) : '',
+ 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? $this->metadata['extra']['soft-require']['phpbb/phpbb'] : '',
'META_REQUIRE_PHPBB_FAIL' => !$this->validate_require_phpbb(),
- 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? htmlspecialchars($this->metadata['extra']['display-name']) : '',
+ 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '',
));
foreach ($this->metadata['authors'] as $author)
{
$this->template->assign_block_vars('meta_authors', array(
- 'AUTHOR_NAME' => htmlspecialchars($author['name']),
+ 'AUTHOR_NAME' => $author['name'],
'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '',
'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '',
- 'AUTHOR_ROLE' => (isset($author['role'])) ? htmlspecialchars($author['role']) : '',
+ 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '',
));
}
}
diff --git a/phpBB/phpbb/file_downloader.php b/phpBB/phpbb/file_downloader.php
new file mode 100644
index 0000000000..d717b394d5
--- /dev/null
+++ b/phpBB/phpbb/file_downloader.php
@@ -0,0 +1,120 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb;
+
+class file_downloader
+{
+ /** @var string Error string */
+ protected $error_string = '';
+
+ /** @var int Error number */
+ protected $error_number = 0;
+
+ /**
+ * Retrieve contents from remotely stored file
+ *
+ * @param string $host File host
+ * @param string $directory Directory file is in
+ * @param string $filename Filename of file to retrieve
+ * @param int $port Port to connect to; default: 80
+ * @param int $timeout Connection timeout in seconds; default: 6
+ *
+ * @return mixed File data as string if file can be read and there is no
+ * timeout, false if there were errors or the connection timed out
+ *
+ * @throws \RuntimeException If data can't be retrieved and no error
+ * message is returned
+ */
+ public function get($host, $directory, $filename, $port = 80, $timeout = 6)
+ {
+ // Set default values for error variables
+ $this->error_number = 0;
+ $this->error_string = '';
+
+ if ($socket = @fsockopen($host, $port, $this->error_number, $this->error_string, $timeout))
+ {
+ @fputs($socket, "GET $directory/$filename HTTP/1.0\r\n");
+ @fputs($socket, "HOST: $host\r\n");
+ @fputs($socket, "Connection: close\r\n\r\n");
+
+ $timer_stop = time() + $timeout;
+ stream_set_timeout($socket, $timeout);
+
+ $file_info = '';
+ $get_info = false;
+
+ while (!@feof($socket))
+ {
+ if ($get_info)
+ {
+ $file_info .= @fread($socket, 1024);
+ }
+ else
+ {
+ $line = @fgets($socket, 1024);
+ if ($line == "\r\n")
+ {
+ $get_info = true;
+ }
+ else if (stripos($line, '404 not found') !== false)
+ {
+ throw new \RuntimeException(array('FILE_NOT_FOUND', $filename));
+ }
+ }
+
+ $stream_meta_data = stream_get_meta_data($socket);
+
+ if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop)
+ {
+ throw new \RuntimeException('FSOCK_TIMEOUT');
+ }
+ }
+ @fclose($socket);
+ }
+ else
+ {
+ if ($this->error_string)
+ {
+ $this->error_string = utf8_convert_message($this->error_string);
+ return false;
+ }
+ else
+ {
+ throw new \RuntimeException('FSOCK_DISABLED');
+ }
+ }
+
+ return $file_info;
+ }
+
+ /**
+ * Get error string
+ *
+ * @return string Error string
+ */
+ public function get_error_string()
+ {
+ return $this->error_string;
+ }
+
+ /**
+ * Get error number
+ *
+ * @return int Error number
+ */
+ public function get_error_number()
+ {
+ return $this->error_number;
+ }
+}
diff --git a/phpBB/phpbb/log/log.php b/phpBB/phpbb/log/log.php
index 2af8b50b54..0c5205530b 100644
--- a/phpBB/phpbb/log/log.php
+++ b/phpBB/phpbb/log/log.php
@@ -708,6 +708,50 @@ class log implements \phpbb\log\log_interface
}
}
+ /**
+ * Allow modifying or execute extra final filter on log entries
+ *
+ * @event core.get_logs_after
+ * @var array log Array with all our log entries
+ * @var array topic_id_list Array of topic ids, for which we
+ * get the permission data
+ * @var array reportee_id_list Array of additional user IDs we
+ * get the username strings for
+ * @var string mode Mode of the entries we display
+ * @var bool count_logs Do we count all matching entries?
+ * @var int limit Limit the number of entries
+ * @var int offset Offset when fetching the entries
+ * @var mixed forum_id Limit entries to the forum_id,
+ * can also be an array of forum_ids
+ * @var int topic_id Limit entries to the topic_id
+ * @var int user_id Limit entries to the user_id
+ * @var int log_time Limit maximum age of log entries
+ * @var string sort_by SQL order option
+ * @var string keywords Will only return entries that have the
+ * keywords in log_operation or log_data
+ * @var string profile_url URL to the users profile
+ * @var int log_type The type of logs it was filtered
+ * @since 3.1.3-RC1
+ */
+ $vars = array(
+ 'log',
+ 'topic_id_list',
+ 'reportee_id_list',
+ 'mode',
+ 'count_logs',
+ 'limit',
+ 'offset',
+ 'forum_id',
+ 'topic_id',
+ 'user_id',
+ 'log_time',
+ 'sort_by',
+ 'keywords',
+ 'profile_url',
+ 'log_type',
+ );
+ extract($this->dispatcher->trigger_event('core.get_logs_after', compact($vars)));
+
return $log;
}
diff --git a/phpBB/phpbb/message/topic_form.php b/phpBB/phpbb/message/topic_form.php
index 1e0f2a1945..174643bb81 100644
--- a/phpBB/phpbb/message/topic_form.php
+++ b/phpBB/phpbb/message/topic_form.php
@@ -117,7 +117,7 @@ class topic_form extends form
'TOPIC_NAME' => htmlspecialchars_decode($this->topic_row['topic_title']),
'U_TOPIC' => generate_board_url() . '/viewtopic.' . $this->phpEx . '?f=' . $this->topic_row['forum_id'] . '&t=' . $this->topic_id,
));
-
+ $this->message->set_body($this->body);
$this->message->add_recipient(
$this->recipient_name,
$this->recipient_address,
diff --git a/phpBB/phpbb/notification/manager.php b/phpBB/phpbb/notification/manager.php
index 971a53a16a..aa52eb61d0 100644
--- a/phpBB/phpbb/notification/manager.php
+++ b/phpBB/phpbb/notification/manager.php
@@ -38,6 +38,9 @@ class manager
/** @var \phpbb\config\config */
protected $config;
+ /** @var \phpbb\event\dispatcher */
+ protected $phpbb_dispatcher;
+
/** @var \phpbb\db\driver\driver_interface */
protected $db;
@@ -70,6 +73,7 @@ class manager
* @param ContainerInterface $phpbb_container
* @param \phpbb\user_loader $user_loader
* @param \phpbb\config\config $config
+ * @param \phpbb\event\dispatcher $phpbb_dispatcher
* @param \phpbb\db\driver\driver_interface $db
* @param \phpbb\cache\service $cache
* @param \phpbb\user $user
@@ -81,7 +85,7 @@ class manager
*
* @return \phpbb\notification\manager
*/
- public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
+ public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\event\dispatcher $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
{
$this->notification_types = $notification_types;
$this->notification_methods = $notification_methods;
@@ -89,6 +93,7 @@ class manager
$this->user_loader = $user_loader;
$this->config = $config;
+ $this->phpbb_dispatcher = $phpbb_dispatcher;
$this->db = $db;
$this->cache = $cache;
$this->user = $user;
@@ -292,7 +297,7 @@ class manager
WHERE notification_time <= " . (int) $time .
(($notification_type_name !== false) ? ' AND ' .
(is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name)) : '') .
- (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id) : 'item_parent_id = ' . (int) $item_parent_id) : '') .
+ (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id, false, true) : 'item_parent_id = ' . (int) $item_parent_id) : '') .
(($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '');
$this->db->sql_query($sql);
}
@@ -350,6 +355,26 @@ class manager
// find out which users want to receive this type of notification
$notify_users = $this->get_item_type_class($notification_type_name)->find_users_for_notification($data, $options);
+ /**
+ * Allow filtering the notify_users array for a notification that is about to be sent.
+ * Here, $notify_users is already filtered by f_read and the ignored list included in the options variable
+ *
+ * @event core.notification_manager_add_notifications
+ * @var string notification_type_name The forum id from where the topic belongs
+ * @var array data Data specific for the notification_type_name used will be inserted
+ * @var array notify_users The array of userid that are going to be notified for this notification. Set to array() to cancel.
+ * @var array options The options that were used when this method was called (read only)
+ *
+ * @since 3.1.3-RC1
+ */
+ $vars = array(
+ 'notification_type_name',
+ 'data',
+ 'notify_users',
+ 'options',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.notification_manager_add_notifications', compact($vars)));
+
$this->add_notifications_for_users($notification_type_name, $data, $notify_users);
return $notify_users;
diff --git a/phpBB/phpbb/path_helper.php b/phpBB/phpbb/path_helper.php
index 936564d8b6..5400c1c5a6 100644
--- a/phpBB/phpbb/path_helper.php
+++ b/phpBB/phpbb/path_helper.php
@@ -154,6 +154,7 @@ class path_helper
return $this->web_root_path;
}
+ // We do not need to escape $path_info, $request_uri and $script_name because we can not find their content in the result.
// Path info (e.g. /foo/bar)
$path_info = $this->filesystem->clean_path($this->symfony_request->getPathInfo());
@@ -203,9 +204,12 @@ class path_helper
*/
if ($this->request->is_ajax() && $this->symfony_request->get('_referer'))
{
+ // We need to escape $absolute_board_url because it can be partially concatenated to the result.
+ $absolute_board_url = $this->request->escape($this->symfony_request->getSchemeAndHttpHost() . $this->symfony_request->getBasePath(), true);
+
$referer_web_root_path = $this->get_web_root_path_from_ajax_referer(
$this->symfony_request->get('_referer'),
- $this->symfony_request->getSchemeAndHttpHost() . $this->symfony_request->getBasePath()
+ $absolute_board_url
);
return $this->web_root_path = $this->phpbb_root_path . $referer_web_root_path;
}
@@ -278,10 +282,16 @@ class path_helper
$referer_dir = dirname($referer_dir);
}
- while (strpos($absolute_board_url, $referer_dir) !== 0)
+ while (($dir_position = strpos($absolute_board_url, $referer_dir)) !== 0)
{
$fixed_root_path .= '../';
$referer_dir = dirname($referer_dir);
+
+ // Just return phpbb_root_path if we reach the top directory
+ if ($referer_dir === '.')
+ {
+ return $this->phpbb_root_path;
+ }
}
$fixed_root_path .= substr($absolute_board_url, strlen($referer_dir) + 1);
@@ -445,4 +455,38 @@ class path_helper
return $url_parts['base'] . (($params) ? '?' . $this->glue_url_params($params) : '');
}
+
+ /**
+ * Get a valid page
+ *
+ * @param string $page The page to verify
+ * @param bool $mod_rewrite Whether mod_rewrite is enabled, default: false
+ *
+ * @return string A valid page based on given page and mod_rewrite
+ */
+ public function get_valid_page($page, $mod_rewrite = false)
+ {
+ // We need to be cautious here.
+ // On some situations, the redirect path is an absolute URL, sometimes a relative path
+ // For a relative path, let's prefix it with $phpbb_root_path to point to the correct location,
+ // else we use the URL directly.
+ $url_parts = parse_url($page);
+
+ // URL
+ if ($url_parts === false || empty($url_parts['scheme']) || empty($url_parts['host']))
+ {
+ // Remove 'app.php/' from the page, when rewrite is enabled.
+ // Treat app.php as a reserved file name and remove on mod rewrite
+ // even if it might not be in the phpBB root.
+ if ($mod_rewrite && ($app_position = strpos($page, 'app.' . $this->php_ext . '/')) !== false)
+ {
+ $page = substr($page, 0, $app_position) . substr($page, $app_position + strlen('app.' . $this->php_ext . '/'));
+ }
+
+ // Remove preceding slashes from page name and prepend root path
+ $page = $this->get_phpbb_root_path() . ltrim($page, '/\\');
+ }
+
+ return $page;
+ }
}
diff --git a/phpBB/phpbb/profilefields/type/type_base.php b/phpBB/phpbb/profilefields/type/type_base.php
index 52f5d15511..9b4bada26d 100644
--- a/phpBB/phpbb/profilefields/type/type_base.php
+++ b/phpBB/phpbb/profilefields/type/type_base.php
@@ -158,7 +158,19 @@ abstract class type_base implements type_interface
}
else
{
- return $this->request->variable($key, '', true);
+ $default_value = '';
+ $lang_fields = array(
+ 'l_lang_name',
+ 'l_lang_explain',
+ 'l_lang_default_value',
+ 'l_lang_options',
+ );
+
+ if (in_array($key, $lang_fields))
+ {
+ $default_value = array(0 => '');
+ }
+ return $this->request->variable($key, $default_value, true);
}
}
diff --git a/phpBB/phpbb/profilefields/type/type_bool.php b/phpBB/phpbb/profilefields/type/type_bool.php
index 3a13102117..77eedcbd04 100644
--- a/phpBB/phpbb/profilefields/type/type_bool.php
+++ b/phpBB/phpbb/profilefields/type/type_bool.php
@@ -352,7 +352,7 @@ class type_bool extends type_base
}
}
- if ($step == 3 && ($field_data[$key] || $action != 'edit') && $key == 'l_lang_options')
+ if ($key == 'l_lang_options' && $this->request->is_set($key))
{
$field_data[$key] = $this->request->variable($key, array(0 => array('')), true);
diff --git a/phpBB/phpbb/profilefields/type/type_string_common.php b/phpBB/phpbb/profilefields/type/type_string_common.php
index ff33a7b49c..f5e1992044 100644
--- a/phpBB/phpbb/profilefields/type/type_string_common.php
+++ b/phpBB/phpbb/profilefields/type/type_string_common.php
@@ -18,11 +18,11 @@ abstract class type_string_common extends type_base
protected $validation_options = array(
'CHARS_ANY' => '.*',
'NUMBERS_ONLY' => '[0-9]+',
- 'ALPHA_ONLY' => '[\w]+',
- 'ALPHA_UNDERSCORE' => '[\w_]+',
- 'ALPHA_DOTS' => '[\w.]+',
- 'ALPHA_SPACERS' => '[\w\x20_+\-\[\]]+',
- 'ALPHA_PUNCTUATION' => '[a-zA-Z][\w\.,\-_]+',
+ 'ALPHA_ONLY' => '[a-zA-Z0-9]+',
+ 'ALPHA_UNDERSCORE' => '[\w]+',
+ 'ALPHA_DOTS' => '[a-zA-Z0-9.]+',
+ 'ALPHA_SPACERS' => '[\w\x20+\-\[\]]+',
+ 'ALPHA_PUNCTUATION' => '[a-zA-Z][\w\.,\-]+',
'LETTER_NUM_ONLY' => '[\p{Lu}\p{Ll}0-9]+',
'LETTER_NUM_UNDERSCORE' => '[\p{Lu}\p{Ll}0-9_]+',
'LETTER_NUM_DOTS' => '[\p{Lu}\p{Ll}0-9.]+',
diff --git a/phpBB/phpbb/profilefields/type/type_url.php b/phpBB/phpbb/profilefields/type/type_url.php
index bc8ac869d0..fe0bffd582 100644
--- a/phpBB/phpbb/profilefields/type/type_url.php
+++ b/phpBB/phpbb/profilefields/type/type_url.php
@@ -64,7 +64,7 @@ class type_url extends type_string
return false;
}
- if (!preg_match('#^' . get_preg_expression('url') . '$#i', $field_value))
+ if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $field_value))
{
return $this->user->lang('FIELD_INVALID_URL', $this->get_field_name($field_data['lang_name']));
}
diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php
index ea9854894c..56ce3999ed 100644
--- a/phpBB/phpbb/request/request.php
+++ b/phpBB/phpbb/request/request.php
@@ -275,7 +275,7 @@ class request implements \phpbb\request\request_interface
*/
public function file($form_name)
{
- return $this->variable($form_name, array('name' => 'none'), false, \phpbb\request\request_interface::FILES);
+ return $this->variable($form_name, array('name' => 'none'), true, \phpbb\request\request_interface::FILES);
}
/**
@@ -416,4 +416,27 @@ class request implements \phpbb\request\request_interface
{
return $this->input[$super_global];
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function escape($var, $multibyte)
+ {
+ if (is_array($var))
+ {
+ $result = array();
+ foreach ($var as $key => $value)
+ {
+ $this->type_cast_helper->set_var($key, $key, gettype($key), $multibyte);
+ $result[$key] = $this->escape($value, $multibyte);
+ }
+ $var = $result;
+ }
+ else
+ {
+ $this->type_cast_helper->set_var($var, $var, 'string', $multibyte);
+ }
+
+ return $var;
+ }
}
diff --git a/phpBB/phpbb/request/request_interface.php b/phpBB/phpbb/request/request_interface.php
index 3236f73990..47b3b3a4ed 100644
--- a/phpBB/phpbb/request/request_interface.php
+++ b/phpBB/phpbb/request/request_interface.php
@@ -142,4 +142,14 @@ interface request_interface
* @return array The original array of the requested super global.
*/
public function get_super_global($super_global = \phpbb\request\request_interface::REQUEST);
+
+ /**
+ * Escape a string variable.
+ *
+ * @param mixed $value The contents to fill with
+ * @param bool $multibyte Indicates whether string values may contain UTF-8 characters.
+ * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks.
+ * @return string|array
+ */
+ public function escape($value, $multibyte);
}
diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php
index 48b0f077c7..8865d37712 100644
--- a/phpBB/phpbb/search/fulltext_native.php
+++ b/phpBB/phpbb/search/fulltext_native.php
@@ -434,7 +434,7 @@ class fulltext_native extends \phpbb\search\base
// throw an error if we shall not ignore unexistant words
else if (!$ignore_no_id && sizeof($non_common_words))
{
- trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], implode($user->lang['COMMA_SEPARATOR'], $non_common_words)));
+ trigger_error(sprintf($this->user->lang['WORDS_IN_NO_POST'], implode($this->user->lang['COMMA_SEPARATOR'], $non_common_words)));
}
unset($non_common_words);
}
diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php
index a06ff9c594..0a6a18ffbe 100644
--- a/phpBB/phpbb/session.php
+++ b/phpBB/phpbb/session.php
@@ -31,10 +31,11 @@ class session
var $update_session_page = true;
/**
- * Extract current session page
- *
- * @param string $root_path current root path (phpbb_root_path)
- */
+ * Extract current session page
+ *
+ * @param string $root_path current root path (phpbb_root_path)
+ * @return array
+ */
static function extract_current_page($root_path)
{
global $request, $symfony_request, $phpbb_filesystem;
@@ -42,8 +43,8 @@ class session
$page_array = array();
// First of all, get the request uri...
- $script_name = $symfony_request->getScriptName();
- $args = explode('&amp;', $symfony_request->getQueryString());
+ $script_name = $request->escape($symfony_request->getScriptName(), true);
+ $args = $request->escape(explode('&', $symfony_request->getQueryString()), true);
// If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support...
if (!$script_name)
@@ -1062,7 +1063,7 @@ class session
$name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
$expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
- $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
+ $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == '127.0.0.1' || strpos($config['cookie_domain'], '.') === false) ? '' : '; domain=' . $config['cookie_domain'];
header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false);
}
@@ -1081,7 +1082,7 @@ class session
*/
function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
{
- global $config, $db;
+ global $config, $db, $phpbb_dispatcher;
if (defined('IN_CHECK_BAN') || defined('SKIP_CHECK_BAN'))
{
@@ -1195,6 +1196,20 @@ class session
}
$db->sql_freeresult($result);
+ /**
+ * Event to set custom ban type
+ *
+ * @event core.session_set_custom_ban
+ * @var bool return If $return is false this routine does not return on finding a banned user, it outputs a relevant message and stops execution
+ * @var bool banned Check if user already banned
+ * @var array|false ban_row Ban data
+ * @var string ban_triggered_by Method that caused ban, can be your custom method
+ * @since 3.1.3-RC1
+ */
+ $ban_row = isset($ban_row) ? $ban_row : false;
+ $vars = array('return', 'banned', 'ban_row', 'ban_triggered_by');
+ extract($phpbb_dispatcher->trigger_event('core.session_set_custom_ban', compact($vars)));
+
if ($banned && !$return)
{
global $template, $phpbb_root_path, $phpEx;
diff --git a/phpBB/phpbb/symfony_request.php b/phpBB/phpbb/symfony_request.php
index 02d22c480f..2931cae3cc 100644
--- a/phpBB/phpbb/symfony_request.php
+++ b/phpBB/phpbb/symfony_request.php
@@ -15,6 +15,10 @@ namespace phpbb;
use Symfony\Component\HttpFoundation\Request;
+/**
+ * WARNING: The Symfony request does not escape the input and should be used very carefully
+ * prefer the phpbb request as possible
+ */
class symfony_request extends Request
{
/**
@@ -24,32 +28,12 @@ class symfony_request extends Request
*/
public function __construct(\phpbb\request\request_interface $phpbb_request)
{
- // This function is meant to sanitize the global input arrays
- $sanitizer = function(&$value, $key) {
- $type_cast_helper = new \phpbb\request\type_cast_helper();
- $type_cast_helper->set_var($value, $value, gettype($value), true);
- };
-
- // This function is meant for additional handling of server variables
- $server_sanitizer = function(&$value, $key) use ($sanitizer) {
- $sanitizer($value, $key);
- $value = str_replace('&amp;', '&', $value);
- };
-
$get_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::GET);
$post_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::POST);
$server_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::SERVER);
$files_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::FILES);
$cookie_parameters = $phpbb_request->get_super_global(\phpbb\request\request_interface::COOKIE);
- array_walk_recursive($get_parameters, $sanitizer);
- array_walk_recursive($post_parameters, $sanitizer);
- array_walk_recursive($files_parameters, $sanitizer);
- array_walk_recursive($cookie_parameters, $sanitizer);
-
- // Run special sanitizer for server superglobal
- array_walk_recursive($server_parameters, $server_sanitizer);
-
parent::__construct($get_parameters, $post_parameters, array(), $cookie_parameters, $files_parameters, $server_parameters);
}
}
diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php
index a3b002f350..db3a8e3571 100644
--- a/phpBB/phpbb/template/twig/twig.php
+++ b/phpBB/phpbb/template/twig/twig.php
@@ -115,6 +115,11 @@ class twig extends \phpbb\template\base
)
);
+ if (defined('DEBUG'))
+ {
+ $this->twig->addExtension(new \Twig_Extension_Debug());
+ }
+
$lexer = new \phpbb\template\twig\lexer($this->twig);
$this->twig->setLexer($lexer);
@@ -189,13 +194,24 @@ class twig extends \phpbb\template\base
{
$path = $this->phpbb_root_path . trim($directory, '/') . "/{$name}/";
$template_path = $path . 'template/';
+ $theme_path = $path . 'theme/';
+ $is_valid_dir = false;
if (is_dir($template_path))
{
+ $is_valid_dir = true;
+ $paths[] = $template_path;
+ }
+ if (is_dir($theme_path))
+ {
+ $is_valid_dir = true;
+ $paths[] = $theme_path;
+ }
+
+ if ($is_valid_dir)
+ {
// Add the base style directory as a safe directory
$this->twig->getLoader()->addSafeDirectory($path);
-
- $paths[] = $template_path;
}
}
}
@@ -253,25 +269,38 @@ class twig extends \phpbb\template\base
{
$ext_style_template_path = $ext_path . $template_dir['ext_path'];
$ext_style_path = dirname($ext_style_template_path);
+ $ext_style_theme_path = $ext_style_path . 'theme/';
}
else
{
$ext_style_path = $ext_path . 'styles/' . $template_dir['name'] . '/';
$ext_style_template_path = $ext_style_path . 'template/';
+ $ext_style_theme_path = $ext_style_path . 'theme/';
}
}
else
{
$ext_style_path = $ext_path . 'styles/' . $template_dir . '/';
$ext_style_template_path = $ext_style_path . 'template/';
+ $ext_style_theme_path = $ext_style_path . 'theme/';
}
+ $ok = false;
if (is_dir($ext_style_template_path))
{
+ $ok = true;
+ $paths[] = $ext_style_template_path;
+ }
+ if (is_dir($ext_style_theme_path))
+ {
+ $ok = true;
+ $paths[] = $ext_style_theme_path;
+ }
+
+ if ($ok)
+ {
// Add the base style directory as a safe directory
$this->twig->getLoader()->addSafeDirectory($ext_style_path);
-
- $paths[] = $ext_style_template_path;
}
}
diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php
index 96386f6d04..dc62f06fb2 100644
--- a/phpBB/phpbb/version_helper.php
+++ b/phpBB/phpbb/version_helper.php
@@ -50,6 +50,9 @@ class version_helper
/** @var \phpbb\config\config */
protected $config;
+ /** @var \phpbb\file_downloader */
+ protected $file_downloader;
+
/** @var \phpbb\user */
protected $user;
@@ -58,12 +61,14 @@ class version_helper
*
* @param \phpbb\cache\service $cache
* @param \phpbb\config\config $config
+ * @param \phpbb\file_downloader $file_downloader
* @param \phpbb\user $user
*/
- public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\user $user)
+ public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader, \phpbb\user $user)
{
$this->cache = $cache;
$this->config = $config;
+ $this->file_downloader = $file_downloader;
$this->user = $user;
if (defined('PHPBB_QA'))
@@ -249,16 +254,32 @@ class version_helper
}
else if ($info === false || $force_update)
{
- $errstr = $errno = '';
- $info = get_remote_file($this->host, $this->path, $this->file, $errstr, $errno);
+ try {
+ $info = $this->file_downloader->get($this->host, $this->path, $this->file);
+ }
+ catch (\RuntimeException $exception)
+ {
+ throw new \RuntimeException($this->user->lang($exception->getMessage()));
+ }
+ $error_string = $this->file_downloader->get_error_string();
- if (!empty($errstr))
+ if (!empty($error_string))
{
- throw new \RuntimeException($errstr);
+ throw new \RuntimeException($error_string);
}
$info = json_decode($info, true);
+ // Sanitize any data we retrieve from a server
+ if (!empty($info))
+ {
+ $json_sanitizer = function (&$value, $key) {
+ $type_cast_helper = new \phpbb\request\type_cast_helper();
+ $type_cast_helper->set_var($value, $value, gettype($value), true);
+ };
+ array_walk_recursive($info, $json_sanitizer);
+ }
+
if (empty($info['stable']) && empty($info['unstable']))
{
$this->user->add_lang('acp/common');
@@ -266,15 +287,6 @@ class version_helper
throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL'));
}
- // Replace & with &amp; on announcement links
- foreach ($info as $stability => $branches)
- {
- foreach ($branches as $branch => $branch_data)
- {
- $info[$stability][$branch]['announcement'] = str_replace('&', '&amp;', $branch_data['announcement']);
- }
- }
-
$info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
$info['unstable'] = (empty($info['unstable'])) ? $info['stable'] : $info['unstable'];