diff options
Diffstat (limited to 'phpBB/phpbb/extension/metadata_manager.php')
| -rw-r--r-- | phpBB/phpbb/extension/metadata_manager.php | 388 | 
1 files changed, 388 insertions, 0 deletions
diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php new file mode 100644 index 0000000000..014d8c79c7 --- /dev/null +++ b/phpBB/phpbb/extension/metadata_manager.php @@ -0,0 +1,388 @@ +<?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\extension; + +/** +* The extension metadata manager validates and gets meta-data for extensions +*/ +class metadata_manager +{ +	/** +	* phpBB Config instance +	* @var \phpbb\config\config +	*/ +	protected $config; + +	/** +	* phpBB Extension Manager +	* @var \phpbb\extension\manager +	*/ +	protected $extension_manager; + +	/** +	* phpBB Template instance +	* @var \phpbb\template\template +	*/ +	protected $template; + +	/** +	* phpBB User instance +	* @var \phpbb\user +	*/ +	protected $user; + +	/** +	* phpBB root path +	* @var string +	*/ +	protected $phpbb_root_path; + +	/** +	* Name (including vendor) of the extension +	* @var string +	*/ +	protected $ext_name; + +	/** +	* Metadata from the composer.json file +	* @var array +	*/ +	protected $metadata; + +	/** +	* Link (including root path) to the metadata file +	* @var string +	*/ +	protected $metadata_file; + +	/** +	* 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\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) +	{ +		$this->config = $config; +		$this->extension_manager = $extension_manager; +		$this->template = $template; +		$this->user = $user; +		$this->phpbb_root_path = $phpbb_root_path; + +		$this->ext_name = $ext_name; +		$this->metadata = array(); +		$this->metadata_file = ''; +	} + +	/** +	* Processes and gets the metadata requested +	* +	* @param  string $element			All for all metadata that it has and is valid, otherwise specify which section you want by its shorthand term. +	* @return array					Contains all of the requested metadata, throws an exception on failure +	*/ +	public function get_metadata($element = 'all') +	{ +		$this->set_metadata_file(); + +		// Fetch the metadata +		$this->fetch_metadata(); + +		// Clean the metadata +		$this->clean_metadata_array(); + +		switch ($element) +		{ +			case 'all': +			default: +				// Validate the metadata +				if (!$this->validate()) +				{ +					return false; +				} + +				return $this->metadata; +			break; + +			case 'name': +				return ($this->validate('name')) ? $this->metadata['name'] : false; +			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; +				} +			break; +		} +	} + +	/** +	* Sets the filepath of the metadata file +	* +	* @throws \phpbb\extension\exception +	*/ +	private function set_metadata_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($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)) +		{ +			throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $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)); +			} + +			$this->metadata = $metadata; + +			return true; +		} +	} + +	/** +	* 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 +	* 						"display" for name, type, and authors +	* 						"name", "type") +	* @return Bool True if valid, throws an exception if invalid +	* @throws \phpbb\extension\exception +	*/ +	public function validate($name = 'display') +	{ +		// Basic fields +		$fields = array( +			'name'		=> '#^[a-zA-Z0-9_\x7f-\xff]{2,}/[a-zA-Z0-9_\x7f-\xff]{2,}$#', +			'type'		=> '#^phpbb-extension$#', +			'license'	=> '#.+#', +			'version'	=> '#.+#', +		); + +		switch ($name) +		{ +			case 'all': +				$this->validate('display'); + +				$this->validate_enable(); +			break; + +			case 'display': +				foreach ($fields as $field => $data) +				{ +					$this->validate($field); +				} + +				$this->validate_authors(); +			break; + +			default: +				if (isset($fields[$name])) +				{ +					if (!isset($this->metadata[$name])) +					{ +						throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', $name)); +					} + +					if (!preg_match($fields[$name], $this->metadata[$name])) +					{ +						throw new \phpbb\extension\exception($this->user->lang('META_FIELD_INVALID', $name)); +					} +				} +			break; +		} + +		return true; +	} + +	/** +	* Validates the contents of the authors field +	* +	* @return boolean True when passes validation, throws exception if invalid +	* @throws \phpbb\extension\exception +	*/ +	public function validate_authors() +	{ +		if (empty($this->metadata['authors'])) +		{ +			throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'authors')); +		} + +		foreach ($this->metadata['authors'] as $author) +		{ +			if (!isset($author['name'])) +			{ +				throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'author name')); +			} +		} + +		return true; +	} + +	/** +	* This array handles the verification that this extension can be enabled on this board +	* +	* @return bool True if validation succeeded, False if failed +	*/ +	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; +	} + +	/** +	* Validates the most basic directory structure to ensure it follows <vendor>/<ext> convention. +	* +	* @return boolean True when passes validation +	*/ +	public function validate_dir() +	{ +		return (substr_count($this->ext_name, '/') === 1 && $this->ext_name == $this->get_metadata('name')); +	} + + +	/** +	* Validates the contents of the phpbb requirement field +	* +	* @return boolean True when passes validation +	*/ +	public function validate_require_phpbb() +	{ +		if (!isset($this->metadata['require']['phpbb/phpbb'])) +		{ +			return false; +		} + +		return true; +	} + +	/** +	* Validates the contents of the php requirement field +	* +	* @return boolean True when passes validation +	*/ +	public function validate_require_php() +	{ +		if (!isset($this->metadata['require']['php'])) +		{ +			return false; +		} + +		return true; +	} + +	/** +	* Version validation helper +	* +	* @param string $string The string for comparing to a version +	* @param string $current_version The version to compare to +	* @return bool True/False if meets version requirements +	*/ +	private function _validate_version($string, $current_version) +	{ +		// Allow them to specify their own comparison operator (ex: <3.1.2, >=3.1.0) +		$comparison_matches = false; +		preg_match('#[=<>]+#', $string, $comparison_matches); + +		if (!empty($comparison_matches)) +		{ +			return version_compare($current_version, str_replace(array($comparison_matches[0], ' '), '', $string), $comparison_matches[0]); +		} + +		return version_compare($current_version, $string, '>='); +	} + +	/** +	* Outputs the metadata into the template +	* +	* @return null +	*/ +	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_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_REQUIRE_PHP'		=> (isset($this->metadata['require']['php'])) ? htmlspecialchars($this->metadata['require']['php']) : '', +			'META_REQUIRE_PHP_FAIL'	=> !$this->validate_require_php(), + +			'META_REQUIRE_PHPBB'		=> (isset($this->metadata['require']['phpbb/phpbb'])) ? htmlspecialchars($this->metadata['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']) : '', +		)); + +		foreach ($this->metadata['authors'] as $author) +		{ +			$this->template->assign_block_vars('meta_authors', array( +				'AUTHOR_NAME'		=> htmlspecialchars($author['name']), +				'AUTHOR_EMAIL'		=> (isset($author['email'])) ? $author['email'] : '', +				'AUTHOR_HOMEPAGE'	=> (isset($author['homepage'])) ? $author['homepage'] : '', +				'AUTHOR_ROLE'		=> (isset($author['role'])) ? htmlspecialchars($author['role']) : '', +			)); +		} +	} +}  | 
