diff options
Diffstat (limited to 'phpBB/phpbb/db/migration/tool')
| -rw-r--r-- | phpBB/phpbb/db/migration/tool/config.php | 160 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/tool/config_text.php | 125 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/tool/module.php | 489 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/tool/permission.php | 632 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/tool/tool_interface.php | 37 | 
5 files changed, 1443 insertions, 0 deletions
| diff --git a/phpBB/phpbb/db/migration/tool/config.php b/phpBB/phpbb/db/migration/tool/config.php new file mode 100644 index 0000000000..f93e7118c4 --- /dev/null +++ b/phpBB/phpbb/db/migration/tool/config.php @@ -0,0 +1,160 @@ +<?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\tool; + +/** +* Migration config tool +*/ +class config implements \phpbb\db\migration\tool\tool_interface +{ +	/** @var \phpbb\config\config */ +	protected $config; + +	/** +	* Constructor +	* +	* @param \phpbb\config\config $config +	*/ +	public function __construct(\phpbb\config\config $config) +	{ +		$this->config = $config; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function get_name() +	{ +		return 'config'; +	} + +	/** +	* Add a config setting. +	* +	* @param string $config_name The name of the config setting +	* 	you would like to add +	* @param mixed $config_value The value of the config setting +	* @param bool $is_dynamic True if it is dynamic (changes very often) +	* 	and should not be stored in the cache, false if not. +	* @return null +	*/ +	public function add($config_name, $config_value, $is_dynamic = false) +	{ +		if (isset($this->config[$config_name])) +		{ +			return; +		} + +		$this->config->set($config_name, $config_value, !$is_dynamic); +	} + +	/** +	* Update an existing config setting. +	* +	* @param string $config_name The name of the config setting you would +	* 	like to update +	* @param mixed $config_value The value of the config setting +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function update($config_name, $config_value) +	{ +		if (!isset($this->config[$config_name])) +		{ +			throw new \phpbb\db\migration\exception('CONFIG_NOT_EXIST', $config_name); +		} + +		$this->config->set($config_name, $config_value); +	} + +	/** +	* Update a config setting if the first argument equal to the +	* current config value +	* +	* @param string $compare If equal to the current config value, will be +	* 	updated to the new config value, otherwise not +	* @param string $config_name The name of the config setting you would +	* 	like to update +	* @param mixed $config_value The value of the config setting +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function update_if_equals($compare, $config_name, $config_value) +	{ +		if (!isset($this->config[$config_name])) +		{ +			throw new \phpbb\db\migration\exception('CONFIG_NOT_EXIST', $config_name); +		} + +		$this->config->set_atomic($config_name, $compare, $config_value); +	} + +	/** +	* Remove an existing config setting. +	* +	* @param string $config_name The name of the config setting you would +	* 	like to remove +	* @return null +	*/ +	public function remove($config_name) +	{ +		if (!isset($this->config[$config_name])) +		{ +			return; +		} + +		$this->config->delete($config_name); +	} + +	/** +	* {@inheritdoc} +	*/ +	public function reverse() +	{ +		$arguments = func_get_args(); +		$original_call = array_shift($arguments); + +		$call = false; +		switch ($original_call) +		{ +			case 'add': +				$call = 'remove'; +			break; + +			case 'remove': +				$call = 'add'; +				if (sizeof($arguments) == 1) +				{ +					$arguments[] = ''; +				} +			break; + +			case 'update_if_equals': +				$call = 'update_if_equals'; + +				// Set to the original value if the current value is what we compared to originally +				$arguments = array( +					$arguments[2], +					$arguments[1], +					$arguments[0], +				); +			break; +		} + +		if ($call) +		{ +			return call_user_func_array(array(&$this, $call), $arguments); +		} +	} +} diff --git a/phpBB/phpbb/db/migration/tool/config_text.php b/phpBB/phpbb/db/migration/tool/config_text.php new file mode 100644 index 0000000000..bf8ac55023 --- /dev/null +++ b/phpBB/phpbb/db/migration/tool/config_text.php @@ -0,0 +1,125 @@ +<?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\tool; + +/** +* Migration config_text tool +*/ +class config_text implements \phpbb\db\migration\tool\tool_interface +{ +	/** @var \phpbb\config\db_text */ +	protected $config_text; + +	/** +	* Constructor +	* +	* @param \phpbb\config\db_text $config_text +	*/ +	public function __construct(\phpbb\config\db_text $config_text) +	{ +		$this->config_text = $config_text; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function get_name() +	{ +		return 'config_text'; +	} + +	/** +	* Add a config_text setting. +	* +	* @param string $config_name The name of the config_text setting +	* 	you would like to add +	* @param mixed $config_value The value of the config_text setting +	* @return null +	*/ +	public function add($config_name, $config_value) +	{ +		if (!is_null($this->config_text->get($config_name))) +		{ +			return; +		} + +		$this->config_text->set($config_name, $config_value); +	} + +	/** +	* Update an existing config_text setting. +	* +	* @param string $config_name The name of the config_text setting you would +	* 	like to update +	* @param mixed $config_value The value of the config_text setting +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function update($config_name, $config_value) +	{ +		if (is_null($this->config_text->get($config_name))) +		{ +			throw new \phpbb\db\migration\exception('CONFIG_NOT_EXIST', $config_name); +		} + +		$this->config_text->set($config_name, $config_value); +	} + +	/** +	* Remove an existing config_text setting. +	* +	* @param string $config_name The name of the config_text setting you would +	* 	like to remove +	* @return null +	*/ +	public function remove($config_name) +	{ +		if (is_null($this->config_text->get($config_name))) +		{ +			return; +		} + +		$this->config_text->delete($config_name); +	} + +	/** +	* {@inheritdoc} +	*/ +	public function reverse() +	{ +		$arguments = func_get_args(); +		$original_call = array_shift($arguments); + +		$call = false; +		switch ($original_call) +		{ +			case 'add': +				$call = 'remove'; +			break; + +			case 'remove': +				$call = 'add'; +				if (sizeof($arguments) == 1) +				{ +					$arguments[] = ''; +				} +			break; +		} + +		if ($call) +		{ +			return call_user_func_array(array(&$this, $call), $arguments); +		} +	} +} diff --git a/phpBB/phpbb/db/migration/tool/module.php b/phpBB/phpbb/db/migration/tool/module.php new file mode 100644 index 0000000000..db43046a95 --- /dev/null +++ b/phpBB/phpbb/db/migration/tool/module.php @@ -0,0 +1,489 @@ +<?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\tool; + +/** +* Migration module management tool +*/ +class module implements \phpbb\db\migration\tool\tool_interface +{ +	/** @var \phpbb\cache\service */ +	protected $cache; + +	/** @var \phpbb\db\driver\driver_interface */ +	protected $db; + +	/** @var \phpbb\user */ +	protected $user; + +	/** @var string */ +	protected $phpbb_root_path; + +	/** @var string */ +	protected $php_ext; + +	/** @var string */ +	protected $modules_table; + +	/** +	* Constructor +	* +	* @param \phpbb\db\driver\driver_interface $db +	* @param \phpbb\cache\service $cache +	* @param \phpbb\user $user +	* @param string $phpbb_root_path +	* @param string $php_ext +	* @param string $modules_table +	*/ +	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, $phpbb_root_path, $php_ext, $modules_table) +	{ +		$this->db = $db; +		$this->cache = $cache; +		$this->user = $user; +		$this->phpbb_root_path = $phpbb_root_path; +		$this->php_ext = $php_ext; +		$this->modules_table = $modules_table; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function get_name() +	{ +		return 'module'; +	} + +	/** +	* Module Exists +	* +	* Check if a module exists +	* +	* @param string $class The module class(acp|mcp|ucp) +	* @param int|string|bool $parent The parent module_id|module_langname (0 for no parent). +	*		Use false to ignore the parent check and check class wide. +	* @param int|string $module The module_id|module_langname you would like to +	* 		check for to see if it exists +	* @return bool true/false if module exists +	*/ +	public function exists($class, $parent, $module) +	{ +		// the main root directory should return true +		if (!$module) +		{ +			return true; +		} + +		$parent_sql = ''; +		if ($parent !== false) +		{ +			// Allows '' to be sent as 0 +			$parent = $parent ?: 0; + +			if (!is_numeric($parent)) +			{ +				$sql = 'SELECT module_id +					FROM ' . $this->modules_table . " +					WHERE module_langname = '" . $this->db->sql_escape($parent) . "' +						AND module_class = '" . $this->db->sql_escape($class) . "'"; +				$result = $this->db->sql_query($sql); +				$module_id = $this->db->sql_fetchfield('module_id'); +				$this->db->sql_freeresult($result); + +				if (!$module_id) +				{ +					return false; +				} + +				$parent_sql = 'AND parent_id = ' . (int) $module_id; +			} +			else +			{ +				$parent_sql = 'AND parent_id = ' . (int) $parent; +			} +		} + +		$sql = 'SELECT module_id +			FROM ' . $this->modules_table . " +			WHERE module_class = '" . $this->db->sql_escape($class) . "' +				$parent_sql +				AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'"); +		$result = $this->db->sql_query($sql); +		$module_id = $this->db->sql_fetchfield('module_id'); +		$this->db->sql_freeresult($result); + +		if ($module_id) +		{ +			return true; +		} + +		return false; +	} + +	/** +	* Module Add +	* +	* Add a new module +	* +	* @param string $class The module class(acp|mcp|ucp) +	* @param int|string $parent The parent module_id|module_langname (0 for no parent) +	* @param array $data an array of the data on the new \module. +	* 	This can be setup in two different ways. +	*	1. The "manual" way.  For inserting a category or one at a time. +	*		It will be merged with the base array shown a bit below, +	*			but at the least requires 'module_langname' to be sent, and, +	*			if you want to create a module (instead of just a category) you must +	*			send module_basename and module_mode. +	*		array( +	*			'module_enabled'	=> 1, +	*			'module_display'	=> 1, +	*	   		'module_basename'	=> '', +	*			'module_class'		=> $class, +	*	   		'parent_id'			=> (int) $parent, +	*			'module_langname'	=> '', +	*	   		'module_mode'		=> '', +	*	   		'module_auth'		=> '', +	*		) +	*	2. The "automatic" way.  For inserting multiple at a time based on the +	*			specs in the info file for the module(s).  For this to work the +	*			modules must be correctly setup in the info file. +	*		An example follows (this would insert the settings, log, and flag +	*			modes from the includes/acp/info/acp_asacp.php file): +	* 		array( +	* 			'module_basename'	=> 'asacp', +	* 			'modes'				=> array('settings', 'log', 'flag'), +	* 		) +	* 		Optionally you may not send 'modes' and it will insert all of the +	* 			modules in that info file. +	* 	path, specify that here +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function add($class, $parent = 0, $data = array()) +	{ +		// Allows '' to be sent as 0 +		$parent = $parent ?: 0; + +		// allow sending the name as a string in $data to create a category +		if (!is_array($data)) +		{ +			$data = array('module_langname' => $data); +		} + +		if (!isset($data['module_langname'])) +		{ +			// The "automatic" way +			$basename = (isset($data['module_basename'])) ? $data['module_basename'] : ''; +			$module = $this->get_module_info($class, $basename); + +			$result = ''; +			foreach ($module['modes'] as $mode => $module_info) +			{ +				if (!isset($data['modes']) || in_array($mode, $data['modes'])) +				{ +					$new_module = array( +						'module_basename'	=> $basename, +						'module_langname'	=> $module_info['title'], +						'module_mode'		=> $mode, +						'module_auth'		=> $module_info['auth'], +						'module_display'	=> (isset($module_info['display'])) ? $module_info['display'] : true, +						'before'			=> (isset($module_info['before'])) ? $module_info['before'] : false, +						'after'				=> (isset($module_info['after'])) ? $module_info['after'] : false, +					); + +					// Run the "manual" way with the data we've collected. +					$this->add($class, $parent, $new_module); +				} +			} + +			return; +		} + +		// The "manual" way +		if (!is_numeric($parent)) +		{ +			$sql = 'SELECT module_id +				FROM ' . $this->modules_table . " +				WHERE module_langname = '" . $this->db->sql_escape($parent) . "' +					AND module_class = '" . $this->db->sql_escape($class) . "'"; +			$result = $this->db->sql_query($sql); +			$module_id = $this->db->sql_fetchfield('module_id'); +			$this->db->sql_freeresult($result); + +			if (!$module_id) +			{ +				throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent); +			} + +			$parent = $data['parent_id'] = $module_id; +		} +		else if (!$this->exists($class, false, $parent)) +		{ +			throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent); +		} + +		if ($this->exists($class, $parent, $data['module_langname'])) +		{ +			return; +		} + +		if (!class_exists('acp_modules')) +		{ +			include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); +			$this->user->add_lang('acp/modules'); +		} +		$acp_modules = new \acp_modules(); + +		$module_data = array( +			'module_enabled'	=> (isset($data['module_enabled'])) ? $data['module_enabled'] : 1, +			'module_display'	=> (isset($data['module_display'])) ? $data['module_display'] : 1, +			'module_basename'	=> (isset($data['module_basename'])) ? $data['module_basename'] : '', +			'module_class'		=> $class, +			'parent_id'			=> (int) $parent, +			'module_langname'	=> (isset($data['module_langname'])) ? $data['module_langname'] : '', +			'module_mode'		=> (isset($data['module_mode'])) ? $data['module_mode'] : '', +			'module_auth'		=> (isset($data['module_auth'])) ? $data['module_auth'] : '', +		); +		$result = $acp_modules->update_module_data($module_data, true); + +		// update_module_data can either return a string or an empty array... +		if (is_string($result)) +		{ +			// Error +			throw new \phpbb\db\migration\exception('MODULE_ERROR', $result); +		} +		else +		{ +			// Success +			$module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']); +			add_log('admin', 'LOG_MODULE_ADD', $module_log_name); + +			// Move the module if requested above/below an existing one +			if (isset($data['before']) && $data['before']) +			{ +				$sql = 'SELECT left_id +					FROM ' . $this->modules_table . " +					WHERE module_class = '" . $this->db->sql_escape($class) . "' +						AND parent_id = " . (int) $parent . " +						AND module_langname = '" . $this->db->sql_escape($data['before']) . "'"; +				$this->db->sql_query($sql); +				$to_left = (int) $this->db->sql_fetchfield('left_id'); + +				$sql = 'UPDATE ' . $this->modules_table . " +					SET left_id = left_id + 2, right_id = right_id + 2 +					WHERE module_class = '" . $this->db->sql_escape($class) . "' +						AND left_id >= $to_left +						AND left_id < {$module_data['left_id']}"; +				$this->db->sql_query($sql); + +				$sql = 'UPDATE ' . $this->modules_table . " +					SET left_id = $to_left, right_id = " . ($to_left + 1) . " +					WHERE module_class = '" . $this->db->sql_escape($class) . "' +						AND module_id = {$module_data['module_id']}"; +				$this->db->sql_query($sql); +			} +			else if (isset($data['after']) && $data['after']) +			{ +				$sql = 'SELECT right_id +					FROM ' . $this->modules_table . " +					WHERE module_class = '" . $this->db->sql_escape($class) . "' +						AND parent_id = " . (int) $parent . " +						AND module_langname = '" . $this->db->sql_escape($data['after']) . "'"; +				$this->db->sql_query($sql); +				$to_right = (int) $this->db->sql_fetchfield('right_id'); + +				$sql = 'UPDATE ' . $this->modules_table . " +					SET left_id = left_id + 2, right_id = right_id + 2 +					WHERE module_class = '" . $this->db->sql_escape($class) . "' +						AND left_id >= $to_right +						AND left_id < {$module_data['left_id']}"; +				$this->db->sql_query($sql); + +				$sql = 'UPDATE ' . $this->modules_table . ' +					SET left_id = ' . ($to_right + 1) . ', right_id = ' . ($to_right + 2) . " +					WHERE module_class = '" . $this->db->sql_escape($class) . "' +						AND module_id = {$module_data['module_id']}"; +				$this->db->sql_query($sql); +			} +		} + +		// Clear the Modules Cache +		$this->cache->destroy("_modules_$class"); +	} + +	/** +	* Module Remove +	* +	* Remove a module +	* +	* @param string $class The module class(acp|mcp|ucp) +	* @param int|string|bool $parent The parent module_id|module_langname(0 for no parent). +	* 	Use false to ignore the parent check and check class wide. +	* @param int|string $module The module id|module_langname +	* 	specify that here +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function remove($class, $parent = 0, $module = '') +	{ +		// Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto +		if (is_array($module)) +		{ +			if (isset($module['module_langname'])) +			{ +				// Manual Method +				return $this->remove($class, $parent, $module['module_langname']); +			} + +			// Failed. +			if (!isset($module['module_basename'])) +			{ +				throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST'); +			} + +			// Automatic method +			$basename = $module['module_basename']; +			$module_info = $this->get_module_info($class, $basename); + +			foreach ($module_info['modes'] as $mode => $info) +			{ +				if (!isset($module['modes']) || in_array($mode, $module['modes'])) +				{ +					$this->remove($class, $parent, $info['title']); +				} +			} +		} +		else +		{ +			if (!$this->exists($class, $parent, $module)) +			{ +				return; +			} + +			$parent_sql = ''; +			if ($parent !== false) +			{ +				// Allows '' to be sent as 0 +				$parent = ($parent) ?: 0; + +				if (!is_numeric($parent)) +				{ +					$sql = 'SELECT module_id +						FROM ' . $this->modules_table . " +						WHERE module_langname = '" . $this->db->sql_escape($parent) . "' +							AND module_class = '" . $this->db->sql_escape($class) . "'"; +					$result = $this->db->sql_query($sql); +					$module_id = $this->db->sql_fetchfield('module_id'); +					$this->db->sql_freeresult($result); + +					// we know it exists from the module_exists check +					$parent_sql = 'AND parent_id = ' . (int) $module_id; +				} +				else +				{ +					$parent_sql = 'AND parent_id = ' . (int) $parent; +				} +			} + +			$module_ids = array(); +			if (!is_numeric($module)) +			{ +				$sql = 'SELECT module_id +					FROM ' . $this->modules_table . " +					WHERE module_langname = '" . $this->db->sql_escape($module) . "' +						AND module_class = '" . $this->db->sql_escape($class) . "' +						$parent_sql"; +				$result = $this->db->sql_query($sql); +				while ($module_id = $this->db->sql_fetchfield('module_id')) +				{ +					$module_ids[] = (int) $module_id; +				} +				$this->db->sql_freeresult($result); +			} +			else +			{ +				$module_ids[] = (int) $module; +			} + +			if (!class_exists('acp_modules')) +			{ +				include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); +				$this->user->add_lang('acp/modules'); +			} +			$acp_modules = new \acp_modules(); +			$acp_modules->module_class = $class; + +			foreach ($module_ids as $module_id) +			{ +				$result = $acp_modules->delete_module($module_id); +				if (!empty($result)) +				{ +					return; +				} +			} + +			$this->cache->destroy("_modules_$class"); +		} +	} + +	/** +	* {@inheritdoc} +	*/ +	public function reverse() +	{ +		$arguments = func_get_args(); +		$original_call = array_shift($arguments); + +		$call = false; +		switch ($original_call) +		{ +			case 'add': +				$call = 'remove'; +			break; + +			case 'remove': +				$call = 'add'; +			break; +		} + +		if ($call) +		{ +			return call_user_func_array(array(&$this, $call), $arguments); +		} +	} + +	/** +	* Wrapper for \acp_modules::get_module_infos() +	* +	* @param string $class Module Class +	* @param string $basename Module Basename +	* @return array Module Information +	* @throws \phpbb\db\migration\exception +	*/ +	protected function get_module_info($class, $basename) +	{ +		if (!class_exists('acp_modules')) +		{ +			include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext); +		} +		$acp_modules = new \acp_modules(); +		$module = $acp_modules->get_module_infos($basename, $class, true); + +		if (empty($module)) +		{ +			throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename); +		} + +		return array_pop($module); +	} +} diff --git a/phpBB/phpbb/db/migration/tool/permission.php b/phpBB/phpbb/db/migration/tool/permission.php new file mode 100644 index 0000000000..5cfbc5ca00 --- /dev/null +++ b/phpBB/phpbb/db/migration/tool/permission.php @@ -0,0 +1,632 @@ +<?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\tool; + +/** +* Migration permission management tool +*/ +class permission implements \phpbb\db\migration\tool\tool_interface +{ +	/** @var \phpbb\auth\auth */ +	protected $auth; + +	/** @var \phpbb\cache\service */ +	protected $cache; + +	/** @var \phpbb\db\driver\driver_interface */ +	protected $db; + +	/** @var string */ +	protected $phpbb_root_path; + +	/** @var string */ +	protected $php_ext; + +	/** +	* Constructor +	* +	* @param \phpbb\db\driver\driver_interface $db +	* @param \phpbb\cache\service $cache +	* @param \phpbb\auth\auth $auth +	* @param string $phpbb_root_path +	* @param string $php_ext +	*/ +	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\auth\auth $auth, $phpbb_root_path, $php_ext) +	{ +		$this->db = $db; +		$this->cache = $cache; +		$this->auth = $auth; +		$this->phpbb_root_path = $phpbb_root_path; +		$this->php_ext = $php_ext; +	} + +	/** +	* {@inheritdoc} +	*/ +	public function get_name() +	{ +		return 'permission'; +	} + +	/** +	* Permission Exists +	* +	* Check if a permission (auth) setting exists +	* +	* @param string $auth_option The name of the permission (auth) option +	* @param bool $global True for checking a global permission setting, +	* 	False for a local permission setting +	* @return bool true if it exists, false if not +	*/ +	public function exists($auth_option, $global = true) +	{ +		if ($global) +		{ +			$type_sql = ' AND is_global = 1'; +		} +		else +		{ +			$type_sql = ' AND is_local = 1'; +		} + +		$sql = 'SELECT auth_option_id +			FROM ' . ACL_OPTIONS_TABLE . " +			WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'" +				. $type_sql; +		$result = $this->db->sql_query($sql); + +		$row = $this->db->sql_fetchrow($result); +		$this->db->sql_freeresult($result); + +		if ($row) +		{ +			return true; +		} + +		return false; +	} + +	/** +	* Permission Add +	* +	* Add a permission (auth) option +	* +	* @param string $auth_option The name of the permission (auth) option +	* @param bool $global True for checking a global permission setting, +	* 	False for a local permission setting +	* @param int|false $copy_from If set, contains the id of the permission from which to copy the new one. +	* @return null +	*/ +	public function add($auth_option, $global = true, $copy_from = false) +	{ +		if ($this->exists($auth_option, $global)) +		{ +			return; +		} + +		// We've added permissions, so set to true to notify the user. +		$this->permissions_added = true; + +		if (!class_exists('auth_admin')) +		{ +			include($this->phpbb_root_path . 'includes/acp/auth.' . $this->php_ext); +		} +		$auth_admin = new \auth_admin(); + +		// We have to add a check to see if the !$global (if global, local, and if local, global) permission already exists.  If it does, acl_add_option currently has a bug which would break the ACL system, so we are having a work-around here. +		if ($this->exists($auth_option, !$global)) +		{ +			$sql_ary = array( +				'is_global'	=> 1, +				'is_local'	=> 1, +			); +			$sql = 'UPDATE ' . ACL_OPTIONS_TABLE . ' +				SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . " +				WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'"; +			$this->db->sql_query($sql); +		} +		else +		{ +			if ($global) +			{ +				$auth_admin->acl_add_option(array('global' => array($auth_option))); +			} +			else +			{ +				$auth_admin->acl_add_option(array('local' => array($auth_option))); +			} +		} + +		// The permission has been added, now we can copy it if needed +		if ($copy_from && isset($auth_admin->acl_options['id'][$copy_from])) +		{ +			$old_id = $auth_admin->acl_options['id'][$copy_from]; +			$new_id = $auth_admin->acl_options['id'][$auth_option]; + +			$tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE); + +			foreach ($tables as $table) +			{ +				$sql = 'SELECT * +					FROM ' . $table . ' +					WHERE auth_option_id = ' . $old_id; +				$result = $this->db->sql_query($sql); + +				$sql_ary = array(); +				while ($row = $this->db->sql_fetchrow($result)) +				{ +					$row['auth_option_id'] = $new_id; +					$sql_ary[] = $row; +				} +				$this->db->sql_freeresult($result); + +				if (!empty($sql_ary)) +				{ +					$this->db->sql_multi_insert($table, $sql_ary); +				} +			} + +			$auth_admin->acl_clear_prefetch(); +		} +	} + +	/** +	* Permission Remove +	* +	* Remove a permission (auth) option +	* +	* @param string $auth_option The name of the permission (auth) option +	* @param bool $global True for checking a global permission setting, +	* 	False for a local permission setting +	* @return null +	*/ +	public function remove($auth_option, $global = true) +	{ +		if (!$this->exists($auth_option, $global)) +		{ +			return; +		} + +		if ($global) +		{ +			$type_sql = ' AND is_global = 1'; +		} +		else +		{ +			$type_sql = ' AND is_local = 1'; +		} +		$sql = 'SELECT auth_option_id, is_global, is_local +			FROM ' . ACL_OPTIONS_TABLE . " +			WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'" . +				$type_sql; +		$result = $this->db->sql_query($sql); +		$row = $this->db->sql_fetchrow($result); +		$this->db->sql_freeresult($result); + +		$id = (int) $row['auth_option_id']; + +		// If it is a local and global permission, do not remove the row! :P +		if ($row['is_global'] && $row['is_local']) +		{ +			$sql = 'UPDATE ' . ACL_OPTIONS_TABLE . ' +				SET ' . (($global) ? 'is_global = 0' : 'is_local = 0') . ' +				WHERE auth_option_id = ' . $id; +			$this->db->sql_query($sql); +		} +		else +		{ +			// Delete time +			$tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE, ACL_OPTIONS_TABLE); +			foreach ($tables as $table) +			{ +				$this->db->sql_query('DELETE FROM ' . $table . ' +					WHERE auth_option_id = ' . $id); +			} +		} + +		// Purge the auth cache +		$this->cache->destroy('_acl_options'); +		$this->auth->acl_clear_prefetch(); +	} + +	/** +	* Add a new permission role +	* +	* @param string $role_name The new role name +	* @param string $role_type The type (u_, m_, a_) +	* @param string $role_description Description of the new role +	* +	* @return null +	*/ +	public function role_add($role_name, $role_type, $role_description = '') +	{ +		$sql = 'SELECT role_id +			FROM ' . ACL_ROLES_TABLE . " +			WHERE role_name = '" . $this->db->sql_escape($role_name) . "'"; +		$this->db->sql_query($sql); +		$role_id = (int) $this->db->sql_fetchfield('role_id'); + +		if ($role_id) +		{ +			return; +		} + +		$sql = 'SELECT MAX(role_order) AS max_role_order +			FROM ' . ACL_ROLES_TABLE . " +			WHERE role_type = '" . $this->db->sql_escape($role_type) . "'"; +		$this->db->sql_query($sql); +		$role_order = (int) $this->db->sql_fetchfield('max_role_order'); +		$role_order = (!$role_order) ? 1 : $role_order + 1; + +		$sql_ary = array( +			'role_name'			=> $role_name, +			'role_description'	=> $role_description, +			'role_type'			=> $role_type, +			'role_order'		=> $role_order, +		); + +		$sql = 'INSERT INTO ' . ACL_ROLES_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary); +		$this->db->sql_query($sql); +	} + +	/** +	* Update the name on a permission role +	* +	* @param string $old_role_name The old role name +	* @param string $new_role_name The new role name +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function role_update($old_role_name, $new_role_name) +	{ +		$sql = 'SELECT role_id +			FROM ' . ACL_ROLES_TABLE . " +			WHERE role_name = '" . $this->db->sql_escape($old_role_name) . "'"; +		$this->db->sql_query($sql); +		$role_id = (int) $this->db->sql_fetchfield('role_id'); + +		if (!$role_id) +		{ +			throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $old_role_name); +		} + +		$sql = 'UPDATE ' . ACL_ROLES_TABLE . " +			SET role_name = '" . $this->db->sql_escape($new_role_name) . "' +			WHERE role_name = '" . $this->db->sql_escape($old_role_name) . "'"; +		$this->db->sql_query($sql); +	} + +	/** +	* Remove a permission role +	* +	* @param string $role_name The role name to remove +	* @return null +	*/ +	public function role_remove($role_name) +	{ +		$sql = 'SELECT role_id +			FROM ' . ACL_ROLES_TABLE . " +			WHERE role_name = '" . $this->db->sql_escape($role_name) . "'"; +		$this->db->sql_query($sql); +		$role_id = (int) $this->db->sql_fetchfield('role_id'); + +		if (!$role_id) +		{ +			return; +		} + +		$sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' +			WHERE role_id = ' . $role_id; +		$this->db->sql_query($sql); + +		$sql = 'DELETE FROM ' . ACL_ROLES_TABLE . ' +			WHERE role_id = ' . $role_id; +		$this->db->sql_query($sql); + +		$this->auth->acl_clear_prefetch(); +	} + +	/** +	* Permission Set +	* +	* Allows you to set permissions for a certain group/role +	* +	* @param string $name The name of the role/group +	* @param string|array $auth_option The auth_option or array of +	* 	auth_options you would like to set +	* @param string $type The type (role|group) +	* @param bool $has_permission True if you want to give them permission, +	* 	false if you want to deny them permission +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function permission_set($name, $auth_option, $type = 'role', $has_permission = true) +	{ +		if (!is_array($auth_option)) +		{ +			$auth_option = array($auth_option); +		} + +		$new_auth = array(); +		$sql = 'SELECT auth_option_id +			FROM ' . ACL_OPTIONS_TABLE . ' +			WHERE ' . $this->db->sql_in_set('auth_option', $auth_option); +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$new_auth[] = (int) $row['auth_option_id']; +		} +		$this->db->sql_freeresult($result); + +		if (empty($new_auth)) +		{ +			return; +		} + +		$current_auth = array(); + +		$type = (string) $type; // Prevent PHP bug. + +		switch ($type) +		{ +			case 'role': +				$sql = 'SELECT role_id +					FROM ' . ACL_ROLES_TABLE . " +					WHERE role_name = '" . $this->db->sql_escape($name) . "'"; +				$this->db->sql_query($sql); +				$role_id = (int) $this->db->sql_fetchfield('role_id'); + +				if (!$role_id) +				{ +					throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $name); +				} + +				$sql = 'SELECT auth_option_id, auth_setting +					FROM ' . ACL_ROLES_DATA_TABLE . ' +					WHERE role_id = ' . $role_id; +				$result = $this->db->sql_query($sql); +				while ($row = $this->db->sql_fetchrow($result)) +				{ +					$current_auth[$row['auth_option_id']] = $row['auth_setting']; +				} +				$this->db->sql_freeresult($result); +			break; + +			case 'group': +				$sql = 'SELECT group_id +					FROM ' . GROUPS_TABLE . " +					WHERE group_name = '" . $this->db->sql_escape($name) . "'"; +				$this->db->sql_query($sql); +				$group_id = (int) $this->db->sql_fetchfield('group_id'); + +				if (!$group_id) +				{ +					throw new \phpbb\db\migration\exception('GROUP_NOT_EXIST', $name); +				} + +				// If the group has a role set for them we will add the requested permissions to that role. +				$sql = 'SELECT auth_role_id +					FROM ' . ACL_GROUPS_TABLE . ' +					WHERE group_id = ' . $group_id . ' +						AND auth_role_id <> 0 +						AND forum_id = 0'; +				$this->db->sql_query($sql); +				$role_id = (int) $this->db->sql_fetchfield('auth_role_id'); +				if ($role_id) +				{ +					$sql = 'SELECT role_name +						FROM ' . ACL_ROLES_TABLE . ' +						WHERE role_id = ' . $role_id; +					$this->db->sql_query($sql); +					$role_name = $this->db->sql_fetchfield('role_name'); + +					return $this->permission_set($role_name, $auth_option, 'role', $has_permission); +				} + +				$sql = 'SELECT auth_option_id, auth_setting +					FROM ' . ACL_GROUPS_TABLE . ' +					WHERE group_id = ' . $group_id; +				$result = $this->db->sql_query($sql); +				while ($row = $this->db->sql_fetchrow($result)) +				{ +					$current_auth[$row['auth_option_id']] = $row['auth_setting']; +				} +				$this->db->sql_freeresult($result); +			break; +		} + +		$sql_ary = array(); +		switch ($type) +		{ +			case 'role': +				foreach ($new_auth as $auth_option_id) +				{ +					if (!isset($current_auth[$auth_option_id])) +					{ +						$sql_ary[] = array( +							'role_id'			=> $role_id, +							'auth_option_id'	=> $auth_option_id, +							'auth_setting'		=> $has_permission, +						); +					} +				} + +				$this->db->sql_multi_insert(ACL_ROLES_DATA_TABLE, $sql_ary); +			break; + +			case 'group': +				foreach ($new_auth as $auth_option_id) +				{ +					if (!isset($current_auth[$auth_option_id])) +					{ +						$sql_ary[] = array( +							'group_id'			=> $group_id, +							'auth_option_id'	=> $auth_option_id, +							'auth_setting'		=> $has_permission, +						); +					} +				} + +				$this->db->sql_multi_insert(ACL_GROUPS_TABLE, $sql_ary); +			break; +		} + +		$this->auth->acl_clear_prefetch(); +	} + +	/** +	* Permission Unset +	* +	* Allows you to unset (remove) permissions for a certain group/role +	* +	* @param string $name The name of the role/group +	* @param string|array $auth_option The auth_option or array of +	* 	auth_options you would like to set +	* @param string $type The type (role|group) +	* @return null +	* @throws \phpbb\db\migration\exception +	*/ +	public function permission_unset($name, $auth_option, $type = 'role') +	{ +		if (!is_array($auth_option)) +		{ +			$auth_option = array($auth_option); +		} + +		$to_remove = array(); +		$sql = 'SELECT auth_option_id +			FROM ' . ACL_OPTIONS_TABLE . ' +			WHERE ' . $this->db->sql_in_set('auth_option', $auth_option); +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$to_remove[] = (int) $row['auth_option_id']; +		} +		$this->db->sql_freeresult($result); + +		if (empty($to_remove)) +		{ +			return; +		} + +		$type = (string) $type; // Prevent PHP bug. + +		switch ($type) +		{ +			case 'role': +				$sql = 'SELECT role_id +					FROM ' . ACL_ROLES_TABLE . " +					WHERE role_name = '" . $this->db->sql_escape($name) . "'"; +				$this->db->sql_query($sql); +				$role_id = (int) $this->db->sql_fetchfield('role_id'); + +				if (!$role_id) +				{ +					throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $name); +				} + +				$sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' +					WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove); +				$this->db->sql_query($sql); +			break; + +			case 'group': +				$sql = 'SELECT group_id +					FROM ' . GROUPS_TABLE . " +					WHERE group_name = '" . $this->db->sql_escape($name) . "'"; +				$this->db->sql_query($sql); +				$group_id = (int) $this->db->sql_fetchfield('group_id'); + +				if (!$group_id) +				{ +					throw new \phpbb\db\migration\exception('GROUP_NOT_EXIST', $name); +				} + +				// If the group has a role set for them we will remove the requested permissions from that role. +				$sql = 'SELECT auth_role_id +					FROM ' . ACL_GROUPS_TABLE . ' +					WHERE group_id = ' . $group_id . ' +						AND auth_role_id <> 0'; +				$this->db->sql_query($sql); +				$role_id = (int) $this->db->sql_fetchfield('auth_role_id'); +				if ($role_id) +				{ +					$sql = 'SELECT role_name +						FROM ' . ACL_ROLES_TABLE . ' +						WHERE role_id = ' . $role_id; +					$this->db->sql_query($sql); +					$role_name = $this->db->sql_fetchfield('role_name'); + +					return $this->permission_unset($role_name, $auth_option, 'role'); +				} + +				$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' +					WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove); +				$this->db->sql_query($sql); +			break; +		} + +		$this->auth->acl_clear_prefetch(); +	} + +	/** +	* {@inheritdoc} +	*/ +	public function reverse() +	{ +		$arguments = func_get_args(); +		$original_call = array_shift($arguments); + +		$call = false; +		switch ($original_call) +		{ +			case 'add': +				$call = 'remove'; +			break; + +			case 'remove': +				$call = 'add'; +			break; + +			case 'permission_set': +				$call = 'permission_unset'; +			break; + +			case 'permission_unset': +				$call = 'permission_set'; +			break; + +			case 'role_add': +				$call = 'role_remove'; +			break; + +			case 'role_remove': +				$call = 'role_add'; +			break; + +			case 'role_update': +				// Set to the original value if the current value is what we compared to originally +				$arguments = array( +					$arguments[1], +					$arguments[0], +				); +			break; +		} + +		if ($call) +		{ +			return call_user_func_array(array(&$this, $call), $arguments); +		} +	} +} diff --git a/phpBB/phpbb/db/migration/tool/tool_interface.php b/phpBB/phpbb/db/migration/tool/tool_interface.php new file mode 100644 index 0000000000..07cd2435e4 --- /dev/null +++ b/phpBB/phpbb/db/migration/tool/tool_interface.php @@ -0,0 +1,37 @@ +<?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\tool; + +/** +* Migration tool interface +*/ +interface tool_interface +{ +	/** +	* Retrieve a short name used for commands in migrations. +	* +	* @return string short name +	*/ +	public function get_name(); + +	/** +	* Reverse an original install action +	* +	* First argument is the original call to the class (e.g. add, remove) +	* After the first argument, send the original arguments to the function in the original call +	* +	* @return null +	*/ +	public function reverse(); +} | 
