diff options
Diffstat (limited to 'phpBB/includes/functions_module.php')
| -rw-r--r-- | phpBB/includes/functions_module.php | 330 | 
1 files changed, 249 insertions, 81 deletions
| diff --git a/phpBB/includes/functions_module.php b/phpBB/includes/functions_module.php index d0e7c8cfc8..53055752f6 100644 --- a/phpBB/includes/functions_module.php +++ b/phpBB/includes/functions_module.php @@ -2,9 +2,8 @@  /**  *  * @package phpBB3 -* @version $Id$  * @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2  *  */ @@ -129,7 +128,7 @@ class p_master  		foreach ($this->module_cache['modules'] as $key => $row)  		{  			// Not allowed to view module? -			if (!$this->module_auth($row['module_auth'])) +			if (!$this->module_auth_self($row['module_auth']))  			{  				unset($this->module_cache['modules'][$key]);  				continue; @@ -221,13 +220,15 @@ class p_master  			// We need to prefix the functions to not create a naming conflict  			// Function for building 'url_extra' -			$url_func = '_module_' . $row['module_basename'] . '_url'; +			$short_name = $this->get_short_name($row['module_basename']); + +			$url_func = '_module_' . $short_name . '_url';  			// Function for building the language name -			$lang_func = '_module_' . $row['module_basename'] . '_lang'; +			$lang_func = '_module_' . $short_name . '_lang';  			// Custom function for calling parameters on module init (for example assigning template variables) -			$custom_func = '_module_' . $row['module_basename']; +			$custom_func = '_module_' . $short_name;  			$names[$row['module_basename'] . '_' . $row['module_mode']][] = true; @@ -275,6 +276,11 @@ class p_master  	*/  	function loaded($module_basename, $module_mode = false)  	{ +		if (!$this->is_full_class($module_basename)) +		{ +			$module_basename = $this->p_class . '_' . $module_basename; +		} +  		if (empty($this->loaded_cache))  		{  			$this->loaded_cache = array(); @@ -309,11 +315,26 @@ class p_master  	}  	/** -	* Check module authorisation +	* Check module authorisation. +	* +	* This is a non-static version that uses $this->acl_forum_id +	* for the forum id. +	*/ +	function module_auth_self($module_auth) +	{ +		return self::module_auth($module_auth, $this->acl_forum_id); +	} + +	/** +	* Check module authorisation. +	* +	* This is a static version, it must be given $forum_id. +	* See also module_auth_self.  	*/ -	function module_auth($module_auth, $forum_id = false) +	static function module_auth($module_auth, $forum_id)  	{  		global $auth, $config; +		global $request, $phpbb_extension_manager, $phpbb_dispatcher;  		$module_auth = trim($module_auth); @@ -330,6 +351,30 @@ class p_master  			[(),]                                  |  			[^\s(),]+)/x', $module_auth, $match); +		// Valid tokens for auth and their replacements +		$valid_tokens = array( +			'acl_([a-z0-9_]+)(,\$id)?'		=> '(int) $auth->acl_get(\'\\1\'\\2)', +			'\$id'							=> '(int) $forum_id', +			'aclf_([a-z0-9_]+)'				=> '(int) $auth->acl_getf_global(\'\\1\')', +			'cfg_([a-z0-9_]+)'				=> '(int) $config[\'\\1\']', +			'request_([a-zA-Z0-9_]+)'		=> '$request->variable(\'\\1\', false)', +			'ext_([a-zA-Z0-9_/]+)'			=> 'array_key_exists(\'\\1\', $phpbb_extension_manager->all_enabled())', +		); + +		/** +		* Alter tokens for module authorisation check +		* +		* @event core.module_auth +		* @var	array	valid_tokens		Valid tokens and their auth check +		*									replacements +		* @var	string	module_auth			The module_auth of the current +		* 									module +		* @var	int		forum_id			The current forum_id +		* @since 3.1-A3 +		*/ +		$vars = array('valid_tokens', 'module_auth', 'forum_id'); +		extract($phpbb_dispatcher->trigger_event('core.module_auth', compact($vars))); +  		$tokens = $match[0];  		for ($i = 0, $size = sizeof($tokens); $i < $size; $i++)  		{ @@ -345,7 +390,7 @@ class p_master  				break;  				default: -					if (!preg_match('#(?:acl_([a-z0-9_]+)(,\$id)?)|(?:\$id)|(?:aclf_([a-z0-9_]+))|(?:cfg_([a-z0-9_]+))|(?:request_([a-zA-Z0-9_]+))#', $token)) +					if (!preg_match('#(?:' . implode(array_keys($valid_tokens), ')|(?:') . ')#', $token))  					{  						$token = '';  					} @@ -355,13 +400,20 @@ class p_master  		$module_auth = implode(' ', $tokens); -		// Make sure $id seperation is working fine +		// Make sure $id separation is working fine  		$module_auth = str_replace(' , ', ',', $module_auth); -		$forum_id = ($forum_id === false) ? $this->acl_forum_id : $forum_id; +		$module_auth = preg_replace( +			// Array keys with # prepended/appended +			array_map(function($value) { +				return '#' . $value . '#'; +			}, array_keys($valid_tokens)), +			array_values($valid_tokens), +			$module_auth +		);  		$is_auth = false; -		eval('$is_auth = (int) (' . preg_replace(array('#acl_([a-z0-9_]+)(,\$id)?#', '#\$id#', '#aclf_([a-z0-9_]+)#', '#cfg_([a-z0-9_]+)#', '#request_([a-zA-Z0-9_]+)#'), array('(int) $auth->acl_get(\'\\1\'\\2)', '(int) $forum_id', '(int) $auth->acl_getf_global(\'\\1\')', '(int) $config[\'\\1\']', '!empty($_REQUEST[\'\\1\'])'), $module_auth) . ');'); +		eval('$is_auth = (int) (' .	$module_auth . ');');  		return $is_auth;  	} @@ -380,6 +432,11 @@ class p_master  			$id = request_var('icat', '');  		} +		if ($id && !is_numeric($id) && !$this->is_full_class($id)) +		{ +			$id = $this->p_class . '_' . $id; +		} +  		$category = false;  		foreach ($this->module_ary as $row_id => $item_ary)  		{ @@ -388,9 +445,9 @@ class p_master  			// If this is a module and no mode selected, select first mode  			// If no category or module selected, go active for first module in first category  			if ( -				(($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) || +				(($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) ||  				($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat && $item_ary['display']) || -				(($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) || +				(($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) ||  				(!$id && !$mode && !$item_ary['cat'] && $item_ary['display'])  				)  			{ @@ -426,10 +483,12 @@ class p_master  	* Loads currently active module  	*  	* This method loads a given module, passing it the relevant id and mode. +	* +	* @param string $mode mode, as passed through to the module  	*/  	function load_active($mode = false, $module_url = false, $execute_module = true)  	{ -		global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user; +		global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template;  		$module_path = $this->include_path . $this->p_class;  		$icat = request_var('icat', ''); @@ -439,75 +498,110 @@ class p_master  			trigger_error('Module not accessible', E_USER_ERROR);  		} -		if (!class_exists("{$this->p_class}_$this->p_name")) +		// new modules use the full class names, old ones are always called <type>_<name>, e.g. acp_board +		if (!class_exists($this->p_name))  		{ -			if (!file_exists("$module_path/{$this->p_class}_$this->p_name.$phpEx")) +			if (!file_exists("$module_path/{$this->p_name}.$phpEx"))  			{ -				trigger_error("Cannot find module $module_path/{$this->p_class}_$this->p_name.$phpEx", E_USER_ERROR); +				trigger_error("Cannot find module $module_path/{$this->p_name}.$phpEx", E_USER_ERROR);  			} -			include("$module_path/{$this->p_class}_$this->p_name.$phpEx"); +			include("$module_path/{$this->p_name}.$phpEx"); -			if (!class_exists("{$this->p_class}_$this->p_name")) +			if (!class_exists($this->p_name))  			{ -				trigger_error("Module file $module_path/{$this->p_class}_$this->p_name.$phpEx does not contain correct class [{$this->p_class}_$this->p_name]", E_USER_ERROR); +				trigger_error("Module file $module_path/{$this->p_name}.$phpEx does not contain correct class [{$this->p_name}]", E_USER_ERROR);  			} +		} -			if (!empty($mode)) -			{ -				$this->p_mode = $mode; -			} +		if (!empty($mode)) +		{ +			$this->p_mode = $mode; +		} -			// Create a new instance of the desired module ... if it has a -			// constructor it will of course be executed -			$instance = "{$this->p_class}_$this->p_name"; +		// Create a new instance of the desired module ... +		$class_name = $this->p_name; -			$this->module = new $instance($this); +		$this->module = new $class_name($this); -			// We pre-define the action parameter we are using all over the place -			if (defined('IN_ADMIN')) +		// We pre-define the action parameter we are using all over the place +		if (defined('IN_ADMIN')) +		{ +			/* +			* If this is an extension module, we'll try to automatically set +			* the style paths for the extension (the ext author can change them +			* if necessary). +			*/ +			$module_dir = explode('\\', get_class($this->module)); + +			// 0 vendor, 1 extension name, ... +			if (isset($module_dir[1]))  			{ -				// Is first module automatically enabled a duplicate and the category not passed yet? -				if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate']) +				$module_style_dir = $phpbb_root_path . 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/adm/style'; + +				if (is_dir($module_style_dir))  				{ -					$icat = $this->module_ary[$this->active_module_row_id]['parent']; +					$template->set_custom_style('adm', array($module_style_dir, $phpbb_admin_path . 'style'));  				} +			} -				// Not being able to overwrite ;) -				$this->module->u_action = append_sid("{$phpbb_admin_path}index.$phpEx", "i={$this->p_name}") . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; +			// Is first module automatically enabled a duplicate and the category not passed yet? +			if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate']) +			{ +				$icat = $this->module_ary[$this->active_module_row_id]['parent'];  			} -			else + +			// Not being able to overwrite ;) +			$this->module->u_action = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=' . $this->get_module_identifier($this->p_name, $this->p_id)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; +		} +		else +		{ +			/* +			* If this is an extension module, we'll try to automatically set +			* the style paths for the extension (the ext author can change them +			* if necessary). +			*/ +			$module_dir = explode('\\', get_class($this->module)); + +			// 0 vendor, 1 extension name, ... +			if (isset($module_dir[1]))  			{ -				// If user specified the module url we will use it... -				if ($module_url !== false) -				{ -					$this->module->u_action = $module_url; -				} -				else +				$module_style_dir = 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/styles'; + +				if (is_dir($phpbb_root_path . $module_style_dir))  				{ -					$this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name']; +					$template->set_style(array($module_style_dir, 'styles'));  				} - -				$this->module->u_action = append_sid($this->module->u_action, "i={$this->p_name}") . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}";  			} -			// Add url_extra parameter to u_action url -			if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra']) +			// If user specified the module url we will use it... +			if ($module_url !== false)  			{ -				$this->module->u_action .= $this->module_ary[$this->active_module_row_id]['url_extra']; +				$this->module->u_action = $module_url;  			} - -			// Assign the module path for re-usage -			$this->module->module_path = $module_path . '/'; - -			// Execute the main method for the new instance, we send the module id and mode as parameters -			// Users are able to call the main method after this function to be able to assign additional parameters manually -			if ($execute_module) +			else  			{ -				$this->module->main($this->p_name, $this->p_mode); +				$this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name'];  			} -			return; +			$this->module->u_action = append_sid($this->module->u_action, 'i=' . $this->get_module_identifier($this->p_name, $this->p_id)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; +		} + +		// Add url_extra parameter to u_action url +		if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra']) +		{ +			$this->module->u_action .= $this->module_ary[$this->active_module_row_id]['url_extra']; +		} + +		// Assign the module path for re-usage +		$this->module->module_path = $module_path . '/'; + +		// Execute the main method for the new instance, we send the module id and mode as parameters +		// Users are able to call the main method after this function to be able to assign additional parameters manually +		if ($execute_module) +		{ +			$short_name = preg_replace("#^{$this->p_class}_#", '', $this->p_name); +			$this->module->main($short_name, $this->p_mode);  		}  	} @@ -546,7 +640,7 @@ class p_master  		// If we find a name by this id and being enabled we have our active one...  		foreach ($this->module_ary as $row_id => $item_ary)  		{ -			if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display']) +			if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display'] || $item_ary['name'] === $this->p_class . '_' . $id)  			{  				if ($mode === false || $mode === $item_ary['mode'])  				{ @@ -734,7 +828,26 @@ class p_master  				}  			} -			$u_title = $module_url . $delim . 'i=' . (($item_ary['cat']) ? $item_ary['id'] : $item_ary['name'] . (($item_ary['is_duplicate']) ? '&icat=' . $current_id : '') . '&mode=' . $item_ary['mode']); +			$u_title = $module_url . $delim . 'i='; +			// if the item has a name use it, else use its id +			if (empty($item_ary['name'])) +			{ +				$u_title .= $item_ary['id']; +			} +			else +			{ +				// if the category has a name, then use it. +				$u_title .= $this->get_module_identifier($item_ary['name'], $item_ary['id']); +			} +			// If the item is not a category append the mode +			if (!$item_ary['cat']) +			{ +				if ($item_ary['is_duplicate']) +				{ +					$u_title .= '&icat=' . $current_id; +				} +				$u_title .= '&mode=' . $item_ary['mode']; +			}  			// Was not allowed in categories before - /*!$item_ary['cat'] && */  			$u_title .= (isset($item_ary['url_extra'])) ? $item_ary['url_extra'] : ''; @@ -790,9 +903,22 @@ class p_master  	/**  	* Load module as the current active one without the need for registering it +	* +	* @param string $class module class (acp/mcp/ucp) +	* @param string $name module name (class name of the module, or its basename +    *                     phpbb_ext_foo_acp_bar_module, ucp_zebra or zebra) +	* @param string $mode mode, as passed through to the module +	*  	*/  	function load($class, $name, $mode = false)  	{ +		// new modules use the full class names, old ones are always called <class>_<name>, e.g. acp_board +		// in the latter case this function may be called as load('acp', 'board') +		if (!class_exists($name) && substr($name, 0, strlen($class) + 1) !== $class . '_') +		{ +			$name = $class . '_' . $name; +		} +  		$this->p_class = $class;  		$this->p_name = $name; @@ -840,7 +966,7 @@ class p_master  	{  		foreach ($this->module_ary as $row_id => $item_ary)  		{ -			if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode)) +			if (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode))  			{  				$this->module_ary[$row_id]['display'] = (int) $display;  			} @@ -854,30 +980,72 @@ class p_master  	{  		global $user, $phpEx; -		if (file_exists($user->lang_path . $user->lang_name . '/mods')) +		global $phpbb_extension_manager; + +		$finder = $phpbb_extension_manager->get_finder(); + +		$lang_files = $finder +			->prefix('info_' . strtolower($module_class) . '_') +			->suffix(".$phpEx") +			->extension_directory('/language/' . $user->lang_name) +			->core_path('language/' . $user->lang_name . '/mods/') +			->find(); + +		foreach ($lang_files as $lang_file => $ext_name)  		{ -			$add_files = array(); +			$user->add_lang_ext($ext_name, $lang_file); +		} +	} -			$dir = @opendir($user->lang_path . $user->lang_name . '/mods'); +	/** +	* Retrieve shortened module basename for legacy basenames (with xcp_ prefix) +	* +	* @param string $basename A module basename +	* @return string The basename if it starts with phpbb_ or the basename with +	*                the current p_class (e.g. acp_) stripped. +	*/ +	protected function get_short_name($basename) +	{ +		if (substr($basename, 0, 6) === 'phpbb\\' || strpos($basename, '\\') !== false) +		{ +			return $basename; +		} -			if ($dir) -			{ -				while (($entry = readdir($dir)) !== false) -				{ -					if (strpos($entry, 'info_' . strtolower($module_class) . '_') === 0 && substr(strrchr($entry, '.'), 1) == $phpEx) -					{ -						$add_files[] = 'mods/' . substr(basename($entry), 0, -(strlen($phpEx) + 1)); -					} -				} -				closedir($dir); -			} +		// strip xcp_ prefix from old classes +		return substr($basename, strlen($this->p_class) + 1); +	} -			if (sizeof($add_files)) -			{ -				$user->add_lang($add_files); -			} +	/** +	* If the basename contains a \ we dont use that for the URL. +	* +	* Firefox is currently unable to correctly copy a urlencoded \ +	* so users will be unable to post links to modules. +	* However we can still fallback to the id instead of the name, +	* so we do that in this case. +	* +	* @param	string	$basename	Basename of the module +	* @param	int		$id			Id of the module +	* @return		mixed	Identifier that should be used for +	*						module link creation +	*/ +	protected function get_module_identifier($basename, $id) +	{ +		if (strpos($basename, '\\') === false) +		{ +			return $basename;  		} + +		return $id;  	} -} -?>
\ No newline at end of file +	/** +	* Checks whether the given module basename is a correct class name +	* +	* @param string $basename A module basename +	* @return bool True if the basename starts with phpbb_ or (x)cp_, false otherwise +	*/ +	protected function is_full_class($basename) +	{ +		return (strpos($basename, '\\') !== false || preg_match('/^(ucp|mcp|acp)_/', $basename)); +	} +} | 
