aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/phpbb
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/phpbb')
-rw-r--r--phpBB/phpbb/avatar/driver/upload.php16
-rw-r--r--phpBB/phpbb/cache/driver/memcached.php134
-rw-r--r--phpBB/phpbb/console/command/extension/disable.php7
-rw-r--r--phpBB/phpbb/console/command/extension/enable.php7
-rw-r--r--phpBB/phpbb/console/command/update/check.php2
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php32
-rw-r--r--phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php7
-rw-r--r--phpBB/phpbb/di/extension/core.php2
-rw-r--r--phpBB/phpbb/event/data.php12
-rw-r--r--phpBB/phpbb/event/php_exporter.php4
-rw-r--r--phpBB/phpbb/extension/manager.php65
-rw-r--r--phpBB/phpbb/extension/metadata_manager.php199
-rw-r--r--phpBB/phpbb/request/request.php6
-rw-r--r--phpBB/phpbb/template/base.php8
-rw-r--r--phpBB/phpbb/template/context.php194
-rw-r--r--phpBB/phpbb/template/template.php20
-rw-r--r--phpBB/phpbb/template/twig/environment.php36
-rw-r--r--phpBB/phpbb/textformatter/s9e/quote_helper.php4
-rw-r--r--phpBB/phpbb/version_helper.php73
19 files changed, 582 insertions, 246 deletions
diff --git a/phpBB/phpbb/avatar/driver/upload.php b/phpBB/phpbb/avatar/driver/upload.php
index 2640e1ad1e..4effa4c410 100644
--- a/phpBB/phpbb/avatar/driver/upload.php
+++ b/phpBB/phpbb/avatar/driver/upload.php
@@ -281,12 +281,20 @@ class upload extends \phpbb\avatar\driver\driver
);
extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars)));
- if (!sizeof($error) && file_exists($filename))
+ if (!sizeof($error) && $this->filesystem->exists($filename))
{
- @unlink($filename);
+ try
+ {
+ $this->filesystem->remove($filename);
+ return true;
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Fail is covered by return statement below
+ }
}
- return true;
+ return false;
}
/**
@@ -304,6 +312,6 @@ class upload extends \phpbb\avatar\driver\driver
*/
protected function can_upload()
{
- return (file_exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
+ return ($this->filesystem->exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
}
}
diff --git a/phpBB/phpbb/cache/driver/memcached.php b/phpBB/phpbb/cache/driver/memcached.php
new file mode 100644
index 0000000000..105e763af4
--- /dev/null
+++ b/phpBB/phpbb/cache/driver/memcached.php
@@ -0,0 +1,134 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\cache\driver;
+
+if (!defined('PHPBB_ACM_MEMCACHED_PORT'))
+{
+ define('PHPBB_ACM_MEMCACHED_PORT', 11211);
+}
+
+if (!defined('PHPBB_ACM_MEMCACHED_COMPRESS'))
+{
+ define('PHPBB_ACM_MEMCACHED_COMPRESS', true);
+}
+
+if (!defined('PHPBB_ACM_MEMCACHED_HOST'))
+{
+ define('PHPBB_ACM_MEMCACHED_HOST', 'localhost');
+}
+
+if (!defined('PHPBB_ACM_MEMCACHED'))
+{
+ //can define multiple servers with host1/port1,host2/port2 format
+ define('PHPBB_ACM_MEMCACHED', PHPBB_ACM_MEMCACHED_HOST . '/' . PHPBB_ACM_MEMCACHED_PORT);
+}
+
+/**
+* ACM for Memcached
+*/
+class memcached extends \phpbb\cache\driver\memory
+{
+ /** @var string Extension to use */
+ protected $extension = 'memcached';
+
+ /** @var \Memcached Memcached class */
+ protected $memcached;
+
+ /** @var int Flags */
+ protected $flags = 0;
+
+ /**
+ * Memcached constructor
+ */
+ public function __construct()
+ {
+ // Call the parent constructor
+ parent::__construct();
+
+ $this->memcached = new \Memcached();
+ $this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
+ // Memcached defaults to using compression, disable if we don't want
+ // to use it
+ if (!PHPBB_ACM_MEMCACHED_COMPRESS)
+ {
+ $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false);
+ }
+
+ foreach (explode(',', PHPBB_ACM_MEMCACHE) as $u)
+ {
+ $parts = explode('/', $u);
+ $this->memcached->addServer(trim($parts[0]), trim($parts[1]));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unload()
+ {
+ parent::unload();
+
+ unset($this->memcached);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function purge()
+ {
+ $this->memcached->flush();
+
+ parent::purge();
+ }
+
+ /**
+ * Fetch an item from the cache
+ *
+ * @param string $var Cache key
+ *
+ * @return mixed Cached data
+ */
+ protected function _read($var)
+ {
+ return $this->memcached->get($this->key_prefix . $var);
+ }
+
+ /**
+ * Store data in the cache
+ *
+ * @param string $var Cache key
+ * @param mixed $data Data to store
+ * @param int $ttl Time-to-live of cached data
+ * @return bool True if the operation succeeded
+ */
+ protected function _write($var, $data, $ttl = 2592000)
+ {
+ if (!$this->memcached->replace($this->key_prefix . $var, $data, $ttl))
+ {
+ return $this->memcached->set($this->key_prefix . $var, $data, $ttl);
+ }
+ return true;
+ }
+
+ /**
+ * Remove an item from the cache
+ *
+ * @param string $var Cache key
+ * @return bool True if the operation succeeded
+ */
+ protected function _delete($var)
+ {
+ return $this->memcached->delete($this->key_prefix . $var);
+ }
+}
diff --git a/phpBB/phpbb/console/command/extension/disable.php b/phpBB/phpbb/console/command/extension/disable.php
index d022755753..b2e10fb960 100644
--- a/phpBB/phpbb/console/command/extension/disable.php
+++ b/phpBB/phpbb/console/command/extension/disable.php
@@ -37,6 +37,13 @@ class disable extends command
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('extension-name');
+
+ if (!$this->manager->is_enabled($name))
+ {
+ $io->error($this->user->lang('CLI_EXTENSION_DISABLED', $name));
+ return 2;
+ }
+
$this->manager->disable($name);
$this->manager->load_extensions();
diff --git a/phpBB/phpbb/console/command/extension/enable.php b/phpBB/phpbb/console/command/extension/enable.php
index 14077d688b..a8312d5c15 100644
--- a/phpBB/phpbb/console/command/extension/enable.php
+++ b/phpBB/phpbb/console/command/extension/enable.php
@@ -37,6 +37,13 @@ class enable extends command
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('extension-name');
+
+ if ($this->manager->is_enabled($name))
+ {
+ $io->error($this->user->lang('CLI_EXTENSION_ENABLED', $name));
+ return 2;
+ }
+
$this->manager->enable($name);
$this->manager->load_extensions();
diff --git a/phpBB/phpbb/console/command/update/check.php b/phpBB/phpbb/console/command/update/check.php
index 1f1cfa25d2..ed8ad79eea 100644
--- a/phpBB/phpbb/console/command/update/check.php
+++ b/phpBB/phpbb/console/command/update/check.php
@@ -134,7 +134,7 @@ class check extends \phpbb\console\command\command
try
{
$ext_manager = $this->phpbb_container->get('ext.manager');
- $md_manager = $ext_manager->create_extension_metadata_manager($ext_name, null);
+ $md_manager = $ext_manager->create_extension_metadata_manager($ext_name);
$updates_available = $ext_manager->version_check($md_manager, $recheck, false, $stability);
$metadata = $md_manager->get_metadata('all');
diff --git a/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php b/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php
new file mode 100644
index 0000000000..92051dc3ca
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php
@@ -0,0 +1,32 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class add_smtp_ssl_context_config_options extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v31x\v3110');
+ }
+
+ public function update_data()
+ {
+ return array(
+ // See http://php.net/manual/en/context.ssl.php
+ array('config.add', array('smtp_verify_peer', 1)),
+ array('config.add', array('smtp_verify_peer_name', 1)),
+ array('config.add', array('smtp_allow_self_signed', 0)),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php b/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php
index afa67fbc58..8fadb4bde4 100644
--- a/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php
+++ b/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php
@@ -32,10 +32,9 @@ class add_help_phpbb extends \phpbb\db\migration\migration
return array(
array('config.add', array('help_send_statistics', true)),
array('config.add', array('help_send_statistics_time', 0)),
- array('module.remove', array(
- 'acp',
- false,
- 'ACP_SEND_STATISTICS',
+ array('if', array(
+ array('module.exists', array('acp', false, 'ACP_SEND_STATISTICS')),
+ array('module.remove', array('acp', false, 'ACP_SEND_STATISTICS')),
)),
array('module.add', array(
'acp',
diff --git a/phpBB/phpbb/di/extension/core.php b/phpBB/phpbb/di/extension/core.php
index 29c0b0e44e..67150f0103 100644
--- a/phpBB/phpbb/di/extension/core.php
+++ b/phpBB/phpbb/di/extension/core.php
@@ -24,7 +24,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
*/
class core extends Extension
{
- const TWIG_OPTIONS_POSITION = 6;
+ const TWIG_OPTIONS_POSITION = 7;
/**
* Config path
diff --git a/phpBB/phpbb/event/data.php b/phpBB/phpbb/event/data.php
index c7365aee35..276ab027f2 100644
--- a/phpBB/phpbb/event/data.php
+++ b/phpBB/phpbb/event/data.php
@@ -63,4 +63,16 @@ class data extends Event implements \ArrayAccess
{
unset($this->data[$offset]);
}
+
+ /**
+ * Returns data with updated key in specified offset.
+ *
+ * @param string $subarray Data array subarray
+ * @param string $key Subarray key
+ * @param mixed $value Value to update
+ */
+ public function update_subarray($subarray, $key, $value)
+ {
+ $this->data[$subarray][$key] = $value;
+ }
}
diff --git a/phpBB/phpbb/event/php_exporter.php b/phpBB/phpbb/event/php_exporter.php
index d2ab0595c0..ae3553c558 100644
--- a/phpBB/phpbb/event/php_exporter.php
+++ b/phpBB/phpbb/event/php_exporter.php
@@ -510,7 +510,7 @@ class php_exporter
/**
* Find the "@changed" Information lines
*
- * @param string $tag_name Should be 'changed' or 'change'
+ * @param string $tag_name Should be 'change', not 'changed'
* @return array Absolute line numbers
* @throws \LogicException
*/
@@ -658,7 +658,7 @@ class php_exporter
{
$match = array();
$line = str_replace("\t", ' ', ltrim($line, "\t "));
- preg_match('#^\* @change(d)? (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)( (?:.*))?$#', $line, $match);
+ preg_match('#^\* @changed (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)( (?:.*))?$#', $line, $match);
if (!isset($match[2]))
{
throw new \LogicException("Invalid '@changed' information for event "
diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php
index ca0ff31d5d..00aa2c6826 100644
--- a/phpBB/phpbb/extension/manager.php
+++ b/phpBB/phpbb/extension/manager.php
@@ -152,7 +152,12 @@ class manager
*/
public function create_extension_metadata_manager($name)
{
- return new \phpbb\extension\metadata_manager($name, $this->config, $this, $this->phpbb_root_path);
+ if (!isset($this->extensions[$name]['metadata']))
+ {
+ $metadata = new \phpbb\extension\metadata_manager($name, $this->get_extension_path($name, true));
+ $this->extensions[$name]['metadata'] = $metadata;
+ }
+ return $this->extensions[$name]['metadata'];
}
/**
@@ -168,7 +173,7 @@ class manager
public function enable_step($name)
{
// ignore extensions that are already enabled
- if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'])
+ if ($this->is_enabled($name))
{
return false;
}
@@ -258,7 +263,7 @@ class manager
public function disable_step($name)
{
// ignore extensions that are already disabled
- if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active'])
+ if ($this->is_disabled($name))
{
return false;
}
@@ -336,8 +341,8 @@ class manager
*/
public function purge_step($name)
{
- // ignore extensions that do not exist
- if (!isset($this->extensions[$name]))
+ // ignore extensions that are not configured
+ if (!$this->is_configured($name))
{
return false;
}
@@ -431,25 +436,11 @@ class manager
if ($file_info->isFile() && $file_info->getFilename() == 'composer.json')
{
$ext_name = $iterator->getInnerIterator()->getSubPath();
- $composer_file = $iterator->getPath() . '/composer.json';
-
- // Ignore the extension if there is no composer.json.
- if (!is_readable($composer_file) || !($ext_info = file_get_contents($composer_file)))
- {
- continue;
- }
-
- $ext_info = json_decode($ext_info, true);
$ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name);
-
- // Ignore the extension if directory depth is not correct or if the directory structure
- // does not match the name value specified in composer.json.
- if (substr_count($ext_name, '/') !== 1 || !isset($ext_info['name']) || $ext_name != $ext_info['name'])
+ if ($this->is_available($ext_name))
{
- continue;
+ $available[$ext_name] = $this->get_extension_path($ext_name, true);
}
-
- $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/';
}
}
ksort($available);
@@ -472,8 +463,12 @@ class manager
$configured = array();
foreach ($this->extensions as $name => $data)
{
- $data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
- $configured[$name] = $data;
+ if ($this->is_configured($name))
+ {
+ unset($data['metadata']);
+ $data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
+ $configured[$name] = $data;
+ }
}
return $configured;
}
@@ -490,7 +485,7 @@ class manager
$enabled = array();
foreach ($this->extensions as $name => $data)
{
- if ($data['ext_active'])
+ if ($this->is_enabled($name))
{
$enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
}
@@ -511,7 +506,7 @@ class manager
$disabled = array();
foreach ($this->extensions as $name => $data)
{
- if (!$data['ext_active'])
+ if ($this->is_disabled($name))
{
$disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
}
@@ -527,7 +522,15 @@ class manager
*/
public function is_available($name)
{
- return file_exists($this->get_extension_path($name, true));
+ $md_manager = $this->create_extension_metadata_manager($name);
+ try
+ {
+ return $md_manager->get_metadata('all') && $md_manager->validate_enable();
+ }
+ catch (\phpbb\extension\exception $e)
+ {
+ return false;
+ }
}
/**
@@ -538,7 +541,7 @@ class manager
*/
public function is_enabled($name)
{
- return isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'];
+ return isset($this->extensions[$name]['ext_active']) && $this->extensions[$name]['ext_active'];
}
/**
@@ -549,7 +552,7 @@ class manager
*/
public function is_disabled($name)
{
- return isset($this->extensions[$name]) && !$this->extensions[$name]['ext_active'];
+ return isset($this->extensions[$name]['ext_active']) && !$this->extensions[$name]['ext_active'];
}
/**
@@ -563,7 +566,7 @@ class manager
*/
public function is_configured($name)
{
- return isset($this->extensions[$name]);
+ return isset($this->extensions[$name]['ext_active']);
}
/**
@@ -573,7 +576,7 @@ class manager
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
* @param string $stability Force the stability (null by default).
- * @return string
+ * @return array
* @throws runtime_exception
*/
public function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false, $stability = null)
@@ -592,7 +595,7 @@ class manager
$version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename'], isset($version_check['ssl']) ? $version_check['ssl'] : false);
$version_helper->force_stability($stability);
- return $updates = $version_helper->get_suggested_updates($force_update, $force_cache);
+ return $version_helper->get_ext_update_on_branch($force_update, $force_cache);
}
/**
diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php
index ae1af10c1d..60b8db8310 100644
--- a/phpBB/phpbb/extension/metadata_manager.php
+++ b/phpBB/phpbb/extension/metadata_manager.php
@@ -19,24 +19,6 @@ namespace phpbb\extension;
class metadata_manager
{
/**
- * phpBB Config instance
- * @var \phpbb\config\config
- */
- protected $config;
-
- /**
- * phpBB Extension Manager
- * @var \phpbb\extension\manager
- */
- protected $extension_manager;
-
- /**
- * phpBB root path
- * @var string
- */
- protected $phpbb_root_path;
-
- /**
* Name (including vendor) of the extension
* @var string
*/
@@ -58,19 +40,13 @@ class metadata_manager
* Creates the metadata manager
*
* @param string $ext_name Name (including vendor) of the extension
- * @param \phpbb\config\config $config phpBB Config instance
- * @param \phpbb\extension\manager $extension_manager An instance of the phpBB extension manager
- * @param string $phpbb_root_path Path to the phpbb includes directory.
+ * @param string $ext_path Path to the extension directory including root path
*/
- public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, $phpbb_root_path)
+ public function __construct($ext_name, $ext_path)
{
- $this->config = $config;
- $this->extension_manager = $extension_manager;
- $this->phpbb_root_path = $phpbb_root_path;
-
$this->ext_name = $ext_name;
$this->metadata = array();
- $this->metadata_file = '';
+ $this->metadata_file = $ext_path . 'composer.json';
}
/**
@@ -81,92 +57,56 @@ class metadata_manager
*/
public function get_metadata($element = 'all')
{
- $this->set_metadata_file();
-
- // Fetch the metadata
- $this->fetch_metadata();
-
- // Clean the metadata
- $this->clean_metadata_array();
+ // Fetch and clean the metadata if not done yet
+ if ($this->metadata === array())
+ {
+ $this->fetch_metadata_from_file();
+ }
switch ($element)
{
case 'all':
default:
- // Validate the metadata
- if (!$this->validate())
- {
- return false;
- }
-
+ $this->validate();
return $this->metadata;
break;
case 'version':
case 'name':
- return ($this->validate($element)) ? $this->metadata[$element] : false;
+ $this->validate($element);
+ return $this->metadata[$element];
break;
case 'display-name':
- if (isset($this->metadata['extra']['display-name']))
- {
- return $this->metadata['extra']['display-name'];
- }
- else
- {
- return ($this->validate('name')) ? $this->metadata['name'] : false;
- }
+ return (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : $this->get_metadata('name');
break;
}
}
/**
- * Sets the filepath of the metadata file
+ * Gets the metadata file contents and cleans loaded file
*
* @throws \phpbb\extension\exception
*/
- private function set_metadata_file()
+ private function fetch_metadata_from_file()
{
- $ext_filepath = $this->extension_manager->get_extension_path($this->ext_name);
- $metadata_filepath = $this->phpbb_root_path . $ext_filepath . 'composer.json';
-
- $this->metadata_file = $metadata_filepath;
-
if (!file_exists($this->metadata_file))
{
throw new \phpbb\extension\exception('FILE_NOT_FOUND', array($this->metadata_file));
}
- }
- /**
- * Gets the contents of the composer.json file
- *
- * @return bool True if success, throws an exception on failure
- * @throws \phpbb\extension\exception
- */
- private function fetch_metadata()
- {
- if (!file_exists($this->metadata_file))
+ if (!($file_contents = file_get_contents($this->metadata_file)))
{
- throw new \phpbb\extension\exception('FILE_NOT_FOUND', array($this->metadata_file));
+ throw new \phpbb\extension\exception('FILE_CONTENT_ERR', array($this->metadata_file));
}
- else
- {
- if (!($file_contents = file_get_contents($this->metadata_file)))
- {
- throw new \phpbb\extension\exception('FILE_CONTENT_ERR', array($this->metadata_file));
- }
-
- if (($metadata = json_decode($file_contents, true)) === null)
- {
- throw new \phpbb\extension\exception('FILE_JSON_DECODE_ERR', array($this->metadata_file));
- }
-
- array_walk_recursive($metadata, array($this, 'sanitize_json'));
- $this->metadata = $metadata;
- return true;
+ if (($metadata = json_decode($file_contents, true)) === null)
+ {
+ throw new \phpbb\extension\exception('FILE_JSON_DECODE_ERR', array($this->metadata_file));
}
+
+ array_walk_recursive($metadata, array($this, 'sanitize_json'));
+ $this->metadata = $metadata;
}
/**
@@ -181,16 +121,6 @@ class metadata_manager
}
/**
- * This array handles the cleaning of the array
- *
- * @return array Contains the cleaned metadata array
- */
- private function clean_metadata_array()
- {
- return $this->metadata;
- }
-
- /**
* Validate fields
*
* @param string $name ("all" for display and enable validation
@@ -212,23 +142,8 @@ class metadata_manager
switch ($name)
{
case 'all':
- $this->validate('display');
-
- if (!$this->validate_dir())
- {
- throw new \phpbb\extension\exception('EXTENSION_DIR_INVALID');
- }
-
- if (!$this->validate_require_phpbb())
- {
- throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('soft-require'));
- }
-
- if (!$this->validate_require_php())
- {
- throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('require php'));
- }
- break;
+ $this->validate_enable();
+ // no break
case 'display':
foreach ($fields as $field => $data)
@@ -285,40 +200,43 @@ class metadata_manager
/**
* This array handles the verification that this extension can be enabled on this board
*
- * @return bool True if validation succeeded, False if failed
+ * @return bool True if validation succeeded, throws an exception if invalid
+ * @throws \phpbb\extension\exception
*/
public function validate_enable()
{
// Check for valid directory & phpBB, PHP versions
- if (!$this->validate_dir() || !$this->validate_require_phpbb() || !$this->validate_require_php())
- {
- return false;
- }
-
- return true;
+ return $this->validate_dir() && $this->validate_require_phpbb() && $this->validate_require_php();
}
/**
* Validates the most basic directory structure to ensure it follows <vendor>/<ext> convention.
*
- * @return boolean True when passes validation
+ * @return boolean True when passes validation, throws an exception if invalid
+ * @throws \phpbb\extension\exception
*/
public function validate_dir()
{
- return (substr_count($this->ext_name, '/') === 1 && $this->ext_name == $this->get_metadata('name'));
+ if (substr_count($this->ext_name, '/') !== 1 || $this->ext_name != $this->get_metadata('name'))
+ {
+ throw new \phpbb\extension\exception('EXTENSION_DIR_INVALID');
+ }
+
+ return true;
}
/**
* Validates the contents of the phpbb requirement field
*
- * @return boolean True when passes validation
+ * @return boolean True when passes validation, throws an exception if invalid
+ * @throws \phpbb\extension\exception
*/
public function validate_require_phpbb()
{
if (!isset($this->metadata['extra']['soft-require']['phpbb/phpbb']))
{
- return false;
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('soft-require'));
}
return true;
@@ -327,51 +245,16 @@ class metadata_manager
/**
* Validates the contents of the php requirement field
*
- * @return boolean True when passes validation
+ * @return boolean True when passes validation, throws an exception if invalid
+ * @throws \phpbb\extension\exception
*/
public function validate_require_php()
{
if (!isset($this->metadata['require']['php']))
{
- return false;
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('require php'));
}
return true;
}
-
- /**
- * Outputs the metadata into the template
- *
- * @param \phpbb\template\template $template phpBB Template instance
- */
- public function output_template_data(\phpbb\template\template $template)
- {
- $template->assign_vars(array(
- 'META_NAME' => $this->metadata['name'],
- 'META_TYPE' => $this->metadata['type'],
- 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? $this->metadata['description'] : '',
- 'META_HOMEPAGE' => (isset($this->metadata['homepage'])) ? $this->metadata['homepage'] : '',
- 'META_VERSION' => (isset($this->metadata['version'])) ? $this->metadata['version'] : '',
- 'META_TIME' => (isset($this->metadata['time'])) ? $this->metadata['time'] : '',
- 'META_LICENSE' => $this->metadata['license'],
-
- 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? $this->metadata['require']['php'] : '',
- 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(),
-
- 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? $this->metadata['extra']['soft-require']['phpbb/phpbb'] : '',
- 'META_REQUIRE_PHPBB_FAIL' => !$this->validate_require_phpbb(),
-
- 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '',
- ));
-
- foreach ($this->metadata['authors'] as $author)
- {
- $template->assign_block_vars('meta_authors', array(
- 'AUTHOR_NAME' => $author['name'],
- 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '',
- 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '',
- 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '',
- ));
- }
- }
}
diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php
index 92d4213180..00be8fd381 100644
--- a/phpBB/phpbb/request/request.php
+++ b/phpBB/phpbb/request/request.php
@@ -169,12 +169,6 @@ class request implements \phpbb\request\request_interface
$GLOBALS[$this->super_globals[$super_global]][$var_name] = $value;
}
}
-
- if (!$this->super_globals_disabled())
- {
- unset($GLOBALS[$this->super_globals[$super_global]][$var_name]);
- $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value;
- }
}
/**
diff --git a/phpBB/phpbb/template/base.php b/phpBB/phpbb/template/base.php
index 9a40702ba8..41c0a01ba8 100644
--- a/phpBB/phpbb/template/base.php
+++ b/phpBB/phpbb/template/base.php
@@ -133,6 +133,14 @@ abstract class base implements template
}
/**
+ * {@inheritdoc}
+ */
+ public function find_key_index($blockname, $key)
+ {
+ return $this->context->find_key_index($blockname, $key);
+ }
+
+ /**
* Calls hook if any is defined.
*
* @param string $handle Template handle being displayed.
diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php
index 8bf6c10e2d..5e4f71a2a9 100644
--- a/phpBB/phpbb/template/context.php
+++ b/phpBB/phpbb/template/context.php
@@ -264,6 +264,89 @@ class context
}
/**
+ * Find the index for a specified key in the innermost specified block
+ *
+ * @param string $blockname the blockname, for example 'loop'
+ * @param mixed $key Key to search for
+ *
+ * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
+ *
+ * int: Position [the position to search for]
+ *
+ * If key is false the position is set to 0
+ * If key is true the position is set to the last entry
+ *
+ * @return mixed false if not found, index position otherwise; be sure to test with ===
+ */
+ public function find_key_index($blockname, $key)
+ {
+ // For nested block, $blockcount > 0, for top-level block, $blockcount == 0
+ $blocks = explode('.', $blockname);
+ $blockcount = sizeof($blocks) - 1;
+
+ $block = $this->tpldata;
+ for ($i = 0; $i < $blockcount; $i++)
+ {
+ if (($pos = strpos($blocks[$i], '[')) !== false)
+ {
+ $name = substr($blocks[$i], 0, $pos);
+
+ if (strpos($blocks[$i], '[]') === $pos)
+ {
+ $index = sizeof($block[$name]) - 1;
+ }
+ else
+ {
+ $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1);
+ }
+ }
+ else
+ {
+ $name = $blocks[$i];
+ $index = sizeof($block[$name]) - 1;
+ }
+ if (!isset($block[$name]))
+ {
+ return false;
+ }
+ $block = $block[$name];
+ if (!isset($block[$index]))
+ {
+ return false;
+ }
+ $block = $block[$index];
+ }
+
+ if (!isset($block[$blocks[$i]]))
+ {
+ return false;
+ }
+ $block = $block[$blocks[$i]]; // Traverse the last block
+
+ // Change key to zero (change first position) if false and to last position if true
+ if ($key === false || $key === true)
+ {
+ return ($key === false) ? 0 : sizeof($block) - 1;
+ }
+
+ // Get correct position if array given
+ if (is_array($key))
+ {
+ // Search array to get correct position
+ list($search_key, $search_value) = @each($key);
+ foreach ($block as $i => $val_ary)
+ {
+ if ($val_ary[$search_key] === $search_value)
+ {
+ return $i;
+ }
+ }
+ }
+
+ return (is_int($key) && ((0 <= $key) && ($key < sizeof($block)))) ? $key : false;
+ }
+
+ /**
* Change already assigned key variable pair (one-dimensional - single loop entry)
*
* An example of how to use this function:
@@ -280,10 +363,11 @@ class context
* If key is false the position is set to 0
* If key is true the position is set to the last entry
*
- * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
+ * @param string $mode Mode to execute (valid modes are 'insert', 'change' and 'delete')
*
* If insert, the vararray is inserted at the given position (position counting from zero).
* If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new \value).
+ * If delete, the vararray is ignored, and the block at the given position (counting from zero) is removed.
*
* Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
* and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
@@ -293,45 +377,49 @@ class context
public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert')
{
$this->num_rows_is_set = false;
- if (strpos($blockname, '.') !== false)
- {
- // Nested block.
- $blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
- $block = &$this->tpldata;
- for ($i = 0; $i < $blockcount; $i++)
+ // For nested block, $blockcount > 0, for top-level block, $blockcount == 0
+ $blocks = explode('.', $blockname);
+ $blockcount = sizeof($blocks) - 1;
+
+ $block = &$this->tpldata;
+ for ($i = 0; $i < $blockcount; $i++)
+ {
+ if (($pos = strpos($blocks[$i], '[')) !== false)
{
- if (($pos = strpos($blocks[$i], '[')) !== false)
+ $name = substr($blocks[$i], 0, $pos);
+
+ if (strpos($blocks[$i], '[]') === $pos)
{
- $name = substr($blocks[$i], 0, $pos);
-
- if (strpos($blocks[$i], '[]') === $pos)
- {
- $index = sizeof($block[$name]) - 1;
- }
- else
- {
- $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1);
- }
+ $index = sizeof($block[$name]) - 1;
}
else
{
- $name = $blocks[$i];
- $index = sizeof($block[$name]) - 1;
+ $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1);
}
- $block = &$block[$name];
- $block = &$block[$index];
}
-
- $block = &$block[$blocks[$i]]; // Traverse the last block
+ else
+ {
+ $name = $blocks[$i];
+ $index = sizeof($block[$name]) - 1;
+ }
+ $block = &$block[$name];
+ $block = &$block[$index];
}
- else
+ $name = $blocks[$i];
+
+ // If last block does not exist and we are inserting, and not searching for key, we create it empty; otherwise, nothing to do
+ if (!isset($block[$name]))
{
- // Top-level block.
- $block = &$this->tpldata[$blockname];
+ if ($mode != 'insert' || is_array($key))
+ {
+ return false;
+ }
+ $block[$name] = array();
}
+ $block = &$block[$name]; // Now we can traverse the last block
+
// Change key to zero (change first position) if false and to last position if true
if ($key === false || $key === true)
{
@@ -371,14 +459,15 @@ class context
unset($block[($key - 1)]['S_LAST_ROW']);
$vararray['S_LAST_ROW'] = true;
}
- else if ($key === 0)
+ if ($key <= 0)
{
+ $key = 0;
unset($block[0]['S_FIRST_ROW']);
$vararray['S_FIRST_ROW'] = true;
}
// Assign S_BLOCK_NAME
- $vararray['S_BLOCK_NAME'] = $blockname;
+ $vararray['S_BLOCK_NAME'] = $name;
// Re-position template blocks
for ($i = sizeof($block); $i > $key; $i--)
@@ -398,6 +487,12 @@ class context
// Which block to change?
if ($mode == 'change')
{
+ // If key is out of bounds, do not change anything
+ if ($key > sizeof($block) || $key < 0)
+ {
+ return false;
+ }
+
if ($key == sizeof($block))
{
$key--;
@@ -408,6 +503,45 @@ class context
return true;
}
+ // Delete Block
+ if ($mode == 'delete')
+ {
+ // If we are exceeding last iteration, do not delete anything
+ if ($key > sizeof($block) || $key < 0)
+ {
+ return false;
+ }
+
+ // If we are positioned at the end, we remove the last element
+ if ($key == sizeof($block))
+ {
+ $key--;
+ }
+
+ // We are deleting the last element in the block, so remove the block
+ if (sizeof($block) === 1)
+ {
+ $block = null; // unset($block); does not work on references
+ return true;
+ }
+
+ // Re-position template blocks
+ for ($i = $key; $i < sizeof($block)-1; $i++)
+ {
+ $block[$i] = $block[$i+1];
+ $block[$i]['S_ROW_COUNT'] = $block[$i]['S_ROW_NUM'] = $i;
+ }
+
+ // Remove the last element
+ unset($block[$i]);
+
+ // Set first and last elements again, in case they were removed
+ $block[0]['S_FIRST_ROW'] = true;
+ $block[sizeof($block)-1]['S_LAST_ROW'] = true;
+
+ return true;
+ }
+
return false;
}
diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php
index 041ecb12e4..d1ec442e9a 100644
--- a/phpBB/phpbb/template/template.php
+++ b/phpBB/phpbb/template/template.php
@@ -160,10 +160,11 @@ interface template
* If key is false the position is set to 0
* If key is true the position is set to the last entry
*
- * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
+ * @param string $mode Mode to execute (valid modes are 'insert', 'change' and 'delete')
*
* If insert, the vararray is inserted at the given position (position counting from zero).
* If change, the current block gets merged with the vararray (resulting in new \key/value pairs be added and existing keys be replaced by the new \value).
+ * If delete, the vararray is ignored, and the block at the given position (counting from zero) is removed.
*
* Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
* and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
@@ -173,6 +174,23 @@ interface template
public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert');
/**
+ * Find the index for a specified key in the innermost specified block
+ *
+ * @param string $blockname the blockname, for example 'loop'
+ * @param mixed $key Key to search for
+ *
+ * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
+ *
+ * int: Position [the position to search for]
+ *
+ * If key is false the position is set to 0
+ * If key is true the position is set to the last entry
+ *
+ * @return mixed false if not found, index position otherwise; be sure to test with ===
+ */
+ public function find_key_index($blockname, $key);
+
+ /**
* Get path to template for handle (required for BBCode parser)
*
* @param string $handle Handle to retrieve the source file
diff --git a/phpBB/phpbb/template/twig/environment.php b/phpBB/phpbb/template/twig/environment.php
index 179412a2e3..ac4b16e457 100644
--- a/phpBB/phpbb/template/twig/environment.php
+++ b/phpBB/phpbb/template/twig/environment.php
@@ -32,6 +32,9 @@ class environment extends \Twig_Environment
/** @var \phpbb\extension\manager */
protected $extension_manager;
+ /** @var \phpbb\event\dispatcher_interface */
+ protected $phpbb_dispatcher;
+
/** @var string */
protected $phpbb_root_path;
@@ -53,15 +56,17 @@ class environment extends \Twig_Environment
* @param string $cache_path The path to the cache directory
* @param \phpbb\extension\manager $extension_manager phpBB extension manager
* @param \Twig_LoaderInterface $loader Twig loader interface
+ * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object
* @param array $options Array of options to pass to Twig
*/
- public function __construct(\phpbb\config\config $phpbb_config, \phpbb\filesystem\filesystem $filesystem, \phpbb\path_helper $path_helper, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, $options = array())
+ public function __construct(\phpbb\config\config $phpbb_config, \phpbb\filesystem\filesystem $filesystem, \phpbb\path_helper $path_helper, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, \phpbb\event\dispatcher_interface $phpbb_dispatcher = null, $options = array())
{
$this->phpbb_config = $phpbb_config;
$this->filesystem = $filesystem;
$this->phpbb_path_helper = $path_helper;
$this->extension_manager = $extension_manager;
+ $this->phpbb_dispatcher = $phpbb_dispatcher;
$this->phpbb_root_path = $this->phpbb_path_helper->get_phpbb_root_path();
$this->web_root_path = $this->phpbb_path_helper->get_web_root_path();
@@ -202,8 +207,37 @@ class environment extends \Twig_Environment
$context['definition']->set('STYLESHEETS', '__STYLESHEETS_' . $placeholder_salt . '__');
}
+ /**
+ * Allow changing the template output stream before rendering
+ *
+ * @event core.twig_environment_render_template_before
+ * @var array context Array with template variables
+ * @var string name The template name
+ * @since 3.2.1-RC1
+ */
+ if ($this->phpbb_dispatcher)
+ {
+ $vars = array('context', 'name');
+ extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_before', compact($vars)));
+ }
+
$output = parent::render($name, $context);
+ /**
+ * Allow changing the template output stream after rendering
+ *
+ * @event core.twig_environment_render_template_after
+ * @var array context Array with template variables
+ * @var string name The template name
+ * @var string output Rendered template output stream
+ * @since 3.2.1-RC1
+ */
+ if ($this->phpbb_dispatcher)
+ {
+ $vars = array('context', 'name', 'output');
+ extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_after', compact($vars)));
+ }
+
return $this->inject_assets($output, $placeholder_salt);
}
diff --git a/phpBB/phpbb/textformatter/s9e/quote_helper.php b/phpBB/phpbb/textformatter/s9e/quote_helper.php
index 24109ac8cc..86c33c7591 100644
--- a/phpBB/phpbb/textformatter/s9e/quote_helper.php
+++ b/phpBB/phpbb/textformatter/s9e/quote_helper.php
@@ -39,8 +39,8 @@ class quote_helper
*/
public function __construct(\phpbb\user $user, $root_path, $php_ext)
{
- $this->post_url = append_sid($root_path . 'viewtopic.' . $php_ext, 'p={POST_ID}#p{POST_ID}');
- $this->profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}');
+ $this->post_url = append_sid($root_path . 'viewtopic.' . $php_ext, 'p={POST_ID}#p{POST_ID}', false);
+ $this->profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}', false);
$this->user = $user;
}
diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php
index f80d2b16fc..bb15dd1a74 100644
--- a/phpBB/phpbb/version_helper.php
+++ b/phpBB/phpbb/version_helper.php
@@ -181,7 +181,7 @@ class version_helper
$self = $this;
$current_version = $this->current_version;
- // Filter out any versions less than to the current version
+ // Filter out any versions less than the current version
$versions = array_filter($versions, function($data) use ($self, $current_version) {
return $self->compare($data['current'], $current_version, '>=');
});
@@ -215,7 +215,7 @@ class version_helper
$self = $this;
$current_version = $this->current_version;
- // Filter out any versions less than to the current version
+ // Filter out any versions less than the current version
$versions = array_filter($versions, function($data) use ($self, $current_version) {
return $self->compare($data['current'], $current_version, '>=');
});
@@ -241,11 +241,74 @@ class version_helper
}
/**
+ * Gets the latest extension update for the current phpBB branch the user is on
+ * Will suggest versions from newer branches when EoL has been reached
+ * and/or version from newer branch is needed for having all known security
+ * issues fixed.
+ *
+ * @param bool $force_update Ignores cached data. Defaults to false.
+ * @param bool $force_cache Force the use of the cache. Override $force_update.
+ * @return array Version info or empty array if there are no updates
+ * @throws \RuntimeException
+ */
+ public function get_ext_update_on_branch($force_update = false, $force_cache = false)
+ {
+ $versions = $this->get_versions_matching_stability($force_update, $force_cache);
+
+ $self = $this;
+ $current_version = $this->current_version;
+
+ // Get current phpBB branch from version, e.g.: 3.2
+ preg_match('/^(\d+\.\d+).*$/', $this->config['version'], $matches);
+ $current_branch = $matches[1];
+
+ // Filter out any versions less than the current version
+ $versions = array_filter($versions, function($data) use ($self, $current_version) {
+ return $self->compare($data['current'], $current_version, '>=');
+ });
+
+ // Filter out any phpbb branches less than the current version
+ $branches = array_filter(array_keys($versions), function($branch) use ($self, $current_branch) {
+ return $self->compare($branch, $current_branch, '>=');
+ });
+ if (!empty($branches))
+ {
+ $versions = array_intersect_key($versions, array_flip($branches));
+ }
+ else
+ {
+ // If branches are empty, it means the current phpBB branch is newer than any branch the
+ // extension was validated against. Reverse sort the versions array so we get the newest
+ // validated release available.
+ krsort($versions);
+ }
+
+ // Get the first available version from the previous list.
+ $update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) {
+ if ($value === null && $self->compare($data['current'], $current_version, '>='))
+ {
+ if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<=')))
+ {
+ return $self->compare($data['current'], $current_version, '>') ? $data : array();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ return $value;
+ });
+
+ return $update_info === null ? array() : $update_info;
+ }
+
+ /**
* Obtains the latest version information
*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
- * @return string
+ * @return array
* @throws version_check_exception
*/
public function get_suggested_updates($force_update = false, $force_cache = false)
@@ -266,7 +329,7 @@ class version_helper
*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
- * @return string Version info
+ * @return array Version info
* @throws version_check_exception
*/
public function get_versions_matching_stability($force_update = false, $force_cache = false)
@@ -286,7 +349,7 @@ class version_helper
*
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
- * @return string Version info, includes stable and unstable data
+ * @return array Version info, includes stable and unstable data
* @throws version_check_exception
*/
public function get_versions($force_update = false, $force_cache = false)