diff options
Diffstat (limited to 'phpBB/includes/extension')
| -rw-r--r-- | phpBB/includes/extension/base.php | 57 | ||||
| -rw-r--r-- | phpBB/includes/extension/controller.php | 77 | ||||
| -rw-r--r-- | phpBB/includes/extension/controller_interface.php | 31 | ||||
| -rw-r--r-- | phpBB/includes/extension/finder.php | 436 | ||||
| -rw-r--r-- | phpBB/includes/extension/interface.php | 65 | ||||
| -rw-r--r-- | phpBB/includes/extension/manager.php | 467 | ||||
| -rw-r--r-- | phpBB/includes/extension/provider.php | 68 | 
7 files changed, 1201 insertions, 0 deletions
| diff --git a/phpBB/includes/extension/base.php b/phpBB/includes/extension/base.php new file mode 100644 index 0000000000..9d076eb6c5 --- /dev/null +++ b/phpBB/includes/extension/base.php @@ -0,0 +1,57 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* A base class for extensions without custom enable/disable/purge code. +* +* @package extension +*/ +class phpbb_extension_base implements phpbb_extension_interface +{ +	/** +	* Single enable step that does nothing +	* +	* @param mixed $old_state State returned by previous call of this method +	* @return false Indicates no further steps are required +	*/ +	public function enable_step($old_state) +	{ +		return false; +	} + +	/** +	* Single disable step that does nothing +	* +	* @param mixed $old_state State returned by previous call of this method +	* @return false Indicates no further steps are required +	*/ +	public function disable_step($old_state) +	{ +		return false; +	} + +	/** +	* Single purge step that does nothing +	* +	* @param mixed $old_state State returned by previous call of this method +	* @return false Indicates no further steps are required +	*/ +	public function purge_step($old_state) +	{ +		return false; +	} +} diff --git a/phpBB/includes/extension/controller.php b/phpBB/includes/extension/controller.php new file mode 100644 index 0000000000..c7fd439a19 --- /dev/null +++ b/phpBB/includes/extension/controller.php @@ -0,0 +1,77 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* Abstract class extended by extension front controller classes +* +* @package extension +*/ +abstract class phpbb_extension_controller implements phpbb_extension_controller_interface +{ +	/** +	* @var phpbb_request Request class object +	*/ +	protected $request; + +	/** +	* @var dbal DBAL class object +	*/ +	protected $db; + +	/** +	* @var user User class object +	*/ +	protected $user; + +	/** +	* @var phpbb_template Template class object +	*/ +	protected $template; + +	/** +	* @var array Config array +	*/ +	protected $config; + +	/** +	* @var string PHP Extension +	*/ +	protected $phpEx; + +	/** +	* @var string Relative path to board root +	*/ +	protected $phpbb_root_path; + +	/** +	* Constructor method that provides the common phpBB objects as inherited class +	* properties for automatic availability in extension controllers +	*/ +	public function __construct() +	{ +		global $request, $db, $user, $template, $config; +		global $phpEx, $phpbb_root_path; + +		$this->request = $request; +		$this->db = $db; +		$this->user = $user; +		$this->template = $template; +		$this->config = $config; +		$this->phpEx = $phpEx; +		$this->phpbb_root_path = $phpbb_root_path; +	} +} diff --git a/phpBB/includes/extension/controller_interface.php b/phpBB/includes/extension/controller_interface.php new file mode 100644 index 0000000000..2b88925388 --- /dev/null +++ b/phpBB/includes/extension/controller_interface.php @@ -0,0 +1,31 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* The interface that extension classes have to implement to run front pages +* +* @package extension +*/ +interface phpbb_extension_controller_interface +{ +	/** +	* Handle the request to display a page from an extension +	* +	* @return	null +	*/ +	public function handle(); +} diff --git a/phpBB/includes/extension/finder.php b/phpBB/includes/extension/finder.php new file mode 100644 index 0000000000..87ca40917d --- /dev/null +++ b/phpBB/includes/extension/finder.php @@ -0,0 +1,436 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* The extension finder provides a simple way to locate files in active extensions +* +* @package extension +*/ +class phpbb_extension_finder +{ +	protected $extension_manager; +	protected $phpbb_root_path; +	protected $cache; +	protected $phpEx; + +	/** +	* The cache variable name used to store $this->cached_queries in $this->cache. +	* +	* Allows the use of multiple differently configured finders with the same cache. +	* @var string +	*/ +	protected $cache_name; + +	/** +	* An associative array, containing all search parameters set in methods. +	* @var	array +	*/ +	protected $query; + +	/** +	* A map from md5 hashes of serialized queries to their previously retrieved +	* results. +	* @var	array +	*/ +	protected $cached_queries; + +	/** +	* Creates a new finder instance with its dependencies +	* +	* @param phpbb_extension_manager $extension_manager An extension manager +	*            instance that provides the finder with a list of active +	*            extensions and their locations +	* @param string $phpbb_root_path Path to the phpbb root directory +	* @param phpbb_cache_driver_interface $cache A cache instance or null +	* @param string $phpEx php file extension +	* @param string $cache_name The name of the cache variable, defaults to +	*                           _ext_finder +	*/ +	public function __construct(phpbb_extension_manager $extension_manager, $phpbb_root_path = '', phpbb_cache_driver_interface $cache = null, $phpEx = '.php', $cache_name = '_ext_finder') +	{ +		$this->extension_manager = $extension_manager; +		$this->phpbb_root_path = $phpbb_root_path; +		$this->cache = $cache; +		$this->phpEx = $phpEx; +		$this->cache_name = $cache_name; + +		$this->query = array( +			'core_path' => false, +			'core_suffix' => false, +			'core_prefix' => false, +			'core_directory' => false, +			'extension_suffix' => false, +			'extension_prefix' => false, +			'extension_directory' => false, +		); + +		$this->cached_queries = ($this->cache) ? $this->cache->get($this->cache_name) : false; +	} + +	/** +	* Sets a core path to be searched in addition to extensions +	* +	* @param string $core_path The path relative to phpbb_root_path +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function core_path($core_path) +	{ +		$this->query['core_path'] = $core_path; +		return $this; +	} + +	/** +	* Sets the suffix all files found in extensions and core must match. +	* +	* There is no default file extension, so to find PHP files only, you will +	* have to specify .php as a suffix. However when using get_classes, the .php +	* file extension is automatically added to suffixes. +	* +	* @param string $suffix A filename suffix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function suffix($suffix) +	{ +		$this->core_suffix($suffix); +		$this->extension_suffix($suffix); +		return $this; +	} + +	/** +	* Sets a suffix all files found in extensions must match +	* +	* There is no default file extension, so to find PHP files only, you will +	* have to specify .php as a suffix. However when using get_classes, the .php +	* file extension is automatically added to suffixes. +	* +	* @param string $extension_suffix A filename suffix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function extension_suffix($extension_suffix) +	{ +		$this->query['extension_suffix'] = $extension_suffix; +		return $this; +	} + +	/** +	* Sets a suffix all files found in the core path must match +	* +	* There is no default file extension, so to find PHP files only, you will +	* have to specify .php as a suffix. However when using get_classes, the .php +	* file extension is automatically added to suffixes. +	* +	* @param string $core_suffix A filename suffix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function core_suffix($core_suffix) +	{ +		$this->query['core_suffix'] = $core_suffix; +		return $this; +	} + +	/** +	* Sets the prefix all files found in extensions and core must match +	* +	* @param string $prefix A filename prefix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function prefix($prefix) +	{ +		$this->core_prefix($prefix); +		$this->extension_prefix($prefix); +		return $this; +	} + +	/** +	* Sets a prefix all files found in extensions must match +	* +	* @param string $extension_prefix A filename prefix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function extension_prefix($extension_prefix) +	{ +		$this->query['extension_prefix'] = $extension_prefix; +		return $this; +	} + +	/** +	* Sets a prefix all files found in the core path must match +	* +	* @param string $core_prefix A filename prefix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function core_prefix($core_prefix) +	{ +		$this->query['core_prefix'] = $core_prefix; +		return $this; +	} + +	/** +	* Sets a directory all files found in extensions and core must be contained in +	* +	* Automatically sets the core_directory if its value does not differ from +	* the current directory. +	* +	* @param string $directory +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function directory($directory) +	{ +		$this->core_directory($directory); +		$this->extension_directory($directory); +		return $this; +	} + +	/** +	* Sets a directory all files found in extensions must be contained in +	* +	* @param string $extension_directory +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function extension_directory($extension_directory) +	{ +		$this->query['extension_directory'] = $this->sanitise_directory($extension_directory); +		return $this; +	} + +	/** +	* Sets a directory all files found in the core path must be contained in +	* +	* @param string $core_directory +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function core_directory($core_directory) +	{ +		$this->query['core_directory'] = $this->sanitise_directory($core_directory); +		return $this; +	} + +	/** +	* Removes occurances of /./ and makes sure path ends without trailing slash +	* +	* @param string $directory A directory pattern +	* @return string A cleaned up directory pattern +	*/ +	protected function sanitise_directory($directory) +	{ +		$directory = preg_replace('#(?:^|/)\./#', '/', $directory); +		$dir_len = strlen($directory); + +		if ($dir_len > 1 && $directory[$dir_len - 1] === '/') +		{ +			$directory = substr($directory, 0, -1); +		} + +		return $directory; +	} + +	/** +	* Finds classes matching the configured options if they follow phpBB naming rules. +	* +	* The php file extension is automatically added to suffixes. +	* +	* Note: If a file is matched but contains a class name not following the +	* phpBB naming rules an incorrect class name will be returned. +	* +	* @param bool $cache Whether the result should be cached +	* @return array An array of found class names +	*/ +	public function get_classes($cache = true) +	{ +		$this->query['extension_suffix'] .= $this->phpEx; +		$this->query['core_suffix'] .= $this->phpEx; + +		$files = $this->find($cache, false); + +		$classes = array(); +		foreach ($files as $file => $ext_name) +		{ +			$file = preg_replace('#^includes/#', '', $file); + +			$classes[] = 'phpbb_' . str_replace('/', '_', substr($file, 0, -strlen($this->phpEx))); +		} +		return $classes; +	} + +	/** +	* Finds all directories matching the configured options +	* +	* @param bool $cache Whether the result should be cached +	* @param bool $extension_keys Whether the result should have extension name as array key +	* @return array An array of paths to found directories +	*/ +	public function get_directories($cache = true, $extension_keys = false) +	{ +		return $this->find_with_root_path($cache, true, $extension_keys); +	} + +	/** +	* Finds all files matching the configured options. +	* +	* @param bool $cache Whether the result should be cached +	* @return array An array of paths to found files +	*/ +	public function get_files($cache = true) +	{ +		return $this->find_with_root_path($cache, false); +	} + +	/** +	* A wrapper around the general find which prepends a root path to results +	* +	* @param bool $cache Whether the result should be cached +	* @param bool $is_dir Directories will be returned when true, only files +	*                     otherwise +	* @param bool $extension_keys If true, result will be associative array +	*					with extension name as key +	* @return array An array of paths to found items +	*/ +	protected function find_with_root_path($cache = true, $is_dir = false, $extension_keys = false) +	{ +		$items = $this->find($cache, $is_dir); + +		$result = array(); +		foreach ($items as $item => $ext_name) +		{ +			if ($extension_keys) +			{ +				$result[$ext_name] = $this->phpbb_root_path . $item; +			} +			else +			{ +				$result[] = $this->phpbb_root_path . $item; +			} +		} + +		return $result; +	} + +	/** +	* Finds all file system entries matching the configured options +	* +	* @param bool $cache Whether the result should be cached +	* @param bool $is_dir Directories will be returned when true, only files +	*                     otherwise +	* @return array An array of paths to found items +	*/ +	public function find($cache = true, $is_dir = false) +	{ +		$this->query['is_dir'] = $is_dir; +		$query = md5(serialize($this->query)); + +		if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query])) +		{ +			return $this->cached_queries[$query]; +		} + +		$files = array(); + +		$extensions = $this->extension_manager->all_enabled(); + +		if ($this->query['core_path']) +		{ +			$extensions['/'] = $this->phpbb_root_path . $this->query['core_path']; +		} + +		foreach ($extensions as $name => $path) +		{ +			$ext_name = $name; + +			if (!file_exists($path)) +			{ +				continue; +			} + +			if ($name === '/') +			{ +				$location = $this->query['core_path']; +				$name = ''; +				$suffix = $this->query['core_suffix']; +				$prefix = $this->query['core_prefix']; +				$directory = $this->query['core_directory']; +			} +			else +			{ +				$location = 'ext/'; +				$name .= '/'; +				$suffix = $this->query['extension_suffix']; +				$prefix = $this->query['extension_prefix']; +				$directory = $this->query['extension_directory']; +			} + +			// match only first directory if leading slash is given +			if ($directory === '/') +			{ +				$directory_pattern = '^' . preg_quote(DIRECTORY_SEPARATOR, '#'); +			} +			else if ($directory && $directory[0] === '/') +			{ +				$directory_pattern = '^' . preg_quote(str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); +			} +			else +			{ +				$directory_pattern = preg_quote(DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); +			} +			if ($is_dir) +			{ +				$directory_pattern .= '$'; +			} +			$directory_pattern = '#' . $directory_pattern . '#'; + +			$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST); +			foreach ($iterator as $file_info) +			{ +				$filename = $file_info->getFilename(); +				if ($filename == '.' || $filename == '..') +				{ +					continue; +				} + +				if ($file_info->isDir() == $is_dir) +				{ +					if ($is_dir) +					{ +						$relative_path = $iterator->getInnerIterator()->getSubPath() . DIRECTORY_SEPARATOR . basename($filename) . DIRECTORY_SEPARATOR; +						if ($relative_path[0] !== DIRECTORY_SEPARATOR) +						{ +							$relative_path = DIRECTORY_SEPARATOR . $relative_path; +						} +					} +					else +					{ +						$relative_path = DIRECTORY_SEPARATOR . $iterator->getInnerIterator()->getSubPathname(); +					} + +					if ((!$suffix || substr($relative_path, -strlen($suffix)) === $suffix) && +						(!$prefix || substr($filename, 0, strlen($prefix)) === $prefix) && +						(!$directory || preg_match($directory_pattern, $relative_path))) +					{ +						$files[str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1))] = $ext_name; +					} +				} +			} +		} + +		if ($cache && $this->cache) +		{ +			$this->cached_queries[$query] = $files; +			$this->cache->put($this->cache_name, $this->cached_queries); +		} + +		return $files; +	} +} diff --git a/phpBB/includes/extension/interface.php b/phpBB/includes/extension/interface.php new file mode 100644 index 0000000000..74ecb9b762 --- /dev/null +++ b/phpBB/includes/extension/interface.php @@ -0,0 +1,65 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* The interface extension meta classes have to implement to run custom code +* on enable/disable/purge. +* +* @package extension +*/ +interface phpbb_extension_interface +{ +	/** +	* enable_step is executed on enabling an extension until it returns false. +	* +	* Calls to this function can be made in subsequent requests, when the +	* function is invoked through a webserver with a too low max_execution_time. +	* +	* @param	mixed	$old_state	The return value of the previous call +	*								of this method, or false on the first call +	* @return	mixed				Returns false after last step, otherwise +	*								temporary state which is passed as an +	*								argument to the next step +	*/ +	public function enable_step($old_state); + +	/** +	* Disables the extension. +	* +	* Calls to this function can be made in subsequent requests, when the +	* function is invoked through a webserver with a too low max_execution_time. +	* +	* @param	mixed	$old_state	The return value of the previous call +	*								of this method, or false on the first call +	* @return null +	*/ +	public function disable_step($old_state); + +	/** +	* purge_step is executed on purging an extension until it returns false. +	* +	* Calls to this function can be made in subsequent requests, when the +	* function is invoked through a webserver with a too low max_execution_time. +	* +	* @param	mixed	$old_state	The return value of the previous call +	*								of this method, or false on the first call +	* @return	mixed				Returns false after last step, otherwise +	*								temporary state which is passed as an +	*								argument to the next step +	*/ +	public function purge_step($old_state); +} diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php new file mode 100644 index 0000000000..537c19aff8 --- /dev/null +++ b/phpBB/includes/extension/manager.php @@ -0,0 +1,467 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* The extension manager provides means to activate/deactivate extensions. +* +* @package extension +*/ +class phpbb_extension_manager +{ +	protected $cache; +	protected $phpEx; +	protected $extensions; +	protected $extension_table; +	protected $phpbb_root_path; +	protected $cache_name; + +	/** +	* Creates a manager and loads information from database +	* +	* @param dbal $db A database connection +	* @param string $extension_table The name of the table holding extensions +	* @param string $phpbb_root_path Path to the phpbb includes directory. +	* @param string $phpEx php file extension +	* @param phpbb_cache_driver_interface $cache A cache instance or null +	* @param string $cache_name The name of the cache variable, defaults to _ext +	*/ +	public function __construct(dbal $db, $extension_table, $phpbb_root_path, $phpEx = '.php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext') +	{ +		$this->phpbb_root_path = $phpbb_root_path; +		$this->db = $db; +		$this->cache = $cache; +		$this->phpEx = $phpEx; +		$this->extension_table = $extension_table; +		$this->cache_name = $cache_name; + +		$this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false; + +		if ($this->extensions === false) +		{ +			$this->load_extensions(); +		} +	} + +	/** +	* Loads all extension information from the database +	* +	* @return null +	*/ +	public function load_extensions() +	{ +		$sql = 'SELECT * +			FROM ' . $this->extension_table; + +		$result = $this->db->sql_query($sql); +		$extensions = $this->db->sql_fetchrowset($result); +		$this->db->sql_freeresult($result); + +		$this->extensions = array(); +		foreach ($extensions as $extension) +		{ +			$extension['ext_path'] = $this->get_extension_path($extension['ext_name']); +			$this->extensions[$extension['ext_name']] = $extension; +		} + +		ksort($this->extensions); + +		if ($this->cache) +		{ +			$this->cache->put($this->cache_name, $this->extensions); +		} +	} + +	/** +	* Generates the path to an extension +	* +	* @param string $name The name of the extension +	* @param bool $phpbb_relative Whether the path should be relative to phpbb root +	* @return string Path to an extension +	*/ +	public function get_extension_path($name, $phpbb_relative = false) +	{ +		$name = str_replace('.', '', $name); + +		return (($phpbb_relative) ? $this->phpbb_root_path : '') . 'ext/' . $name . '/'; +	} + +	/** +	* Instantiates the extension meta class for the extension with the given name +	* +	* @param string $name The extension name +	* @return phpbb_extension_interface Instance of the extension meta class or +	*                     phpbb_extension_base if the class does not exist +	*/ +	public function get_extension($name) +	{ +		$extension_class_name = 'phpbb_ext_' . str_replace('/', '_', $name) . '_ext'; + +		if (class_exists($extension_class_name)) +		{ +			return new $extension_class_name; +		} +		else +		{ +			return new phpbb_extension_base; +		} +	} + +	/** +	* Runs a step of the extension enabling process. +	* +	* Allows the exentension to enable in a long running script that works +	* in multiple steps across requests. State is kept for the extension +	* in the extensions table. +	* +	* @param	string	$name	The extension's name +	* @return	bool			False if enabling is finished, true otherwise +	*/ +	public function enable_step($name) +	{ +		// ignore extensions that are already enabled +		if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active']) +		{ +			return false; +		} + +		$old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false; + +		$extension = $this->get_extension($name); +		$state = $extension->enable_step($old_state); + +		$active = ($state === false); + +		$extension_data = array( +			'ext_name'		=> $name, +			'ext_active'	=> $active, +			'ext_state'		=> serialize($state), +		); + +		$this->extensions[$name] = $extension_data; +		$this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']); +		ksort($this->extensions); + +		$sql = 'UPDATE ' . $this->extension_table . ' +			SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " +			WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; +		$this->db->sql_query($sql); + +		if (!$this->db->sql_affectedrows()) +		{ +			$sql = 'INSERT INTO ' . $this->extension_table . ' +				' . $this->db->sql_build_array('INSERT', $extension_data); +			$this->db->sql_query($sql); +		} + +		if ($this->cache) +		{ +			$this->cache->destroy($this->cache_name); +		} + +		return !$active; +	} + +	/** +	* Enables an extension +	* +	* This method completely enables an extension. But it could be long running +	* so never call this in a script that has a max_execution time. +	* +	* @param string $name The extension's name +	* @return null +	*/ +	public function enable($name) +	{ +		while ($this->enable_step($name)); +	} + +	/** +	* Disables an extension +	* +	* Calls the disable method on the extension's meta class to allow it to +	* process the event. +	* +	* @param string $name The extension's name +	* @return bool False if disabling is finished, true otherwise +	*/ +	public function disable_step($name) +	{ +		// ignore extensions that are already disabled +		if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active']) +		{ +			return false; +		} + +		$old_state = unserialize($this->extensions[$name]['ext_state']); + +		$extension = $this->get_extension($name); +		$state = $extension->disable_step($old_state); + +		// continue until the state is false +		if ($state !== false) +		{ +			$extension_data = array( +				'ext_state'		=> serialize($state), +			); +			$this->extensions[$name]['ext_state'] = serialize($state); + +			$sql = 'UPDATE ' . $this->extension_table . ' +				SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " +				WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; +			$this->db->sql_query($sql); + +			if ($this->cache) +			{ +				$this->cache->destroy($this->cache_name); +			} + +			return true; +		} + +		$extension_data = array( +			'ext_active'	=> false, +			'ext_state'		=> serialize(false), +		); +		$this->extensions[$name]['ext_active'] = false; +		$this->extensions[$name]['ext_state'] = serialize(false); + +		$sql = 'UPDATE ' . $this->extension_table . ' +			SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " +			WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; +		$this->db->sql_query($sql); + +		if ($this->cache) +		{ +			$this->cache->destroy($this->cache_name); +		} + +		return false; +	} + +	/** +	* Disables an extension +	* +	* Disables an extension completely at once. This process could run for a +	* while so never call this in a script that has a max_execution time. +	* +	* @param string $name The extension's name +	* @return null +	*/ +	public function disable($name) +	{ +		while ($this->disable_step($name)); +	} + +	/** +	* Purge an extension +	* +	* Disables the extension first if active, and then calls purge on the +	* extension's meta class to delete the extension's database content. +	* +	* @param string $name The extension's name +	* @return bool False if purging is finished, true otherwise +	*/ +	public function purge_step($name) +	{ +		// ignore extensions that do not exist +		if (!isset($this->extensions[$name])) +		{ +			return false; +		} + +		// disable first if necessary +		if ($this->extensions[$name]['ext_active']) +		{ +			$this->disable($name); +		} + +		$old_state = unserialize($this->extensions[$name]['ext_state']); + +		$extension = $this->get_extension($name); +		$state = $extension->purge_step($old_state); + +		// continue until the state is false +		if ($state !== false) +		{ +			$extension_data = array( +				'ext_state'		=> serialize($state), +			); +			$this->extensions[$name]['ext_state'] = serialize($state); + +			$sql = 'UPDATE ' . $this->extension_table . ' +				SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " +				WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; +			$this->db->sql_query($sql); + +			if ($this->cache) +			{ +				$this->cache->destroy($this->cache_name); +			} + +			return true; +		} + +		unset($this->extensions[$name]); + +		$sql = 'DELETE FROM ' . $this->extension_table . " +			WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; +		$this->db->sql_query($sql); + +		if ($this->cache) +		{ +			$this->cache->destroy($this->cache_name); +		} + +		return false; +	} + +	/** +	* Purge an extension +	* +	* Purges an extension completely at once. This process could run for a while +	* so never call this in a script that has a max_execution time. +	* +	* @param string $name The extension's name +	* @return null +	*/ +	public function purge($name) +	{ +		while ($this->purge_step($name)); +	} + +	/** +	* Retrieves a list of all available extensions on the filesystem +	* +	* @return array An array with extension names as keys and paths to the +	*               extension as values +	*/ +	public function all_available() +	{ +		$available = array(); +		if (!is_dir($this->phpbb_root_path . 'ext/')) +		{ +			return $available; +		} + +		$iterator = new RecursiveIteratorIterator( +			new RecursiveDirectoryIterator($this->phpbb_root_path . 'ext/'), +			RecursiveIteratorIterator::SELF_FIRST); +		foreach ($iterator as $file_info) +		{ +			if ($file_info->isFile() && $file_info->getFilename() == 'ext' . $this->phpEx) +			{ +				$ext_name = $iterator->getInnerIterator()->getSubPath(); + +				$ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name); + +				$available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; +			} +		} +		ksort($available); +		return $available; +	} + +	/** +	* Retrieves all configured extensions. +	* +	* All enabled and disabled extensions are considered configured. A purged +	* extension that is no longer in the database is not configured. +	* +	* @return array An array with extension names as keys and and the +	*               database stored extension information as values +	*/ +	public function all_configured() +	{ +		$configured = array(); +		foreach ($this->extensions as $name => $data) +		{ +			$data['ext_path'] = $this->phpbb_root_path . $data['ext_path']; +			$configured[$name] = $data; +		} +		return $configured; +	} + +	/** +	* Retrieves all enabled extensions. +	* +	* @return array An array with extension names as keys and and the +	*               database stored extension information as values +	*/ +	public function all_enabled() +	{ +		$enabled = array(); +		foreach ($this->extensions as $name => $data) +		{ +			if ($data['ext_active']) +			{ +				$enabled[$name] = $this->phpbb_root_path . $data['ext_path']; +			} +		} +		return $enabled; +	} + +	/** +	* Retrieves all disabled extensions. +	* +	* @return array An array with extension names as keys and and the +	*               database stored extension information as values +	*/ +	public function all_disabled() +	{ +		$disabled = array(); +		foreach ($this->extensions as $name => $data) +		{ +			if (!$data['ext_active']) +			{ +				$disabled[$name] = $this->phpbb_root_path . $data['ext_path']; +			} +		} +		return $disabled; +	} +	 +	/** +	* Check to see if a given extension is available on the filesystem +	* +	* @param string $name Extension name to check NOTE: Can be user input +	* @return bool Depending on whether or not the extension is available +	*/ +	public function available($name) +	{ +		return file_exists($this->get_extension_path($name, true)); +	} + +	/** +	* Check to see if a given extension is enabled +	* +	* @param string $name Extension name to check +	* @return bool Depending on whether or not the extension is enabled +	*/ +	public function enabled($name) +	{ +		return isset($this->extensions[$name]) && $this->extensions[$name]['ext_active']; +	} + +	/** +	* Instantiates a phpbb_extension_finder. +	* +	* @return phpbb_extension_finder An extension finder instance +	*/ +	public function get_finder() +	{ +		return new phpbb_extension_finder($this, $this->phpbb_root_path, $this->cache, $this->phpEx, $this->cache_name . '_finder'); +	} +} diff --git a/phpBB/includes/extension/provider.php b/phpBB/includes/extension/provider.php new file mode 100644 index 0000000000..d0541fa007 --- /dev/null +++ b/phpBB/includes/extension/provider.php @@ -0,0 +1,68 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* Provides a set of items found in extensions +* +* @package extension +*/ +abstract class phpbb_extension_provider implements IteratorAggregate +{ +	/** +	* Array holding all found items +	* @var array|null +	*/ +	protected $items = null; + +	/** +	* An extension manager to search for items in extensions +	* @var phpbb_extension_manager +	*/ +	protected $extension_manager; + +	/** +	* Constructor. Loads all available items. +	* +	* @param phpbb_extension_manager $extension_manager phpBB extension manager +	*/ +	public function __construct(phpbb_extension_manager $extension_manager) +	{ +		$this->extension_manager = $extension_manager; +	} + +	/** +	* Finds template paths using the extension manager. +	* +	* @return array     List of task names +	*/ +	abstract protected function find(); + +	/** +	* Retrieve an iterator over all items +	* +	* @return ArrayIterator An iterator for the array of template paths +	*/ +	public function getIterator() +	{ +		if ($this->items === null) +		{ +			$this->items = $this->find(); +		} + +		return new ArrayIterator($this->items); +	} +} | 
