diff options
Diffstat (limited to 'phpBB/phpbb')
| -rw-r--r-- | phpBB/phpbb/cache/driver/memcached.php | 134 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php | 51 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php | 32 | ||||
| -rw-r--r-- | phpBB/phpbb/extension/manager.php | 32 | ||||
| -rw-r--r-- | phpBB/phpbb/extension/metadata_manager.php | 138 | ||||
| -rw-r--r-- | phpBB/phpbb/profilefields/type/type_date.php | 2 | ||||
| -rw-r--r-- | phpBB/phpbb/request/request.php | 6 | ||||
| -rw-r--r-- | phpBB/phpbb/template/base.php | 8 | ||||
| -rw-r--r-- | phpBB/phpbb/template/context.php | 152 | ||||
| -rw-r--r-- | phpBB/phpbb/template/template.php | 17 | ||||
| -rw-r--r-- | phpBB/phpbb/version_helper.php | 73 | 
11 files changed, 491 insertions, 154 deletions
| 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/db/migration/data/v31x/add_latest_topics_index.php b/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php new file mode 100644 index 0000000000..fa2899e348 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php @@ -0,0 +1,51 @@ +<?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_latest_topics_index extends \phpbb\db\migration\migration +{ +	static public function depends_on() +	{ +		return array( +			'\phpbb\db\migration\data\v31x\v3110', +		); +	} + +	public function update_schema() +	{ +		return array( +			'add_index' => array( +				$this->table_prefix . 'topics' => array( +					'latest_topics'	=> array( +						'forum_id', +						'topic_last_post_time', +						'topic_last_post_id', +						'topic_moved_id', +					), +				), +			), +		); +	} + +	public function revert_schema() +	{ +		return array( +			'drop_keys' => array( +				$this->table_prefix . 'topics' => array( +					'latest_topics', +				), +			), +		); +	} +} 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/extension/manager.php b/phpBB/phpbb/extension/manager.php index 76f0e3558e..e7e5f83c23 100644 --- a/phpBB/phpbb/extension/manager.php +++ b/phpBB/phpbb/extension/manager.php @@ -149,10 +149,10 @@ class manager  	* Instantiates the metadata manager for the extension with the given name  	*  	* @param string $name The extension name -	* @param \phpbb\template\template $template The template manager +	* @param \phpbb\template\template $template The template manager or null  	* @return \phpbb\extension\metadata_manager Instance of the metadata manager  	*/ -	public function create_extension_metadata_manager($name, \phpbb\template\template $template) +	public function create_extension_metadata_manager($name, \phpbb\template\template $template = null)  	{  		return new \phpbb\extension\metadata_manager($name, $this->config, $this, $template, $this->user, $this->phpbb_root_path);  	} @@ -433,25 +433,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->phpbb_root_path . 'ext/' . $ext_name . '/';  				} - -				$available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/';  			}  		}  		ksort($available); @@ -524,7 +510,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; +		}  	}  	/** diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php index 107907609b..a09f07bed2 100644 --- a/phpBB/phpbb/extension/metadata_manager.php +++ b/phpBB/phpbb/extension/metadata_manager.php @@ -66,17 +66,18 @@ class metadata_manager  	*/  	protected $metadata_file; +	// @codingStandardsIgnoreStart  	/**  	* 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 \phpbb\template\template	$template			phpBB Template instance +	* @param \phpbb\template\template	$template			phpBB Template instance or null  	* @param \phpbb\user 		$user 				User instance  	* @param string				$phpbb_root_path	Path to the phpbb includes directory.  	*/ -	public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template, \phpbb\user $user, $phpbb_root_path) +	public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template = null, \phpbb\user $user, $phpbb_root_path)  	{  		$this->config = $config;  		$this->extension_manager = $extension_manager; @@ -88,6 +89,7 @@ class metadata_manager  		$this->metadata = array();  		$this->metadata_file = '';  	} +	// @codingStandardsIgnoreEnd  	/**  	* Processes and gets the metadata requested @@ -97,51 +99,38 @@ 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_file === '') +		{ +			$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 +	* Sets the path of the metadata file, gets its 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'; @@ -152,37 +141,19 @@ class metadata_manager  		{  			throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $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($this->user->lang('FILE_NOT_FOUND', $this->metadata_file)); +			throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file));  		} -		else -		{ -			if (!($file_contents = file_get_contents($this->metadata_file))) -			{ -				throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file)); -			} - -			if (($metadata = json_decode($file_contents, true)) === null) -			{ -				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; +		if (($metadata = json_decode($file_contents, true)) === null) +		{ +			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;  	}  	/** @@ -197,16 +168,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 @@ -228,23 +189,8 @@ class metadata_manager  		switch ($name)  		{  			case 'all': -				$this->validate('display'); - -				if (!$this->validate_dir()) -				{ -					throw new \phpbb\extension\exception($this->user->lang('EXTENSION_DIR_INVALID')); -				} - -				if (!$this->validate_require_phpbb()) -				{ -					throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'soft-require')); -				} - -				if (!$this->validate_require_php()) -				{ -					throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'require php')); -				} -			break; +				$this->validate_enable(); +				// no break  			case 'display':  				foreach ($fields as $field => $data) @@ -301,40 +247,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($this->user->lang('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($this->user->lang('META_FIELD_NOT_SET', 'soft-require'));  		}  		return true; @@ -343,13 +292,14 @@ 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($this->user->lang('META_FIELD_NOT_SET', 'require php'));  		}  		return true; @@ -372,10 +322,10 @@ class metadata_manager  			'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_PHP_FAIL'	=> (isset($this->metadata['require']['php'])) ? false : true,  			'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_REQUIRE_PHPBB_FAIL'	=> (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? false : true,  			'META_DISPLAY_NAME'	=> (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '',  		)); diff --git a/phpBB/phpbb/profilefields/type/type_date.php b/phpBB/phpbb/profilefields/type/type_date.php index 90ac9a6703..63a0c79a3d 100644 --- a/phpBB/phpbb/profilefields/type/type_date.php +++ b/phpBB/phpbb/profilefields/type/type_date.php @@ -264,7 +264,7 @@ class type_date extends type_base  		}  		$profile_row['s_year_options'] = '<option value="0"' . ((!$year) ? ' selected="selected"' : '') . '>--</option>'; -		for ($i = $now['year'] - 100; $i <= $now['year'] + 100; $i++) +		for ($i = 1901; $i <= $now['year'] + 50; $i++)  		{  			$profile_row['s_year_options'] .= '<option value="' . $i . '"' . (($i == $year) ? ' selected="selected"' : '') . ">$i</option>";  		} diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php index 4cac6fbaea..00ff9064cb 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..5d04a09865 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: @@ -293,45 +376,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 +458,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 +486,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--; diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php index 041ecb12e4..9e3d658ca8 100644 --- a/phpBB/phpbb/template/template.php +++ b/phpBB/phpbb/template/template.php @@ -173,6 +173,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/version_helper.php b/phpBB/phpbb/version_helper.php index 135d390584..9dc5a2e7c9 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -184,7 +184,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, '>=');  		}); @@ -218,7 +218,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, '>=');  		}); @@ -244,11 +244,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 \RuntimeException  	*/  	public function get_suggested_updates($force_update = false, $force_cache = false) @@ -269,7 +332,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 \RuntimeException  	*/  	public function get_versions_matching_stability($force_update = false, $force_cache = false) @@ -289,7 +352,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 \RuntimeException  	*/  	public function get_versions($force_update = false, $force_cache = false) | 
