diff options
Diffstat (limited to 'phpBB/phpbb')
65 files changed, 3113 insertions, 1552 deletions
| diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php index b59f0e60ec..92c19fd5f7 100644 --- a/phpBB/phpbb/auth/auth.php +++ b/phpBB/phpbb/auth/auth.php @@ -929,6 +929,7 @@ class auth  	{  		global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container; +		/* @var $provider_collection \phpbb\auth\provider_collection */  		$provider_collection = $phpbb_container->get('auth.provider_collection');  		$provider = $provider_collection->get_provider(); diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index d8c5fb72de..1adf85ee05 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -155,6 +155,7 @@ class db extends \phpbb\auth\provider\base  		// Every auth module is able to define what to do by itself...  		if ($show_captcha)  		{ +			/* @var $captcha_factory \phpbb\captcha\factory */  			$captcha_factory = $this->phpbb_container->get('captcha.factory');  			$captcha = $captcha_factory->get_instance($this->config['captcha_plugin']);  			$captcha->init(CONFIRM_LOGIN); diff --git a/phpBB/phpbb/cache/driver/base.php b/phpBB/phpbb/cache/driver/base.php index 4c20ad916d..c83b928a12 100644 --- a/phpBB/phpbb/cache/driver/base.php +++ b/phpBB/phpbb/cache/driver/base.php @@ -50,6 +50,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface  			}  			else if (strpos($filename, 'container_') === 0 ||  				strpos($filename, 'url_matcher') === 0 || +				strpos($filename, 'url_generator') === 0 ||  				strpos($filename, 'sql_') === 0 ||  				strpos($filename, 'data_') === 0)  			{ @@ -90,14 +91,14 @@ abstract class base implements \phpbb\cache\driver\driver_interface  	{  		// Remove extra spaces and tabs  		$query = preg_replace('/[\n\r\s\t]+/', ' ', $query); +		$query_id = md5($query); -		if (($rowset = $this->_read('sql_' . md5($query))) === false) +		if (($result = $this->_read('sql_' . $query_id)) === false)  		{  			return false;  		} -		$query_id = sizeof($this->sql_rowset); -		$this->sql_rowset[$query_id] = $rowset; +		$this->sql_rowset[$query_id] = $result;  		$this->sql_row_pointer[$query_id] = 0;  		return $query_id; diff --git a/phpBB/phpbb/cache/driver/eaccelerator.php b/phpBB/phpbb/cache/driver/eaccelerator.php index 1697758acc..740855144f 100644 --- a/phpBB/phpbb/cache/driver/eaccelerator.php +++ b/phpBB/phpbb/cache/driver/eaccelerator.php @@ -44,9 +44,11 @@ class eaccelerator extends \phpbb\cache\driver\memory  	*/  	function tidy()  	{ +		global $config; +  		eaccelerator_gc(); -		set_config('cache_last_gc', time(), true); +		$config->set('cache_last_gc', time(), false);  	}  	/** diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php index 9a7c4aec7f..32086458ee 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -27,8 +27,14 @@ class file extends \phpbb\cache\driver\base  	*/  	function __construct($cache_dir = null)  	{ -		global $phpbb_root_path; -		$this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_root_path . 'cache/'; +		global $phpbb_root_path, $phpbb_container; + +		$this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_root_path . 'cache/' . $phpbb_container->getParameter('core.environment') . '/'; + +		if (!is_dir($this->cache_dir)) +		{ +			@mkdir($this->cache_dir, 0777, true); +		}  	}  	/** @@ -89,7 +95,7 @@ class file extends \phpbb\cache\driver\base  	*/  	function tidy()  	{ -		global $phpEx; +		global $config, $phpEx;  		$dir = @opendir($this->cache_dir); @@ -143,7 +149,7 @@ class file extends \phpbb\cache\driver\base  			}  		} -		set_config('cache_last_gc', time(), true); +		$config->set('cache_last_gc', time(), false);  	}  	/** @@ -306,7 +312,7 @@ class file extends \phpbb\cache\driver\base  		// Remove extra spaces and tabs  		$query = preg_replace('/[\n\r\s\t]+/', ' ', $query); -		$query_id = sizeof($this->sql_rowset); +		$query_id = md5($query);  		$this->sql_rowset[$query_id] = array();  		$this->sql_row_pointer[$query_id] = 0; @@ -316,7 +322,7 @@ class file extends \phpbb\cache\driver\base  		}  		$db->sql_freeresult($query_result); -		if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query)) +		if ($this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl + time(), $query))  		{  			return $query_id;  		} diff --git a/phpBB/phpbb/cache/driver/memory.php b/phpBB/phpbb/cache/driver/memory.php index 0b0e323e3d..baae22d809 100644 --- a/phpBB/phpbb/cache/driver/memory.php +++ b/phpBB/phpbb/cache/driver/memory.php @@ -81,9 +81,10 @@ abstract class memory extends \phpbb\cache\driver\base  	*/  	function tidy()  	{ -		// cache has auto GC, no need to have any code here :) +		global $config; -		set_config('cache_last_gc', time(), true); +		// cache has auto GC, no need to have any code here :) +		$config->set('cache_last_gc', time(), false);  	}  	/** @@ -203,7 +204,7 @@ abstract class memory extends \phpbb\cache\driver\base  	{  		// Remove extra spaces and tabs  		$query = preg_replace('/[\n\r\s\t]+/', ' ', $query); -		$hash = md5($query); +		$query_id = md5($query);  		// determine which tables this query belongs to  		// Some queries use backticks, namely the get_database_size() query @@ -244,14 +245,13 @@ abstract class memory extends \phpbb\cache\driver\base  				$temp = array();  			} -			$temp[$hash] = true; +			$temp[$query_id] = true;  			// This must never expire  			$this->_write('sql_' . $table_name, $temp, 0);  		}  		// store them in the right place -		$query_id = sizeof($this->sql_rowset);  		$this->sql_rowset[$query_id] = array();  		$this->sql_row_pointer[$query_id] = 0; @@ -261,7 +261,7 @@ abstract class memory extends \phpbb\cache\driver\base  		}  		$db->sql_freeresult($query_result); -		$this->_write('sql_' . $hash, $this->sql_rowset[$query_id], $ttl); +		$this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl);  		return $query_id;  	} diff --git a/phpBB/phpbb/cache/driver/null.php b/phpBB/phpbb/cache/driver/null.php index a45cf97862..298731ea54 100644 --- a/phpBB/phpbb/cache/driver/null.php +++ b/phpBB/phpbb/cache/driver/null.php @@ -52,8 +52,10 @@ class null extends \phpbb\cache\driver\base  	*/  	function tidy()  	{ +		global $config; +  		// This cache always has a tidy room. -		set_config('cache_last_gc', time(), true); +		$config->set('cache_last_gc', time(), false);  	}  	/** diff --git a/phpBB/phpbb/captcha/plugins/captcha_abstract.php b/phpBB/phpbb/captcha/plugins/captcha_abstract.php index 24ed7f939d..799947a84e 100644 --- a/phpBB/phpbb/captcha/plugins/captcha_abstract.php +++ b/phpBB/phpbb/captcha/plugins/captcha_abstract.php @@ -34,12 +34,12 @@ abstract class captcha_abstract  	function init($type)  	{ -		global $config, $db, $user; +		global $config, $db, $user, $request;  		// read input -		$this->confirm_id = request_var('confirm_id', ''); -		$this->confirm_code = request_var('confirm_code', ''); -		$refresh = request_var('refresh_vc', false) && $config['confirm_refresh']; +		$this->confirm_id = $request->variable('confirm_id', ''); +		$this->confirm_code = $request->variable('confirm_code', ''); +		$refresh = $request->variable('refresh_vc', false) && $config['confirm_refresh'];  		$this->type = (int) $type; @@ -117,7 +117,7 @@ abstract class captcha_abstract  	function get_demo_template($id)  	{ -		global $config, $user, $template, $phpbb_admin_path, $phpEx; +		global $config, $user, $template, $request, $phpbb_admin_path, $phpEx;  		$variables = ''; @@ -125,7 +125,7 @@ abstract class captcha_abstract  		{  			foreach ($this->captcha_vars as $captcha_var => $template_var)  			{ -				$variables .= '&' . rawurlencode($captcha_var) . '=' . request_var($captcha_var, (int) $config[$captcha_var]); +				$variables .= '&' . rawurlencode($captcha_var) . '=' . $request->variable($captcha_var, (int) $config[$captcha_var]);  			}  		} @@ -350,7 +350,9 @@ abstract class captcha_abstract  	function is_solved()  	{ -		if (request_var('confirm_code', false) && $this->solved === 0) +		global $request; + +		if ($request->variable('confirm_code', false) && $this->solved === 0)  		{  			$this->validate();  		} diff --git a/phpBB/phpbb/captcha/plugins/gd.php b/phpBB/phpbb/captcha/plugins/gd.php index f6200b5b2f..1727dcc1bb 100644 --- a/phpBB/phpbb/captcha/plugins/gd.php +++ b/phpBB/phpbb/captcha/plugins/gd.php @@ -53,7 +53,7 @@ class gd extends captcha_abstract  	function acp_page($id, &$module)  	{ -		global $db, $user, $auth, $template; +		global $db, $user, $auth, $template, $phpbb_log, $request;  		global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;  		$user->add_lang('acp/board'); @@ -70,21 +70,21 @@ class gd extends captcha_abstract  		$form_key = 'acp_captcha';  		add_form_key($form_key); -		$submit = request_var('submit', ''); +		$submit = $request->variable('submit', '');  		if ($submit && check_form_key($form_key))  		{  			$captcha_vars = array_keys($this->captcha_vars);  			foreach ($captcha_vars as $captcha_var)  			{ -				$value = request_var($captcha_var, 0); +				$value = $request->variable($captcha_var, 0);  				if ($value >= 0)  				{ -					set_config($captcha_var, $value); +					$config->set($captcha_var, $value);  				}  			} -			add_log('admin', 'LOG_CONFIG_VISUAL'); +			$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');  			trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action));  		}  		else if ($submit) @@ -95,7 +95,7 @@ class gd extends captcha_abstract  		{  			foreach ($this->captcha_vars as $captcha_var => $template_var)  			{ -				$var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; +				$var = (isset($_REQUEST[$captcha_var])) ? $request->variable($captcha_var, 0) : $config[$captcha_var];  				$template->assign_var($template_var, $var);  			} @@ -109,7 +109,7 @@ class gd extends captcha_abstract  	function execute_demo()  	{ -		global $config; +		global $config, $request;  		$config_old = $config; @@ -121,7 +121,7 @@ class gd extends captcha_abstract  		foreach ($this->captcha_vars as $captcha_var => $template_var)  		{ -			$config->set($captcha_var, request_var($captcha_var, (int) $config[$captcha_var])); +			$config->set($captcha_var, $request->variable($captcha_var, (int) $config[$captcha_var]));  		}  		parent::execute_demo();  		$config = $config_old; diff --git a/phpBB/phpbb/captcha/plugins/qa.php b/phpBB/phpbb/captcha/plugins/qa.php index a7ba994cc3..cf03f92e96 100644 --- a/phpBB/phpbb/captcha/plugins/qa.php +++ b/phpBB/phpbb/captcha/plugins/qa.php @@ -58,14 +58,14 @@ class qa  	*/  	function init($type)  	{ -		global $config, $db, $user; +		global $config, $db, $user, $request;  		// load our language file  		$user->add_lang('captcha_qa');  		// read input -		$this->confirm_id = request_var('qa_confirm_id', ''); -		$this->answer = utf8_normalize_nfc(request_var('qa_answer', '', true)); +		$this->confirm_id = $request->variable('qa_confirm_id', ''); +		$this->answer = $request->variable('qa_answer', '', true);  		$this->type = (int) $type;  		$this->question_lang = $user->lang_name; @@ -113,9 +113,9 @@ class qa  	*/  	public function is_installed()  	{ -		global $db; +		global $phpbb_container; -		$db_tool = new \phpbb\db\tools($db); +		$db_tool = $phpbb_container->get('dbal.tools');  		return $db_tool->sql_table_exists($this->table_captcha_questions);  	} @@ -306,11 +306,9 @@ class qa  	*/  	function install()  	{ -		global $db; - -		$db_tool = new \phpbb\db\tools($db); +		global $phpbb_container; -		$tables = array($this->table_captcha_questions, $this->table_captcha_answers, $this->table_qa_confirm); +		$db_tool = $phpbb_container->get('dbal.tools');  		$schemas = array(  				$this->table_captcha_questions		=> array ( @@ -352,7 +350,7 @@ class qa  				),  		); -		foreach($schemas as $table => $schema) +		foreach ($schemas as $table => $schema)  		{  			if (!$db_tool->sql_table_exists($table))  			{ @@ -544,9 +542,9 @@ class qa  	*/  	function check_answer()  	{ -		global $db; +		global $db, $request; -		$answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true))); +		$answer = ($this->question_strict) ? $request->variable('qa_answer', '', true) : utf8_clean_string($request->variable('qa_answer', '', true));  		$sql = 'SELECT answer_text  			FROM ' . $this->table_captcha_answers . ' @@ -598,7 +596,9 @@ class qa  	*/  	function is_solved()  	{ -		if (request_var('qa_answer', false) && $this->solved === 0) +		global $request; + +		if ($request->variable('qa_answer', false) && $this->solved === 0)  		{  			$this->validate();  		} @@ -611,7 +611,7 @@ class qa  	*/  	function acp_page($id, &$module)  	{ -		global $db, $user, $auth, $template; +		global $db, $user, $auth, $template, $phpbb_log, $request;  		global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;  		$user->add_lang('acp/board'); @@ -627,9 +627,9 @@ class qa  		$form_key = 'acp_captcha';  		add_form_key($form_key); -		$submit = request_var('submit', false); -		$question_id = request_var('question_id', 0); -		$action = request_var('action', ''); +		$submit = $request->variable('submit', false); +		$question_id = $request->variable('question_id', 0); +		$action = $request->variable('action', '');  		// we have two pages, so users might want to navigate from one to the other  		$list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_service_name(); @@ -675,10 +675,10 @@ class qa  		{  			// okay, show the editor  			$error = false; -			$input_question = request_var('question_text', '', true); -			$input_answers = request_var('answers', '', true); -			$input_lang = request_var('lang_iso', '', true); -			$input_strict = request_var('strict', false); +			$input_question = $request->variable('question_text', '', true); +			$input_answers = $request->variable('answers', '', true); +			$input_lang = $request->variable('lang_iso', '', true); +			$input_strict = $request->variable('strict', false);  			$langs = $this->get_languages();  			foreach ($langs as $lang => $entry) @@ -742,7 +742,7 @@ class qa  						$this->acp_add_question($data);  					} -					add_log('admin', 'LOG_CONFIG_VISUAL'); +					$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');  					trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url));  				}  			} @@ -826,11 +826,13 @@ class qa  	*/  	function acp_get_question_input()  	{ -		$answers = utf8_normalize_nfc(request_var('answers', '', true)); +		global $request; + +		$answers = $request->variable('answers', '', true);  		$question = array( -			'question_text'	=> request_var('question_text', '', true), -			'strict'		=> request_var('strict', false), -			'lang_iso'		=> request_var('lang_iso', ''), +			'question_text'	=> $request->variable('question_text', '', true), +			'strict'		=> $request->variable('strict', false), +			'lang_iso'		=> $request->variable('lang_iso', ''),  			'answers'		=> (strlen($answers)) ? explode("\n", $answers) : '',  		); diff --git a/phpBB/phpbb/captcha/plugins/recaptcha.php b/phpBB/phpbb/captcha/plugins/recaptcha.php index 584f3afec1..98132ab47d 100644 --- a/phpBB/phpbb/captcha/plugins/recaptcha.php +++ b/phpBB/phpbb/captcha/plugins/recaptcha.php @@ -37,12 +37,12 @@ class recaptcha extends captcha_abstract  	function init($type)  	{ -		global $config, $db, $user; +		global $config, $db, $user, $request;  		$user->add_lang('captcha_recaptcha');  		parent::init($type); -		$this->challenge = request_var('recaptcha_challenge_field', ''); -		$this->response = request_var('recaptcha_response_field', ''); +		$this->challenge = $request->variable('recaptcha_challenge_field', ''); +		$this->response = $request->variable('recaptcha_response_field', '');  	}  	public function is_available() @@ -75,7 +75,7 @@ class recaptcha extends captcha_abstract  	function acp_page($id, &$module)  	{ -		global $config, $db, $template, $user; +		global $config, $db, $template, $user, $phpbb_log, $request;  		$captcha_vars = array(  			'recaptcha_pubkey'				=> 'RECAPTCHA_PUBKEY', @@ -87,21 +87,21 @@ class recaptcha extends captcha_abstract  		$form_key = 'acp_captcha';  		add_form_key($form_key); -		$submit = request_var('submit', ''); +		$submit = $request->variable('submit', '');  		if ($submit && check_form_key($form_key))  		{  			$captcha_vars = array_keys($captcha_vars);  			foreach ($captcha_vars as $captcha_var)  			{ -				$value = request_var($captcha_var, ''); +				$value = $request->variable($captcha_var, '');  				if ($value)  				{ -					set_config($captcha_var, $value); +					$config->set($captcha_var, $value);  				}  			} -			add_log('admin', 'LOG_CONFIG_VISUAL'); +			$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');  			trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action));  		}  		else if ($submit) @@ -112,7 +112,7 @@ class recaptcha extends captcha_abstract  		{  			foreach ($captcha_vars as $captcha_var => $template_var)  			{ -				$var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : ''); +				$var = (isset($_REQUEST[$captcha_var])) ? $request->variable($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : '');  				$template->assign_var($template_var, $var);  			} diff --git a/phpBB/phpbb/composer.json b/phpBB/phpbb/composer.json index 513d7e4559..175be4b0ab 100644 --- a/phpBB/phpbb/composer.json +++ b/phpBB/phpbb/composer.json @@ -22,6 +22,6 @@  		"classmap": [""]  	},  	"require": { -		"php": ">=5.3.3" +		"php": ">=5.3.9"      }  } diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php index c6c470e91b..2790ea4277 100644 --- a/phpBB/phpbb/controller/helper.php +++ b/phpBB/phpbb/controller/helper.php @@ -14,7 +14,6 @@  namespace phpbb\controller;  use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Generator\UrlGenerator;  use Symfony\Component\Routing\Generator\UrlGeneratorInterface;  use Symfony\Component\Routing\RequestContext; @@ -41,6 +40,12 @@ class helper  	*/  	protected $config; +	/** +	 * phpBB router +	 * @var \phpbb\routing\router +	 */ +	protected $router; +  	/* @var \phpbb\symfony_request */  	protected $symfony_request; @@ -70,26 +75,24 @@ class helper  	* @param \phpbb\template\template $template Template object  	* @param \phpbb\user $user User object  	* @param \phpbb\config\config $config Config object -	* @param \phpbb\controller\provider $provider Path provider -	* @param \phpbb\extension\manager $manager Extension manager object +	* @param \phpbb\routing\router $router phpBB router  	* @param \phpbb\symfony_request $symfony_request Symfony Request object  	* @param \phpbb\request\request_interface $request phpBB request object  	* @param \phpbb\filesystem $filesystem The filesystem object  	* @param string $phpbb_root_path phpBB root path  	* @param string $php_ext PHP file extension  	*/ -	public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext) +	public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\routing\router $router, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext)  	{  		$this->template = $template;  		$this->user = $user;  		$this->config = $config; +		$this->router = $router;  		$this->symfony_request = $symfony_request;  		$this->request = $request;  		$this->filesystem = $filesystem;  		$this->phpbb_root_path = $phpbb_root_path;  		$this->php_ext = $php_ext; -		$provider->find_routing_files($manager->get_finder()); -		$this->route_collection = $provider->find($phpbb_root_path)->get_routes();  	}  	/** @@ -162,8 +165,8 @@ class helper  		$context->setBaseUrl($base_url); -		$url_generator = new UrlGenerator($this->route_collection, $context); -		$route_url = $url_generator->generate($route, $params, $reference_type); +		$this->router->setContext($context); +		$route_url = $this->router->generate($route, $params, $reference_type);  		if ($is_amp)  		{ diff --git a/phpBB/phpbb/controller/provider.php b/phpBB/phpbb/controller/provider.php deleted file mode 100644 index 7e26848290..0000000000 --- a/phpBB/phpbb/controller/provider.php +++ /dev/null @@ -1,92 +0,0 @@ -<?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\controller; - -use Symfony\Component\Routing\RouteCollection; -use Symfony\Component\Routing\Loader\YamlFileLoader; -use Symfony\Component\Config\FileLocator; - -/** -* Controller interface -*/ -class provider -{ -	/** -	* YAML file(s) containing route information -	* @var array -	*/ -	protected $routing_files; - -	/** -	* Collection of the routes in phpBB and all found extensions -	* @var RouteCollection -	*/ -	protected $routes; - -	/** -	* Construct method -	* -	* @param array $routing_files Array of strings containing paths -	*							to YAML files holding route information -	*/ -	public function __construct($routing_files = array()) -	{ -		$this->routing_files = $routing_files; -	} - -	/** -	* Find the list of routing files -	* -	* @param \phpbb\finder $finder -	* @return null -	*/ -	public function find_routing_files(\phpbb\finder $finder) -	{ -		// We hardcode the path to the core config directory -		// because the finder cannot find it -		$this->routing_files = array_merge($this->routing_files, array('config/routing.yml'), array_keys($finder -				->directory('/config') -				->suffix('routing.yml') -				->find() -		)); -	} - -	/** -	* Find a list of controllers -	* -	* @param string $base_path Base path to prepend to file paths -	* @return provider -	*/ -	public function find($base_path = '') -	{ -		$this->routes = new RouteCollection; -		foreach ($this->routing_files as $file_path) -		{ -			$loader = new YamlFileLoader(new FileLocator(phpbb_realpath($base_path))); -			$this->routes->addCollection($loader->load($file_path)); -		} - -		return $this; -	} - -	/** -	* Get the list of routes -	* -	* @return RouteCollection Get the route collection -	*/ -	public function get_routes() -	{ -		return $this->routes; -	} -} diff --git a/phpBB/phpbb/cron/task/core/prune_forum.php b/phpBB/phpbb/cron/task/core/prune_forum.php index ba68565197..abf91aee19 100644 --- a/phpBB/phpbb/cron/task/core/prune_forum.php +++ b/phpBB/phpbb/cron/task/core/prune_forum.php @@ -31,7 +31,7 @@ class prune_forum extends \phpbb\cron\task\base implements \phpbb\cron\task\para  	* If $forum_data is given, it is assumed to contain necessary information  	* about a single forum that is to be pruned.  	* -	* If $forum_data is not given, forum id will be retrieved via request_var +	* If $forum_data is not given, forum id will be retrieved via $request->variable()  	* and a database query will be performed to load the necessary information  	* about the forum.  	*/ diff --git a/phpBB/phpbb/cron/task/core/prune_shadow_topics.php b/phpBB/phpbb/cron/task/core/prune_shadow_topics.php index 97a4b0ea86..0ab59f9ed5 100644 --- a/phpBB/phpbb/cron/task/core/prune_shadow_topics.php +++ b/phpBB/phpbb/cron/task/core/prune_shadow_topics.php @@ -33,7 +33,7 @@ class prune_shadow_topics extends \phpbb\cron\task\base implements \phpbb\cron\t  	* If $forum_data is given, it is assumed to contain necessary information  	* about a single forum that is to be pruned.  	* -	* If $forum_data is not given, forum id will be retrieved via request_var +	* If $forum_data is not given, forum id will be retrieved via $request->variable()  	* and a database query will be performed to load the necessary information  	* about the forum.  	*/ diff --git a/phpBB/phpbb/cron/task/core/tidy_plupload.php b/phpBB/phpbb/cron/task/core/tidy_plupload.php index b6aeecf4b4..d7364374af 100644 --- a/phpBB/phpbb/cron/task/core/tidy_plupload.php +++ b/phpBB/phpbb/cron/task/core/tidy_plupload.php @@ -67,6 +67,8 @@ class tidy_plupload extends \phpbb\cron\task\base  	*/  	public function run()  	{ +		global $user, $phpbb_log; +  		// Remove old temporary file (perhaps failed uploads?)  		$last_valid_timestamp = time() - $this->max_file_age;  		try @@ -88,13 +90,11 @@ class tidy_plupload extends \phpbb\cron\task\base  		}  		catch (\UnexpectedValueException $e)  		{ -			add_log( -				'critical', -				'LOG_PLUPLOAD_TIDY_FAILED', +			$phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_PLUPLOAD_TIDY_FAILED', false, array(  				$this->plupload_upload_path,  				$e->getMessage(),  				$e->getTraceAsString() -			); +			));  		}  		$this->config->set('plupload_last_gc', time(), true); diff --git a/phpBB/phpbb/db/driver/driver.php b/phpBB/phpbb/db/driver/driver.php index 9fc04d47a1..8d360fc3e2 100644 --- a/phpBB/phpbb/db/driver/driver.php +++ b/phpBB/phpbb/db/driver/driver.php @@ -271,7 +271,7 @@ abstract class driver implements driver_interface  			$query_id = $this->query_result;  		} -		if ($query_id !== false) +		if ($query_id)  		{  			$result = array();  			while ($row = $this->sql_fetchrow($query_id)) @@ -302,7 +302,7 @@ abstract class driver implements driver_interface  			return $cache->sql_rowseek($rownum, $query_id);  		} -		if ($query_id === false) +		if (!$query_id)  		{  			return false;  		} @@ -310,7 +310,7 @@ abstract class driver implements driver_interface  		$this->sql_freeresult($query_id);  		$query_id = $this->sql_query($this->last_query_text); -		if ($query_id === false) +		if (!$query_id)  		{  			return false;  		} @@ -339,7 +339,7 @@ abstract class driver implements driver_interface  			$query_id = $this->query_result;  		} -		if ($query_id !== false) +		if ($query_id)  		{  			if ($rownum !== false)  			{ @@ -363,8 +363,8 @@ abstract class driver implements driver_interface  	*/  	function sql_like_expression($expression)  	{ -		$expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); -		$expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); +		$expression = str_replace(array('_', '%'), array("\_", "\%"), $expression); +		$expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);  		return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\'');  	} @@ -374,8 +374,8 @@ abstract class driver implements driver_interface  	*/  	function sql_not_like_expression($expression)  	{ -		$expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); -		$expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); +		$expression = str_replace(array('_', '%'), array("\_", "\%"), $expression); +		$expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);  		return $this->_sql_not_like_expression('NOT LIKE \'' . $this->sql_escape($expression) . '\'');  	} diff --git a/phpBB/phpbb/db/driver/mssql.php b/phpBB/phpbb/db/driver/mssql.php index f9ea884ce2..dfdbfe15e6 100644 --- a/phpBB/phpbb/db/driver/mssql.php +++ b/phpBB/phpbb/db/driver/mssql.php @@ -71,8 +71,8 @@ class mssql extends \phpbb\db\driver\driver  			$row = false;  			if ($result_id)  			{ -				$row = @mssql_fetch_assoc($result_id); -				@mssql_free_result($result_id); +				$row = mssql_fetch_assoc($result_id); +				mssql_free_result($result_id);  			}  			$this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; @@ -161,12 +161,17 @@ class mssql extends \phpbb\db\driver\driver  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);  				} -				else if (strpos($query, 'SELECT') === 0 && $this->query_result) +				else if (strpos($query, 'SELECT') === 0 && $this->query_result !== true)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  				} @@ -241,12 +246,12 @@ class mssql extends \phpbb\db\driver\driver  			return $cache->sql_fetchrow($query_id);  		} -		if ($query_id === false) +		if (!$query_id || $query_id === true)  		{  			return false;  		} -		$row = @mssql_fetch_assoc($query_id); +		$row = mssql_fetch_assoc($query_id);  		// I hope i am able to remove this later... hopefully only a PHP or MSSQL bug  		if ($row) @@ -272,12 +277,17 @@ class mssql extends \phpbb\db\driver\driver  			$query_id = $this->query_result;  		} +		if ($query_id === true) +		{ +			return false; +		} +  		if ($cache && $cache->sql_exists($query_id))  		{  			return $cache->sql_rowseek($rownum, $query_id);  		} -		return ($query_id !== false) ? @mssql_data_seek($query_id, $rownum) : false; +		return ($query_id) ? @mssql_data_seek($query_id, $rownum) : false;  	}  	/** @@ -288,12 +298,12 @@ class mssql extends \phpbb\db\driver\driver  		$result_id = @mssql_query('SELECT SCOPE_IDENTITY()', $this->db_connect_id);  		if ($result_id)  		{ -			if ($row = @mssql_fetch_assoc($result_id)) +			if ($row = mssql_fetch_assoc($result_id))  			{ -				@mssql_free_result($result_id); +				mssql_free_result($result_id);  				return $row['computed'];  			} -			@mssql_free_result($result_id); +			mssql_free_result($result_id);  		}  		return false; @@ -311,6 +321,11 @@ class mssql extends \phpbb\db\driver\driver  			$query_id = $this->query_result;  		} +		if ($query_id === true) +		{ +			return false; +		} +  		if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))  		{  			return $cache->sql_freeresult($query_id); @@ -319,7 +334,7 @@ class mssql extends \phpbb\db\driver\driver  		if (isset($this->open_queries[(int) $query_id]))  		{  			unset($this->open_queries[(int) $query_id]); -			return @mssql_free_result($query_id); +			return mssql_free_result($query_id);  		}  		return false; @@ -376,9 +391,9 @@ class mssql extends \phpbb\db\driver\driver  			$result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id);  			if ($result_id)  			{ -				$row = @mssql_fetch_assoc($result_id); +				$row = mssql_fetch_assoc($result_id);  				$error['code'] = $row['code']; -				@mssql_free_result($result_id); +				mssql_free_result($result_id);  			}  			// Get full error message if possible @@ -389,12 +404,12 @@ class mssql extends \phpbb\db\driver\driver  			if ($result_id)  			{ -				$row = @mssql_fetch_assoc($result_id); +				$row = mssql_fetch_assoc($result_id);  				if (!empty($row['message']))  				{  					$error['message'] .= '<br />' . $row['message'];  				} -				@mssql_free_result($result_id); +				mssql_free_result($result_id);  			}  		}  		else @@ -440,13 +455,13 @@ class mssql extends \phpbb\db\driver\driver  				if ($result = @mssql_query($query, $this->db_connect_id))  				{  					@mssql_next_result($result); -					while ($row = @mssql_fetch_row($result)) +					while ($row = mssql_fetch_row($result))  					{  						$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);  					}  				}  				@mssql_query('SET SHOWPLAN_TEXT OFF;', $this->db_connect_id); -				@mssql_free_result($result); +				mssql_free_result($result);  				if ($html_table)  				{ @@ -459,11 +474,14 @@ class mssql extends \phpbb\db\driver\driver  				$endtime = $endtime[0] + $endtime[1];  				$result = @mssql_query($query, $this->db_connect_id); -				while ($void = @mssql_fetch_assoc($result)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +					while ($void = mssql_fetch_assoc($result)) +					{ +						// Take the time spent on parsing rows into account +					} +					mssql_free_result($result);  				} -				@mssql_free_result($result);  				$splittime = explode(' ', microtime());  				$splittime = $splittime[0] + $splittime[1]; diff --git a/phpBB/phpbb/db/driver/mssql_odbc.php b/phpBB/phpbb/db/driver/mssql_odbc.php index 8e5d4c7a4c..9d9ad603e0 100644 --- a/phpBB/phpbb/db/driver/mssql_odbc.php +++ b/phpBB/phpbb/db/driver/mssql_odbc.php @@ -98,8 +98,8 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base  			$row = false;  			if ($result_id)  			{ -				$row = @odbc_fetch_array($result_id); -				@odbc_free_result($result_id); +				$row = odbc_fetch_array($result_id); +				odbc_free_result($result_id);  			}  			$this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; @@ -181,12 +181,17 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);  				} -				else if (strpos($query, 'SELECT') === 0 && $this->query_result) +				else if (strpos($query, 'SELECT') === 0)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  				} @@ -261,7 +266,7 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base  			return $cache->sql_fetchrow($query_id);  		} -		return ($query_id !== false) ? @odbc_fetch_array($query_id) : false; +		return ($query_id) ? odbc_fetch_array($query_id) : false;  	}  	/** @@ -273,13 +278,13 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base  		if ($result_id)  		{ -			if (@odbc_fetch_array($result_id)) +			if (odbc_fetch_array($result_id))  			{ -				$id = @odbc_result($result_id, 1); -				@odbc_free_result($result_id); +				$id = odbc_result($result_id, 1); +				odbc_free_result($result_id);  				return $id;  			} -			@odbc_free_result($result_id); +			odbc_free_result($result_id);  		}  		return false; @@ -305,7 +310,7 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base  		if (isset($this->open_queries[(int) $query_id]))  		{  			unset($this->open_queries[(int) $query_id]); -			return @odbc_free_result($query_id); +			return odbc_free_result($query_id);  		}  		return false; @@ -360,11 +365,14 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base  				$endtime = $endtime[0] + $endtime[1];  				$result = @odbc_exec($this->db_connect_id, $query); -				while ($void = @odbc_fetch_array($result)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +					while ($void = odbc_fetch_array($result)) +					{ +						// Take the time spent on parsing rows into account +					} +					odbc_free_result($result);  				} -				@odbc_free_result($result);  				$splittime = explode(' ', microtime());  				$splittime = $splittime[0] + $splittime[1]; diff --git a/phpBB/phpbb/db/driver/mssqlnative.php b/phpBB/phpbb/db/driver/mssqlnative.php index 46a9b3a477..50dce35baa 100644 --- a/phpBB/phpbb/db/driver/mssqlnative.php +++ b/phpBB/phpbb/db/driver/mssqlnative.php @@ -154,12 +154,17 @@ class mssqlnative extends \phpbb\db\driver\mssql_base  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);  				} -				else if (strpos($query, 'SELECT') === 0 && $this->query_result) +				else if (strpos($query, 'SELECT') === 0)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  				} @@ -242,12 +247,12 @@ class mssqlnative extends \phpbb\db\driver\mssql_base  			return $cache->sql_fetchrow($query_id);  		} -		if ($query_id === false) +		if (!$query_id)  		{  			return false;  		} -		$row = @sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC); +		$row = sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC);  		if ($row)  		{ @@ -272,11 +277,11 @@ class mssqlnative extends \phpbb\db\driver\mssql_base  	{  		$result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY'); -		if ($result_id !== false) +		if ($result_id)  		{ -			$row = @sqlsrv_fetch_array($result_id); +			$row = sqlsrv_fetch_array($result_id);  			$id = $row[0]; -			@sqlsrv_free_stmt($result_id); +			sqlsrv_free_stmt($result_id);  			return $id;  		}  		else @@ -305,7 +310,7 @@ class mssqlnative extends \phpbb\db\driver\mssql_base  		if (isset($this->open_queries[(int) $query_id]))  		{  			unset($this->open_queries[(int) $query_id]); -			return @sqlsrv_free_stmt($query_id); +			return sqlsrv_free_stmt($query_id);  		}  		return false; @@ -378,14 +383,14 @@ class mssqlnative extends \phpbb\db\driver\mssql_base  				@sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;');  				if ($result = @sqlsrv_query($this->db_connect_id, $query))  				{ -					@sqlsrv_next_result($result); -					while ($row = @sqlsrv_fetch_array($result)) +					sqlsrv_next_result($result); +					while ($row = sqlsrv_fetch_array($result))  					{  						$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);  					} +					sqlsrv_free_stmt($result);  				}  				@sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;'); -				@sqlsrv_free_stmt($result);  				if ($html_table)  				{ @@ -398,11 +403,14 @@ class mssqlnative extends \phpbb\db\driver\mssql_base  				$endtime = $endtime[0] + $endtime[1];  				$result = @sqlsrv_query($this->db_connect_id, $query); -				while ($void = @sqlsrv_fetch_array($result)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +					while ($void = sqlsrv_fetch_array($result)) +					{ +						// Take the time spent on parsing rows into account +					} +					sqlsrv_free_stmt($result);  				} -				@sqlsrv_free_stmt($result);  				$splittime = explode(' ', microtime());  				$splittime = $splittime[0] + $splittime[1]; diff --git a/phpBB/phpbb/db/driver/mysql.php b/phpBB/phpbb/db/driver/mysql.php index e93c7239e8..a94e88b331 100644 --- a/phpBB/phpbb/db/driver/mysql.php +++ b/phpBB/phpbb/db/driver/mysql.php @@ -70,9 +70,16 @@ class mysql extends \phpbb\db\driver\mysql_base  					if (version_compare($this->sql_server_info(true), '5.0.2', '>='))  					{  						$result = @mysql_query('SELECT @@session.sql_mode AS sql_mode', $this->db_connect_id); -						$row = @mysql_fetch_assoc($result); -						@mysql_free_result($result); -						$modes = array_map('trim', explode(',', $row['sql_mode'])); +						if ($result) +						{ +							$row = mysql_fetch_assoc($result); +							mysql_free_result($result); +							$modes = array_map('trim', explode(',', $row['sql_mode'])); +						} +						else +						{ +							$modes = array(); +						}  						// TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES  						if (!in_array('TRADITIONAL', $modes)) @@ -114,14 +121,17 @@ class mysql extends \phpbb\db\driver\mysql_base  		if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false)  		{  			$result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id); -			$row = @mysql_fetch_assoc($result); -			@mysql_free_result($result); +			if ($result) +			{ +				$row = mysql_fetch_assoc($result); +				mysql_free_result($result); -			$this->sql_server_version = $row['version']; +				$this->sql_server_version = $row['version']; -			if (!empty($cache) && $use_cache) -			{ -				$cache->put('mysql_version', $this->sql_server_version); +				if (!empty($cache) && $use_cache) +				{ +					$cache->put('mysql_version', $this->sql_server_version); +				}  			}  		} @@ -190,12 +200,17 @@ class mysql extends \phpbb\db\driver\mysql_base  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);  				} -				else if (strpos($query, 'SELECT') === 0 && $this->query_result) +				else if (strpos($query, 'SELECT') === 0)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  				} @@ -257,7 +272,7 @@ class mysql extends \phpbb\db\driver\mysql_base  			return $cache->sql_fetchrow($query_id);  		} -		return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false; +		return ($query_id) ? mysql_fetch_assoc($query_id) : false;  	}  	/** @@ -308,7 +323,7 @@ class mysql extends \phpbb\db\driver\mysql_base  		if (isset($this->open_queries[(int) $query_id]))  		{  			unset($this->open_queries[(int) $query_id]); -			return @mysql_free_result($query_id); +			return mysql_free_result($query_id);  		}  		return false; @@ -411,12 +426,12 @@ class mysql extends \phpbb\db\driver\mysql_base  					if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id))  					{ -						while ($row = @mysql_fetch_assoc($result)) +						while ($row = mysql_fetch_assoc($result))  						{  							$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);  						} +						mysql_free_result($result);  					} -					@mysql_free_result($result);  					if ($html_table)  					{ @@ -431,7 +446,7 @@ class mysql extends \phpbb\db\driver\mysql_base  						if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id))  						{  							$this->html_hold .= '<br />'; -							while ($row = @mysql_fetch_assoc($result)) +							while ($row = mysql_fetch_assoc($result))  							{  								// make <unknown> HTML safe  								if (!empty($row['Source_function'])) @@ -449,8 +464,8 @@ class mysql extends \phpbb\db\driver\mysql_base  								}  								$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);  							} +							mysql_free_result($result);  						} -						@mysql_free_result($result);  						if ($html_table)  						{ @@ -468,11 +483,14 @@ class mysql extends \phpbb\db\driver\mysql_base  				$endtime = $endtime[0] + $endtime[1];  				$result = @mysql_query($query, $this->db_connect_id); -				while ($void = @mysql_fetch_assoc($result)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +					while ($void = mysql_fetch_assoc($result)) +					{ +						// Take the time spent on parsing rows into account +					} +					mysql_free_result($result);  				} -				@mysql_free_result($result);  				$splittime = explode(' ', microtime());  				$splittime = $splittime[0] + $splittime[1]; diff --git a/phpBB/phpbb/db/driver/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php index c0ddfbf76c..d43e201526 100644 --- a/phpBB/phpbb/db/driver/mysqli.php +++ b/phpBB/phpbb/db/driver/mysqli.php @@ -74,9 +74,10 @@ class mysqli extends \phpbb\db\driver\mysql_base  			if (version_compare($this->sql_server_info(true), '5.0.2', '>='))  			{  				$result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode'); -				if ($result !== null) +				if ($result)  				{ -					$row = @mysqli_fetch_assoc($result); +					$row = mysqli_fetch_assoc($result); +					mysqli_free_result($result);  					$modes = array_map('trim', explode(',', $row['sql_mode']));  				} @@ -84,7 +85,6 @@ class mysqli extends \phpbb\db\driver\mysql_base  				{  					$modes = array();  				} -				@mysqli_free_result($result);  				// TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES  				if (!in_array('TRADITIONAL', $modes)) @@ -119,9 +119,10 @@ class mysqli extends \phpbb\db\driver\mysql_base  		if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false)  		{  			$result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version'); -			if ($result !== null) +			if ($result)  			{ -				$row = @mysqli_fetch_assoc($result); +				$row = mysqli_fetch_assoc($result); +				mysqli_free_result($result);  				$this->sql_server_version = $row['version']; @@ -130,7 +131,6 @@ class mysqli extends \phpbb\db\driver\mysql_base  					$cache->put('mysqli_version', $this->sql_server_version);  				}  			} -			@mysqli_free_result($result);  		}  		return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version; @@ -202,6 +202,11 @@ class mysqli extends \phpbb\db\driver\mysql_base  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); @@ -245,9 +250,9 @@ class mysqli extends \phpbb\db\driver\mysql_base  			return $cache->sql_fetchrow($query_id);  		} -		if ($query_id !== false && $query_id !== null) +		if ($query_id)  		{ -			$result = @mysqli_fetch_assoc($query_id); +			$result = mysqli_fetch_assoc($query_id);  			return $result !== null ? $result : false;  		} @@ -271,7 +276,7 @@ class mysqli extends \phpbb\db\driver\mysql_base  			return $cache->sql_rowseek($rownum, $query_id);  		} -		return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false; +		return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false;  	}  	/** @@ -299,7 +304,17 @@ class mysqli extends \phpbb\db\driver\mysql_base  			return $cache->sql_freeresult($query_id);  		} -		return @mysqli_free_result($query_id); +		if (!$query_id) +		{ +			return false; +		} + +		if ($query_id === true) +		{ +			return true; +		} + +		return mysqli_free_result($query_id);  	}  	/** @@ -398,12 +413,12 @@ class mysqli extends \phpbb\db\driver\mysql_base  					if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query"))  					{ -						while ($row = @mysqli_fetch_assoc($result)) +						while ($row = mysqli_fetch_assoc($result))  						{  							$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);  						} +						mysqli_free_result($result);  					} -					@mysqli_free_result($result);  					if ($html_table)  					{ @@ -418,7 +433,7 @@ class mysqli extends \phpbb\db\driver\mysql_base  						if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;'))  						{  							$this->html_hold .= '<br />'; -							while ($row = @mysqli_fetch_assoc($result)) +							while ($row = mysqli_fetch_assoc($result))  							{  								// make <unknown> HTML safe  								if (!empty($row['Source_function'])) @@ -436,8 +451,8 @@ class mysqli extends \phpbb\db\driver\mysql_base  								}  								$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);  							} +							mysqli_free_result($result);  						} -						@mysqli_free_result($result);  						if ($html_table)  						{ @@ -455,14 +470,14 @@ class mysqli extends \phpbb\db\driver\mysql_base  				$endtime = $endtime[0] + $endtime[1];  				$result = @mysqli_query($this->db_connect_id, $query); -				if ($result !== null) +				if ($result)  				{ -					while ($void = @mysqli_fetch_assoc($result)) +					while ($void = mysqli_fetch_assoc($result))  					{  						// Take the time spent on parsing rows into account  					} +					mysqli_free_result($result);  				} -				@mysqli_free_result($result);  				$splittime = explode(' ', microtime());  				$splittime = $splittime[0] + $splittime[1]; diff --git a/phpBB/phpbb/db/driver/oracle.php b/phpBB/phpbb/db/driver/oracle.php index 6dcab5dd7d..89e1b68aac 100644 --- a/phpBB/phpbb/db/driver/oracle.php +++ b/phpBB/phpbb/db/driver/oracle.php @@ -439,12 +439,17 @@ class oracle extends \phpbb\db\driver\driver  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);  				} -				else if (strpos($query, 'SELECT') === 0 && $this->query_result) +				else if (strpos($query, 'SELECT') === 0)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  				} @@ -499,10 +504,10 @@ class oracle extends \phpbb\db\driver\driver  			return $cache->sql_fetchrow($query_id);  		} -		if ($query_id !== false) +		if ($query_id)  		{  			$row = array(); -			$result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); +			$result = ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);  			if (!$result || !$row)  			{ @@ -550,7 +555,7 @@ class oracle extends \phpbb\db\driver\driver  			return $cache->sql_rowseek($rownum, $query_id);  		} -		if ($query_id === false) +		if (!$query_id)  		{  			return false;  		} @@ -583,18 +588,24 @@ class oracle extends \phpbb\db\driver\driver  			{  				$query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';  				$stmt = @ociparse($this->db_connect_id, $query); -				@ociexecute($stmt, OCI_DEFAULT); +				if ($stmt) +				{ +					$success = @ociexecute($stmt, OCI_DEFAULT); -				$temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS); -				@ocifreestatement($stmt); +					if ($success) +					{ +						$temp_result = ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS); +						ocifreestatement($stmt); -				if ($temp_result) -				{ -					return $temp_array['CURRVAL']; -				} -				else -				{ -					return false; +						if ($temp_result) +						{ +							return $temp_array['CURRVAL']; +						} +						else +						{ +							return false; +						} +					}  				}  			}  		} @@ -622,7 +633,7 @@ class oracle extends \phpbb\db\driver\driver  		if (isset($this->open_queries[(int) $query_id]))  		{  			unset($this->open_queries[(int) $query_id]); -			return @ocifreestatement($query_id); +			return ocifreestatement($query_id);  		}  		return false; @@ -787,14 +798,20 @@ class oracle extends \phpbb\db\driver\driver  				$endtime = $endtime[0] + $endtime[1];  				$result = @ociparse($this->db_connect_id, $query); -				$success = @ociexecute($result, OCI_DEFAULT); -				$row = array(); - -				while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +					$success = @ociexecute($result, OCI_DEFAULT); +					if ($success) +					{ +						$row = array(); + +						while (ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS)) +						{ +							// Take the time spent on parsing rows into account +						} +						@ocifreestatement($result); +					}  				} -				@ocifreestatement($result);  				$splittime = explode(' ', microtime());  				$splittime = $splittime[0] + $splittime[1]; diff --git a/phpBB/phpbb/db/driver/postgres.php b/phpBB/phpbb/db/driver/postgres.php index a3b9aa4c6b..44476612c3 100644 --- a/phpBB/phpbb/db/driver/postgres.php +++ b/phpBB/phpbb/db/driver/postgres.php @@ -123,14 +123,17 @@ class postgres extends \phpbb\db\driver\driver  		if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false)  		{  			$query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version'); -			$row = @pg_fetch_assoc($query_id, null); -			@pg_free_result($query_id); +			if ($query_id) +			{ +				$row = pg_fetch_assoc($query_id, null); +				pg_free_result($query_id); -			$this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0; +				$this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0; -			if (!empty($cache) && $use_cache) -			{ -				$cache->put('pgsql_version', $this->sql_server_version); +				if (!empty($cache) && $use_cache) +				{ +					$cache->put('pgsql_version', $this->sql_server_version); +				}  			}  		} @@ -200,12 +203,17 @@ class postgres extends \phpbb\db\driver\driver  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);  				} -				else if (strpos($query, 'SELECT') === 0 && $this->query_result) +				else if (strpos($query, 'SELECT') === 0)  				{  					$this->open_queries[(int) $this->query_result] = $this->query_result;  				} @@ -275,7 +283,7 @@ class postgres extends \phpbb\db\driver\driver  			return $cache->sql_fetchrow($query_id);  		} -		return ($query_id !== false) ? @pg_fetch_assoc($query_id, null) : false; +		return ($query_id) ? pg_fetch_assoc($query_id, null) : false;  	}  	/** @@ -295,7 +303,7 @@ class postgres extends \phpbb\db\driver\driver  			return $cache->sql_rowseek($rownum, $query_id);  		} -		return ($query_id !== false) ? @pg_result_seek($query_id, $rownum) : false; +		return ($query_id) ? @pg_result_seek($query_id, $rownum) : false;  	}  	/** @@ -317,8 +325,8 @@ class postgres extends \phpbb\db\driver\driver  					return false;  				} -				$temp_result = @pg_fetch_assoc($temp_q_id, null); -				@pg_free_result($query_id); +				$temp_result = pg_fetch_assoc($temp_q_id, null); +				pg_free_result($query_id);  				return ($temp_result) ? $temp_result['last_value'] : false;  			} @@ -347,7 +355,7 @@ class postgres extends \phpbb\db\driver\driver  		if (isset($this->open_queries[(int) $query_id]))  		{  			unset($this->open_queries[(int) $query_id]); -			return @pg_free_result($query_id); +			return pg_free_result($query_id);  		}  		return false; @@ -453,12 +461,12 @@ class postgres extends \phpbb\db\driver\driver  					if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query"))  					{ -						while ($row = @pg_fetch_assoc($result, null)) +						while ($row = pg_fetch_assoc($result, null))  						{  							$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);  						} +						pg_free_result($result);  					} -					@pg_free_result($result);  					if ($html_table)  					{ @@ -473,11 +481,14 @@ class postgres extends \phpbb\db\driver\driver  				$endtime = $endtime[0] + $endtime[1];  				$result = @pg_query($this->db_connect_id, $query); -				while ($void = @pg_fetch_assoc($result, null)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +					while ($void = pg_fetch_assoc($result, null)) +					{ +						// Take the time spent on parsing rows into account +					} +					pg_free_result($result);  				} -				@pg_free_result($result);  				$splittime = explode(' ', microtime());  				$splittime = $splittime[0] + $splittime[1]; diff --git a/phpBB/phpbb/db/driver/sqlite.php b/phpBB/phpbb/db/driver/sqlite.php index d5da0e2438..8e205ebb81 100644 --- a/phpBB/phpbb/db/driver/sqlite.php +++ b/phpBB/phpbb/db/driver/sqlite.php @@ -70,13 +70,16 @@ class sqlite extends \phpbb\db\driver\driver  		if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false)  		{  			$result = @sqlite_query('SELECT sqlite_version() AS version', $this->db_connect_id); -			$row = @sqlite_fetch_array($result, SQLITE_ASSOC); +			if ($result) +			{ +				$row = sqlite_fetch_array($result, SQLITE_ASSOC); -			$this->sql_server_version = (!empty($row['version'])) ? $row['version'] : 0; +				$this->sql_server_version = (!empty($row['version'])) ? $row['version'] : 0; -			if (!empty($cache) && $use_cache) -			{ -				$cache->put('sqlite_version', $this->sql_server_version); +				if (!empty($cache) && $use_cache) +				{ +					$cache->put('sqlite_version', $this->sql_server_version); +				}  			}  		} @@ -145,14 +148,14 @@ class sqlite extends \phpbb\db\driver\driver  					$this->sql_time += microtime(true) - $this->curtime;  				} -				if ($cache && $cache_ttl) +				if (!$this->query_result)  				{ -					$this->open_queries[(int) $this->query_result] = $this->query_result; -					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); +					return false;  				} -				else if (strpos($query, 'SELECT') === 0 && $this->query_result) + +				if ($cache && $cache_ttl)  				{ -					$this->open_queries[(int) $this->query_result] = $this->query_result; +					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);  				}  			}  			else if (defined('DEBUG')) @@ -211,7 +214,7 @@ class sqlite extends \phpbb\db\driver\driver  			return $cache->sql_fetchrow($query_id);  		} -		return ($query_id !== false) ? @sqlite_fetch_array($query_id, SQLITE_ASSOC) : false; +		return ($query_id) ? sqlite_fetch_array($query_id, SQLITE_ASSOC) : false;  	}  	/** @@ -231,7 +234,7 @@ class sqlite extends \phpbb\db\driver\driver  			return $cache->sql_rowseek($rownum, $query_id);  		} -		return ($query_id !== false) ? @sqlite_seek($query_id, $rownum) : false; +		return ($query_id) ? @sqlite_seek($query_id, $rownum) : false;  	}  	/** @@ -362,9 +365,12 @@ class sqlite extends \phpbb\db\driver\driver  				$endtime = $endtime[0] + $endtime[1];  				$result = @sqlite_query($query, $this->db_connect_id); -				while ($void = @sqlite_fetch_array($result, SQLITE_ASSOC)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +					while ($void = sqlite_fetch_array($result, SQLITE_ASSOC)) +					{ +						// Take the time spent on parsing rows into account +					}  				}  				$splittime = explode(' ', microtime()); diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php index 4e3e0d3329..f5c2dd225b 100644 --- a/phpBB/phpbb/db/driver/sqlite3.php +++ b/phpBB/phpbb/db/driver/sqlite3.php @@ -147,6 +147,11 @@ class sqlite3 extends \phpbb\db\driver\driver  					$this->sql_time += microtime(true) - $this->curtime;  				} +				if (!$this->query_result) +				{ +					return false; +				} +  				if ($cache && $cache_ttl)  				{  					$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); @@ -388,9 +393,12 @@ class sqlite3 extends \phpbb\db\driver\driver  				$endtime = $endtime[0] + $endtime[1];  				$result = $this->dbo->query($query); -				while ($void = $result->fetchArray(SQLITE3_ASSOC)) +				if ($result)  				{ -					// Take the time spent on parsing rows into account +						while ($void = $result->fetchArray(SQLITE3_ASSOC)) +						{ +							// Take the time spent on parsing rows into account +						}  				}  				$splittime = explode(' ', microtime()); diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php index 003ccf8f18..9f6e3efb91 100644 --- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php @@ -57,7 +57,9 @@ class release_3_0_5_rc1 extends container_aware_migration  	public function hash_old_passwords()  	{ +		/* @var $passwords_manager \phpbb\passwords\manager */  		$passwords_manager = $this->container->get('passwords.manager'); +  		$sql = 'SELECT user_id, user_password  				FROM ' . $this->table_prefix . 'users  				WHERE user_pass_convert = 1'; diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php index 06e46d522f..5f928df47c 100644 --- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php @@ -34,7 +34,7 @@ class release_3_0_9_rc1 extends \phpbb\db\migration\migration  						// this column was removed from the database updater  						// after 3.0.9-RC3 was released. It might still exist  						// in 3.0.9-RCX installations and has to be dropped as -						// soon as the db_tools class is capable of properly +						// soon as the \phpbb\db\tools\tools class is capable of properly  						// removing a primary key.  						// 'attempt_id'			=> array('UINT', NULL, 'auto_increment'),  						'attempt_ip'			=> array('VCHAR:40', ''), diff --git a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php index e8d3a3af64..918a565e06 100644 --- a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php +++ b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php @@ -62,6 +62,8 @@ class style_update_p1 extends \phpbb\db\migration\migration  	public function styles_update()  	{ +		global $config; +  		// Get list of valid 3.1 styles  		$available_styles = array('prosilver'); @@ -163,7 +165,7 @@ class style_update_p1 extends \phpbb\db\migration\migration  			$default_style = $this->db->sql_fetchfield($result);  			$this->db->sql_freeresult($result); -			set_config('default_style', $default_style); +			$config->set('default_style', $default_style);  			$sql = 'UPDATE ' . USERS_TABLE . ' SET user_style = 0';  			$this->sql_query($sql); diff --git a/phpBB/phpbb/db/migration/migration.php b/phpBB/phpbb/db/migration/migration.php index 5f120333e1..2304c8e44c 100644 --- a/phpBB/phpbb/db/migration/migration.php +++ b/phpBB/phpbb/db/migration/migration.php @@ -28,7 +28,7 @@ abstract class migration  	/** @var \phpbb\db\driver\driver_interface */  	protected $db; -	/** @var \phpbb\db\tools */ +	/** @var \phpbb\db\tools\tools_interface */  	protected $db_tools;  	/** @var string */ @@ -51,12 +51,12 @@ abstract class migration  	*  	* @param \phpbb\config\config $config  	* @param \phpbb\db\driver\driver_interface $db -	* @param \phpbb\db\tools $db_tools +	* @param \phpbb\db\tools\tools_interface $db_tools  	* @param string $phpbb_root_path  	* @param string $php_ext  	* @param string $table_prefix  	*/ -	public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $phpbb_root_path, $php_ext, $table_prefix) +	public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools\tools_interface $db_tools, $phpbb_root_path, $php_ext, $table_prefix)  	{  		$this->config = $config;  		$this->db = $db; diff --git a/phpBB/phpbb/db/migration/profilefield_base_migration.php b/phpBB/phpbb/db/migration/profilefield_base_migration.php index da1a38e2fa..3f26a4998c 100644 --- a/phpBB/phpbb/db/migration/profilefield_base_migration.php +++ b/phpBB/phpbb/db/migration/profilefield_base_migration.php @@ -237,6 +237,7 @@ abstract class profilefield_base_migration extends container_aware_migration  		if ($profile_row === null)  		{ +			/* @var $manager \phpbb\profilefields\manager */  			$manager = $this->container->get('profilefields.manager');  			$profile_row = $manager->build_insert_sql_array(array());  		} diff --git a/phpBB/phpbb/db/migration/schema_generator.php b/phpBB/phpbb/db/migration/schema_generator.php index 91d8307d91..7003844bc4 100644 --- a/phpBB/phpbb/db/migration/schema_generator.php +++ b/phpBB/phpbb/db/migration/schema_generator.php @@ -24,7 +24,7 @@ class schema_generator  	/** @var \phpbb\db\driver\driver_interface */  	protected $db; -	/** @var \phpbb\db\tools */ +	/** @var \phpbb\db\tools\tools_interface */  	protected $db_tools;  	/** @var array */ @@ -48,7 +48,7 @@ class schema_generator  	/**  	* Constructor  	*/ -	public function __construct(array $class_names, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $phpbb_root_path, $php_ext, $table_prefix) +	public function __construct(array $class_names, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools\tools_interface $db_tools, $phpbb_root_path, $php_ext, $table_prefix)  	{  		$this->config = $config;  		$this->db = $db; diff --git a/phpBB/phpbb/db/migration/tool/module.php b/phpBB/phpbb/db/migration/tool/module.php index 035625b095..b6f0372181 100644 --- a/phpBB/phpbb/db/migration/tool/module.php +++ b/phpBB/phpbb/db/migration/tool/module.php @@ -171,6 +171,8 @@ class module implements \phpbb\db\migration\tool\tool_interface  	*/  	public function add($class, $parent = 0, $data = array())  	{ +		global $user, $phpbb_log; +  		// Allows '' to be sent as 0  		$parent = $parent ?: 0; @@ -266,7 +268,7 @@ class module implements \phpbb\db\migration\tool\tool_interface  		{  			// 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); +			$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_ADD', false, array($module_log_name));  			// Move the module if requested above/below an existing one  			if (isset($data['before']) && $data['before']) diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php index 7fc3e787e2..6902913c64 100644 --- a/phpBB/phpbb/db/migrator.php +++ b/phpBB/phpbb/db/migrator.php @@ -32,7 +32,7 @@ class migrator  	/** @var \phpbb\db\driver\driver_interface */  	protected $db; -	/** @var \phpbb\db\tools */ +	/** @var \phpbb\db\tools\tools_interface */  	protected $db_tools;  	/** @var \phpbb\db\migration\helper */ @@ -92,7 +92,7 @@ class migrator  	/**  	* Constructor of the database migrator  	*/ -	public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $migrations_table, $phpbb_root_path, $php_ext, $table_prefix, $tools, \phpbb\db\migration\helper $helper) +	public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools\tools_interface $db_tools, $migrations_table, $phpbb_root_path, $php_ext, $table_prefix, $tools, \phpbb\db\migration\helper $helper)  	{  		$this->container = $container;  		$this->config = $config; diff --git a/phpBB/phpbb/db/tools/factory.php b/phpBB/phpbb/db/tools/factory.php new file mode 100644 index 0000000000..d204451a63 --- /dev/null +++ b/phpBB/phpbb/db/tools/factory.php @@ -0,0 +1,43 @@ +<?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\tools; + +/** + * A factory which serves the suitable tools instance for the given dbal + */ +class factory +{ +	/** +	 * @param mixed $db_driver +	 * @param bool $return_statements +	 * @return \phpbb\db\tools\tools_interface +	 */ +	public function get($db_driver, $return_statements = false) +	{ +		if ($db_driver instanceof \phpbb\db\driver\mssql || $db_driver instanceof \phpbb\db\driver\mssql_base) +		{ +			return new \phpbb\db\tools\mssql($db_driver, $return_statements); +		} +		else if ($db_driver instanceof \phpbb\db\driver\postgres) +		{ +			return new \phpbb\db\tools\postgres($db_driver, $return_statements); +		} +		else if ($db_driver instanceof \phpbb\db\driver\driver_interface) +		{ +			return new \phpbb\db\tools\tools($db_driver, $return_statements); +		} + +		throw new \InvalidArgumentException('Invalid database driver given'); +	} +} diff --git a/phpBB/phpbb/db/tools/mssql.php b/phpBB/phpbb/db/tools/mssql.php new file mode 100644 index 0000000000..6e58171040 --- /dev/null +++ b/phpBB/phpbb/db/tools/mssql.php @@ -0,0 +1,793 @@ +<?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\tools; + +/** + * Database Tools for handling cross-db actions such as altering columns, etc. + * Currently not supported is returning SQL for creating tables. + */ +class mssql extends tools +{ +	/** +	 * Is the used MS SQL Server a SQL Server 2000? +	 * @var bool +	 */ +	protected $is_sql_server_2000; + +	/** +	 * Get the column types for mssql based databases +	 * +	 * @return array +	 */ +	public static function get_dbms_type_map() +	{ +		return array( +			'mssql'		=> array( +				'INT:'		=> '[int]', +				'BINT'		=> '[float]', +				'UINT'		=> '[int]', +				'UINT:'		=> '[int]', +				'TINT:'		=> '[int]', +				'USINT'		=> '[int]', +				'BOOL'		=> '[int]', +				'VCHAR'		=> '[varchar] (255)', +				'VCHAR:'	=> '[varchar] (%d)', +				'CHAR:'		=> '[char] (%d)', +				'XSTEXT'	=> '[varchar] (1000)', +				'STEXT'		=> '[varchar] (3000)', +				'TEXT'		=> '[varchar] (8000)', +				'MTEXT'		=> '[text]', +				'XSTEXT_UNI'=> '[varchar] (100)', +				'STEXT_UNI'	=> '[varchar] (255)', +				'TEXT_UNI'	=> '[varchar] (4000)', +				'MTEXT_UNI'	=> '[text]', +				'TIMESTAMP'	=> '[int]', +				'DECIMAL'	=> '[float]', +				'DECIMAL:'	=> '[float]', +				'PDECIMAL'	=> '[float]', +				'PDECIMAL:'	=> '[float]', +				'VCHAR_UNI'	=> '[varchar] (255)', +				'VCHAR_UNI:'=> '[varchar] (%d)', +				'VCHAR_CI'	=> '[varchar] (255)', +				'VARBINARY'	=> '[varchar] (255)', +			), + +			'mssqlnative'	=> array( +				'INT:'		=> '[int]', +				'BINT'		=> '[float]', +				'UINT'		=> '[int]', +				'UINT:'		=> '[int]', +				'TINT:'		=> '[int]', +				'USINT'		=> '[int]', +				'BOOL'		=> '[int]', +				'VCHAR'		=> '[varchar] (255)', +				'VCHAR:'	=> '[varchar] (%d)', +				'CHAR:'		=> '[char] (%d)', +				'XSTEXT'	=> '[varchar] (1000)', +				'STEXT'		=> '[varchar] (3000)', +				'TEXT'		=> '[varchar] (8000)', +				'MTEXT'		=> '[text]', +				'XSTEXT_UNI'=> '[varchar] (100)', +				'STEXT_UNI'	=> '[varchar] (255)', +				'TEXT_UNI'	=> '[varchar] (4000)', +				'MTEXT_UNI'	=> '[text]', +				'TIMESTAMP'	=> '[int]', +				'DECIMAL'	=> '[float]', +				'DECIMAL:'	=> '[float]', +				'PDECIMAL'	=> '[float]', +				'PDECIMAL:'	=> '[float]', +				'VCHAR_UNI'	=> '[varchar] (255)', +				'VCHAR_UNI:'=> '[varchar] (%d)', +				'VCHAR_CI'	=> '[varchar] (255)', +				'VARBINARY'	=> '[varchar] (255)', +			), +		); +	} + +	/** +	* Constructor. Set DB Object and set {@link $return_statements return_statements}. +	* +	* @param \phpbb\db\driver\driver_interface	$db					Database connection +	* @param bool		$return_statements	True if only statements should be returned and no SQL being executed +	*/ +	public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false) +	{ +		parent::__construct($db, $return_statements); + +		// Determine mapping database type +		switch ($this->db->get_sql_layer()) +		{ +			case 'mssql': +			case 'mssql_odbc': +				$this->sql_layer = 'mssql'; +			break; + +			case 'mssqlnative': +				$this->sql_layer = 'mssqlnative'; +			break; +		} + +		$this->dbms_type_map = self::get_dbms_type_map(); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_list_tables() +	{ +		$sql = "SELECT name +			FROM sysobjects +			WHERE type='U'"; +		$result = $this->db->sql_query($sql); + +		$tables = array(); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$name = current($row); +			$tables[$name] = $name; +		} +		$this->db->sql_freeresult($result); + +		return $tables; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_table($table_name, $table_data) +	{ +		// holds the DDL for a column +		$columns = $statements = array(); + +		if ($this->sql_table_exists($table_name)) +		{ +			return $this->_sql_run_sql($statements); +		} + +		// Begin transaction +		$statements[] = 'begin'; + +		// Determine if we have created a PRIMARY KEY in the earliest +		$primary_key_gen = false; + +		// Determine if the table requires a sequence +		$create_sequence = false; + +		// Begin table sql statement +		$table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n"; + +		if (!isset($table_data['PRIMARY_KEY'])) +		{ +			$table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment'); +			$table_data['PRIMARY_KEY'] = 'mssqlindex'; +		} + +		// Iterate through the columns to create a table +		foreach ($table_data['COLUMNS'] as $column_name => $column_data) +		{ +			// here lies an array, filled with information compiled on the column's data +			$prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data); + +			if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen" +			{ +				trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR); +			} + +			// here we add the definition of the new column to the list of columns +			$columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default']; + +			// see if we have found a primary key set due to a column definition if we have found it, we can stop looking +			if (!$primary_key_gen) +			{ +				$primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set']; +			} + +			// create sequence DDL based off of the existance of auto incrementing columns +			if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment']) +			{ +				$create_sequence = $column_name; +			} +		} + +		// this makes up all the columns in the create table statement +		$table_sql .= implode(",\n", $columns); + +		// Close the table for two DBMS and add to the statements +		$table_sql .= "\n);"; +		$statements[] = $table_sql; + +		// we have yet to create a primary key for this table, +		// this means that we can add the one we really wanted instead +		if (!$primary_key_gen) +		{ +			// Write primary key +			if (isset($table_data['PRIMARY_KEY'])) +			{ +				if (!is_array($table_data['PRIMARY_KEY'])) +				{ +					$table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']); +				} + +				// We need the data here +				$old_return_statements = $this->return_statements; +				$this->return_statements = true; + +				$primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']); +				foreach ($primary_key_stmts as $pk_stmt) +				{ +					$statements[] = $pk_stmt; +				} + +				$this->return_statements = $old_return_statements; +			} +		} + +		// Write Keys +		if (isset($table_data['KEYS'])) +		{ +			foreach ($table_data['KEYS'] as $key_name => $key_data) +			{ +				if (!is_array($key_data[1])) +				{ +					$key_data[1] = array($key_data[1]); +				} + +				$old_return_statements = $this->return_statements; +				$this->return_statements = true; + +				$key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]); + +				foreach ($key_stmts as $key_stmt) +				{ +					$statements[] = $key_stmt; +				} + +				$this->return_statements = $old_return_statements; +			} +		} + +		// Commit Transaction +		$statements[] = 'commit'; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_list_columns($table_name) +	{ +		$columns = array(); + +		$sql = "SELECT c.name +			FROM syscolumns c +			LEFT JOIN sysobjects o ON c.id = o.id +			WHERE o.name = '{$table_name}'"; +		$result = $this->db->sql_query($sql); + +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$column = strtolower(current($row)); +			$columns[$column] = $column; +		} +		$this->db->sql_freeresult($result); + +		return $columns; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_index_exists($table_name, $index_name) +	{ +		$sql = "EXEC sp_statistics '$table_name'"; +		$result = $this->db->sql_query($sql); + +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			if ($row['TYPE'] == 3) +			{ +				if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) +				{ +					$this->db->sql_freeresult($result); +					return true; +				} +			} +		} +		$this->db->sql_freeresult($result); + +		return false; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_unique_index_exists($table_name, $index_name) +	{ +		$sql = "EXEC sp_statistics '$table_name'"; +		$result = $this->db->sql_query($sql); + +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			// Usually NON_UNIQUE is the column we want to check, but we allow for both +			if ($row['TYPE'] == 3) +			{ +				if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) +				{ +					$this->db->sql_freeresult($result); +					return true; +				} +			} +		} +		$this->db->sql_freeresult($result); + +		return false; +	} + +	/** +	 * {@inheritDoc} +	*/ +	function sql_prepare_column_data($table_name, $column_name, $column_data) +	{ +		if (strlen($column_name) > 30) +		{ +			trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); +		} + +		// Get type +		list($column_type, ) = $this->get_column_type($column_data[0]); + +		// Adjust default value if db-dependent specified +		if (is_array($column_data[1])) +		{ +			$column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default']; +		} + +		$sql = ''; + +		$return_array = array(); + +		$sql .= " {$column_type} "; +		$sql_default = " {$column_type} "; + +		// For adding columns we need the default definition +		if (!is_null($column_data[1])) +		{ +			// For hexadecimal values do not use single quotes +			if (strpos($column_data[1], '0x') === 0) +			{ +				$return_array['default'] = 'DEFAULT (' . $column_data[1] . ') '; +				$sql_default .= $return_array['default']; +			} +			else +			{ +				$return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; +				$sql_default .= $return_array['default']; +			} +		} + +		if (isset($column_data[2]) && $column_data[2] == 'auto_increment') +		{ +			// $sql .= 'IDENTITY (1, 1) '; +			$sql_default .= 'IDENTITY (1, 1) '; +		} + +		$return_array['textimage'] = $column_type === '[text]'; + +		if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment')) +		{ +			$sql .= 'NOT NULL'; +			$sql_default .= 'NOT NULL'; +		} +		else +		{ +			$sql .= 'NULL'; +			$sql_default .= 'NULL'; +		} + +		$return_array['column_type_sql_default'] = $sql_default; + +		$return_array['column_type_sql'] = $sql; + +		return $return_array; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_column_add($table_name, $column_name, $column_data, $inline = false) +	{ +		$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); +		$statements = array(); + +		// Does not support AFTER, only through temporary table +		$statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default']; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_column_remove($table_name, $column_name, $inline = false) +	{ +		$statements = array(); + +		// We need the data here +		$old_return_statements = $this->return_statements; +		$this->return_statements = true; + +		$indexes = $this->get_existing_indexes($table_name, $column_name); +		$indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true)); + +		// Drop any indexes +		$recreate_indexes = array(); +		if (!empty($indexes)) +		{ +			foreach ($indexes as $index_name => $index_data) +			{ +				$result = $this->sql_index_drop($table_name, $index_name); +				$statements = array_merge($statements, $result); +				if (sizeof($index_data) > 1) +				{ +					// Remove this column from the index and recreate it +					$recreate_indexes[$index_name] = array_diff($index_data, array($column_name)); +				} +			} +		} + +		// Drop default value constraint +		$result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name); +		$statements = array_merge($statements, $result); + +		// Remove the column +		$statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; + +		if (!empty($recreate_indexes)) +		{ +			// Recreate indexes after we removed the column +			foreach ($recreate_indexes as $index_name => $index_data) +			{ +				$result = $this->sql_create_index($table_name, $index_name, $index_data); +				$statements = array_merge($statements, $result); +			} +		} + +		$this->return_statements = $old_return_statements; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_index_drop($table_name, $index_name) +	{ +		$statements = array(); + +		$statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_table_drop($table_name) +	{ +		$statements = array(); + +		if (!$this->sql_table_exists($table_name)) +		{ +			return $this->_sql_run_sql($statements); +		} + +		// the most basic operation, get rid of the table +		$statements[] = 'DROP TABLE ' . $table_name; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_primary_key($table_name, $column, $inline = false) +	{ +		$statements = array(); + +		$sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD "; +		$sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY  CLUSTERED ("; +		$sql .= '[' . implode("],\n\t\t[", $column) . ']'; +		$sql .= ')'; + +		$statements[] = $sql; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_unique_index($table_name, $index_name, $column) +	{ +		$statements = array(); + +		$this->check_index_name_length($table_name, $index_name); + +		$statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])'; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_index($table_name, $index_name, $column) +	{ +		$statements = array(); + +		$this->check_index_name_length($table_name, $index_name); + +		// remove index length +		$column = preg_replace('#:.*$#', '', $column); + +		$statements[] = 'CREATE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])'; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_list_index($table_name) +	{ +		$index_array = array(); +		$sql = "EXEC sp_statistics '$table_name'"; +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			if ($row['TYPE'] == 3) +			{ +				$index_array[] = strtolower($row['INDEX_NAME']); +			} +		} +		$this->db->sql_freeresult($result); + +		return $index_array; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_column_change($table_name, $column_name, $column_data, $inline = false) +	{ +		$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); +		$statements = array(); + +		// We need the data here +		$old_return_statements = $this->return_statements; +		$this->return_statements = true; + +		$indexes = $this->get_existing_indexes($table_name, $column_name); +		$unique_indexes = $this->get_existing_indexes($table_name, $column_name, true); + +		// Drop any indexes +		if (!empty($indexes) || !empty($unique_indexes)) +		{ +			$drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes)); +			foreach ($drop_indexes as $index_name) +			{ +				$result = $this->sql_index_drop($table_name, $index_name); +				$statements = array_merge($statements, $result); +			} +		} + +		// Drop default value constraint +		$result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name); +		$statements = array_merge($statements, $result); + +		// Change the column +		$statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; + +		if (!empty($column_data['default'])) +		{ +			// Add new default value constraint +			$statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $this->db->sql_escape($column_data['default']) . ' FOR [' . $column_name . ']'; +		} + +		if (!empty($indexes)) +		{ +			// Recreate indexes after we changed the column +			foreach ($indexes as $index_name => $index_data) +			{ +				$result = $this->sql_create_index($table_name, $index_name, $index_data); +				$statements = array_merge($statements, $result); +			} +		} + +		if (!empty($unique_indexes)) +		{ +			// Recreate unique indexes after we changed the column +			foreach ($unique_indexes as $index_name => $index_data) +			{ +				$result = $this->sql_create_unique_index($table_name, $index_name, $index_data); +				$statements = array_merge($statements, $result); +			} +		} + +		$this->return_statements = $old_return_statements; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	* Get queries to drop the default constraints of a column +	* +	* We need to drop the default constraints of a column, +	* before being able to change their type or deleting them. +	* +	* @param string $table_name +	* @param string $column_name +	* @return array		Array with SQL statements +	*/ +	protected function mssql_get_drop_default_constraints_queries($table_name, $column_name) +	{ +		$statements = array(); +		if ($this->mssql_is_sql_server_2000()) +		{ +			// http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx +			// Deprecated in SQL Server 2005 +			$sql = "SELECT so.name AS def_name +				FROM sysobjects so +				JOIN sysconstraints sc ON so.id = sc.constid +				WHERE object_name(so.parent_obj) = '{$table_name}' +					AND so.xtype = 'D' +					AND sc.colid = (SELECT colid FROM syscolumns +						WHERE id = object_id('{$table_name}') +							AND name = '{$column_name}')"; +		} +		else +		{ +			$sql = "SELECT dobj.name AS def_name +				FROM sys.columns col +					LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D') +				WHERE col.object_id = object_id('{$table_name}') +					AND col.name = '{$column_name}' +					AND dobj.name IS NOT NULL"; +		} + +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']'; +		} +		$this->db->sql_freeresult($result); + +		return $statements; +	} + +	/** +	* Get a list with existing indexes for the column +	* +	* @param string $table_name +	* @param string $column_name +	* @param bool $unique Should we get unique indexes or normal ones +	* @return array		Array with Index name => columns +	*/ +	public function get_existing_indexes($table_name, $column_name, $unique = false) +	{ +		$existing_indexes = array(); +		if ($this->mssql_is_sql_server_2000()) +		{ +			// http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx +			// Deprecated in SQL Server 2005 +			$sql = "SELECT DISTINCT ix.name AS phpbb_index_name +				FROM sysindexes ix +				INNER JOIN sysindexkeys ixc +					ON ixc.id = ix.id +						AND ixc.indid = ix.indid +				INNER JOIN syscolumns cols +					ON cols.colid = ixc.colid +						AND cols.id = ix.id +				WHERE ix.id = object_id('{$table_name}') +					AND cols.name = '{$column_name}' +					AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0'); +		} +		else +		{ +			$sql = "SELECT DISTINCT ix.name AS phpbb_index_name +				FROM sys.indexes ix +				INNER JOIN sys.index_columns ixc +					ON ixc.object_id = ix.object_id +						AND ixc.index_id = ix.index_id +				INNER JOIN sys.columns cols +					ON cols.column_id = ixc.column_id +						AND cols.object_id = ix.object_id +				WHERE ix.object_id = object_id('{$table_name}') +					AND cols.name = '{$column_name}' +					AND ix.is_unique = " . ($unique ? '1' : '0'); +		} + +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE')) +			{ +				$existing_indexes[$row['phpbb_index_name']] = array(); +			} +		} +		$this->db->sql_freeresult($result); + +		if (empty($existing_indexes)) +		{ +			return array(); +		} + +		if ($this->mssql_is_sql_server_2000()) +		{ +			$sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name +				FROM sysindexes ix +				INNER JOIN sysindexkeys ixc +					ON ixc.id = ix.id +						AND ixc.indid = ix.indid +				INNER JOIN syscolumns cols +					ON cols.colid = ixc.colid +						AND cols.id = ix.id +				WHERE ix.id = object_id('{$table_name}') +					AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); +		} +		else +		{ +			$sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name +				FROM sys.indexes ix +				INNER JOIN sys.index_columns ixc +					ON ixc.object_id = ix.object_id +						AND ixc.index_id = ix.index_id +				INNER JOIN sys.columns cols +					ON cols.column_id = ixc.column_id +						AND cols.object_id = ix.object_id +				WHERE ix.object_id = object_id('{$table_name}') +					AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); +		} + +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name']; +		} +		$this->db->sql_freeresult($result); + +		return $existing_indexes; +	} + +	/** +	* Is the used MS SQL Server a SQL Server 2000? +	* +	* @return bool +	*/ +	protected function mssql_is_sql_server_2000() +	{ +		if ($this->is_sql_server_2000 === null) +		{ +			$sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version"; +			$result = $this->db->sql_query($sql); +			$properties = $this->db->sql_fetchrow($result); +			$this->db->sql_freeresult($result); +			$this->is_sql_server_2000 = $properties['mssql_version'][0] == '8'; +		} + +		return $this->is_sql_server_2000; +	} + +} diff --git a/phpBB/phpbb/db/tools/postgres.php b/phpBB/phpbb/db/tools/postgres.php new file mode 100644 index 0000000000..8b61625c3c --- /dev/null +++ b/phpBB/phpbb/db/tools/postgres.php @@ -0,0 +1,613 @@ +<?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\tools; + +/** + * Database Tools for handling cross-db actions such as altering columns, etc. + * Currently not supported is returning SQL for creating tables. + */ +class postgres extends tools +{ +	/** +	 * Get the column types for postgres only +	 * +	 * @return array +	 */ +	public static function get_dbms_type_map() +	{ +		return array( +			'postgres'	=> array( +				'INT:'		=> 'INT4', +				'BINT'		=> 'INT8', +				'UINT'		=> 'INT4', // unsigned +				'UINT:'		=> 'INT4', // unsigned +				'USINT'		=> 'INT2', // unsigned +				'BOOL'		=> 'INT2', // unsigned +				'TINT:'		=> 'INT2', +				'VCHAR'		=> 'varchar(255)', +				'VCHAR:'	=> 'varchar(%d)', +				'CHAR:'		=> 'char(%d)', +				'XSTEXT'	=> 'varchar(1000)', +				'STEXT'		=> 'varchar(3000)', +				'TEXT'		=> 'varchar(8000)', +				'MTEXT'		=> 'TEXT', +				'XSTEXT_UNI'=> 'varchar(100)', +				'STEXT_UNI'	=> 'varchar(255)', +				'TEXT_UNI'	=> 'varchar(4000)', +				'MTEXT_UNI'	=> 'TEXT', +				'TIMESTAMP'	=> 'INT4', // unsigned +				'DECIMAL'	=> 'decimal(5,2)', +				'DECIMAL:'	=> 'decimal(%d,2)', +				'PDECIMAL'	=> 'decimal(6,3)', +				'PDECIMAL:'	=> 'decimal(%d,3)', +				'VCHAR_UNI'	=> 'varchar(255)', +				'VCHAR_UNI:'=> 'varchar(%d)', +				'VCHAR_CI'	=> 'varchar_ci', +				'VARBINARY'	=> 'bytea', +			), +		); +	} + +	/** +	* Constructor. Set DB Object and set {@link $return_statements return_statements}. +	* +	* @param \phpbb\db\driver\driver_interface	$db					Database connection +	* @param bool		$return_statements	True if only statements should be returned and no SQL being executed +	*/ +	public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false) +	{ +		parent::__construct($db, $return_statements); + +		// Determine mapping database type +		$this->sql_layer = 'postgres'; + +		$this->dbms_type_map = self::get_dbms_type_map(); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_list_tables() +	{ +		$sql = 'SELECT relname +			FROM pg_stat_user_tables'; +		$result = $this->db->sql_query($sql); + +		$tables = array(); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$name = current($row); +			$tables[$name] = $name; +		} +		$this->db->sql_freeresult($result); + +		return $tables; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_table($table_name, $table_data) +	{ +		// holds the DDL for a column +		$columns = $statements = array(); + +		if ($this->sql_table_exists($table_name)) +		{ +			return $this->_sql_run_sql($statements); +		} + +		// Begin transaction +		$statements[] = 'begin'; + +		// Determine if we have created a PRIMARY KEY in the earliest +		$primary_key_gen = false; + +		// Determine if the table requires a sequence +		$create_sequence = false; + +		// Begin table sql statement +		$table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n"; + +		// Iterate through the columns to create a table +		foreach ($table_data['COLUMNS'] as $column_name => $column_data) +		{ +			// here lies an array, filled with information compiled on the column's data +			$prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data); + +			if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen" +			{ +				trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR); +			} + +			// here we add the definition of the new column to the list of columns +			$columns[] = "\t {$column_name} " . $prepared_column['column_type_sql']; + +			// see if we have found a primary key set due to a column definition if we have found it, we can stop looking +			if (!$primary_key_gen) +			{ +				$primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set']; +			} + +			// create sequence DDL based off of the existance of auto incrementing columns +			if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment']) +			{ +				$create_sequence = $column_name; +			} +		} + +		// this makes up all the columns in the create table statement +		$table_sql .= implode(",\n", $columns); + +		// we have yet to create a primary key for this table, +		// this means that we can add the one we really wanted instead +		if (!$primary_key_gen) +		{ +			// Write primary key +			if (isset($table_data['PRIMARY_KEY'])) +			{ +				if (!is_array($table_data['PRIMARY_KEY'])) +				{ +					$table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']); +				} + +				$table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; +			} +		} + +		// do we need to add a sequence for auto incrementing columns? +		if ($create_sequence) +		{ +			$statements[] = "CREATE SEQUENCE {$table_name}_seq;"; +		} + +		// close the table +		$table_sql .= "\n);"; +		$statements[] = $table_sql; + +		// Write Keys +		if (isset($table_data['KEYS'])) +		{ +			foreach ($table_data['KEYS'] as $key_name => $key_data) +			{ +				if (!is_array($key_data[1])) +				{ +					$key_data[1] = array($key_data[1]); +				} + +				$old_return_statements = $this->return_statements; +				$this->return_statements = true; + +				$key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]); + +				foreach ($key_stmts as $key_stmt) +				{ +					$statements[] = $key_stmt; +				} + +				$this->return_statements = $old_return_statements; +			} +		} + +		// Commit Transaction +		$statements[] = 'commit'; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_list_columns($table_name) +	{ +		$columns = array(); + +		$sql = "SELECT a.attname +			FROM pg_class c, pg_attribute a +			WHERE c.relname = '{$table_name}' +				AND a.attnum > 0 +				AND a.attrelid = c.oid"; +		$result = $this->db->sql_query($sql); + +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$column = strtolower(current($row)); +			$columns[$column] = $column; +		} +		$this->db->sql_freeresult($result); + +		return $columns; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_index_exists($table_name, $index_name) +	{ +		$sql = "SELECT ic.relname as index_name +			FROM pg_class bc, pg_class ic, pg_index i +			WHERE (bc.oid = i.indrelid) +				AND (ic.oid = i.indexrelid) +				AND (bc.relname = '" . $table_name . "') +				AND (i.indisunique != 't') +				AND (i.indisprimary != 't')"; +		$result = $this->db->sql_query($sql); + +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			// This DBMS prefixes index names with the table name +			$row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']); + +			if (strtolower($row['index_name']) == strtolower($index_name)) +			{ +				$this->db->sql_freeresult($result); +				return true; +			} +		} +		$this->db->sql_freeresult($result); + +		return false; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_unique_index_exists($table_name, $index_name) +	{ +		$sql = "SELECT ic.relname as index_name, i.indisunique +			FROM pg_class bc, pg_class ic, pg_index i +			WHERE (bc.oid = i.indrelid) +				AND (ic.oid = i.indexrelid) +				AND (bc.relname = '" . $table_name . "') +				AND (i.indisprimary != 't')"; +		$result = $this->db->sql_query($sql); + +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			if ($row['indisunique'] != 't') +			{ +				continue; +			} + +			// This DBMS prefixes index names with the table name +			$row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']); + +			if (strtolower($row['index_name']) == strtolower($index_name)) +			{ +				$this->db->sql_freeresult($result); +				return true; +			} +		} +		$this->db->sql_freeresult($result); + +		return false; +	} + +	/** +	* Function to prepare some column information for better usage +	* @access private +	*/ +	function sql_prepare_column_data($table_name, $column_name, $column_data) +	{ +		if (strlen($column_name) > 30) +		{ +			trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); +		} + +		// Get type +		list($column_type, $orig_column_type) = $this->get_column_type($column_data[0]); + +		// Adjust default value if db-dependent specified +		if (is_array($column_data[1])) +		{ +			$column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default']; +		} + +		$sql = " {$column_type} "; + +		$return_array = array( +			'column_type'		=> $column_type, +			'auto_increment'	=> false, +		); + +		if (isset($column_data[2]) && $column_data[2] == 'auto_increment') +		{ +			$default_val = "nextval('{$table_name}_seq')"; +			$return_array['auto_increment'] = true; +		} +		else if (!is_null($column_data[1])) +		{ +			$default_val = "'" . $column_data[1] . "'"; +			$return_array['null'] = 'NOT NULL'; +			$sql .= 'NOT NULL '; +		} +		else +		{ +			// Integers need to have 0 instead of empty string as default +			if (strpos($column_type, 'INT') === 0) +			{ +				$default_val = '0'; +			} +			else +			{ +				$default_val = "'" . $column_data[1] . "'"; +			} +			$return_array['null'] = 'NULL'; +			$sql .= 'NULL '; +		} + +		$return_array['default'] = $default_val; + +		$sql .= "DEFAULT {$default_val}"; + +		// Unsigned? Then add a CHECK contraint +		if (in_array($orig_column_type, $this->unsigned_types)) +		{ +			$return_array['constraint'] = "CHECK ({$column_name} >= 0)"; +			$sql .= " CHECK ({$column_name} >= 0)"; +		} + +		$return_array['column_type_sql'] = $sql; + +		return $return_array; +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_column_add($table_name, $column_name, $column_data, $inline = false) +	{ +		$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); +		$statements = array(); + +		// Does not support AFTER, only through temporary table +		if (version_compare($this->db->sql_server_info(true), '8.0', '>=')) +		{ +			$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; +		} +		else +		{ +			// old versions cannot add columns with default and null information +			$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint']; + +			if (isset($column_data['null'])) +			{ +				if ($column_data['null'] == 'NOT NULL') +				{ +					$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL'; +				} +			} + +			if (isset($column_data['default'])) +			{ +				$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; +			} +		} + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_column_remove($table_name, $column_name, $inline = false) +	{ +		$statements = array(); + +		$statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"'; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_index_drop($table_name, $index_name) +	{ +		$statements = array(); + +		$statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_table_drop($table_name) +	{ +		$statements = array(); + +		if (!$this->sql_table_exists($table_name)) +		{ +			return $this->_sql_run_sql($statements); +		} + +		// the most basic operation, get rid of the table +		$statements[] = 'DROP TABLE ' . $table_name; + +		// PGSQL does not "tightly" bind sequences and tables, we must guess... +		$sql = "SELECT relname +			FROM pg_class +			WHERE relkind = 'S' +				AND relname = '{$table_name}_seq'"; +		$result = $this->db->sql_query($sql); + +		// We don't even care about storing the results. We already know the answer if we get rows back. +		if ($this->db->sql_fetchrow($result)) +		{ +			$statements[] =  "DROP SEQUENCE {$table_name}_seq;\n"; +		} +		$this->db->sql_freeresult($result); + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_primary_key($table_name, $column, $inline = false) +	{ +		$statements = array(); + +		$statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')'; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_unique_index($table_name, $index_name, $column) +	{ +		$statements = array(); + +		$this->check_index_name_length($table_name, $index_name); + +		$statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_create_index($table_name, $index_name, $column) +	{ +		$statements = array(); + +		$this->check_index_name_length($table_name, $index_name); + +		// remove index length +		$column = preg_replace('#:.*$#', '', $column); + +		$statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; + +		return $this->_sql_run_sql($statements); +	} + + +	/** +	 * {@inheritDoc} +	 */ +	function sql_list_index($table_name) +	{ +		$index_array = array(); + +		$sql = "SELECT ic.relname as index_name +			FROM pg_class bc, pg_class ic, pg_index i +			WHERE (bc.oid = i.indrelid) +				AND (ic.oid = i.indexrelid) +				AND (bc.relname = '" . $table_name . "') +				AND (i.indisunique != 't') +				AND (i.indisprimary != 't')"; +		$result = $this->db->sql_query($sql); + +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']); + +			$index_array[] = $row['index_name']; +		} +		$this->db->sql_freeresult($result); + +		return array_map('strtolower', $index_array); +	} + +	/** +	 * {@inheritDoc} +	 */ +	function sql_column_change($table_name, $column_name, $column_data, $inline = false) +	{ +		$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); +		$statements = array(); + +		$sql = 'ALTER TABLE ' . $table_name . ' '; + +		$sql_array = array(); +		$sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type']; + +		if (isset($column_data['null'])) +		{ +			if ($column_data['null'] == 'NOT NULL') +			{ +				$sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL'; +			} +			else if ($column_data['null'] == 'NULL') +			{ +				$sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL'; +			} +		} + +		if (isset($column_data['default'])) +		{ +			$sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; +		} + +		// we don't want to double up on constraints if we change different number data types +		if (isset($column_data['constraint'])) +		{ +			$constraint_sql = "SELECT consrc as constraint_data +				FROM pg_constraint, pg_class bc +				WHERE conrelid = bc.oid +					AND bc.relname = '{$table_name}' +					AND NOT EXISTS ( +						SELECT * +						FROM pg_constraint as c, pg_inherits as i +						WHERE i.inhrelid = pg_constraint.conrelid +							AND c.conname = pg_constraint.conname +							AND c.consrc = pg_constraint.consrc +							AND c.conrelid = i.inhparent +					)"; + +			$constraint_exists = false; + +			$result = $this->db->sql_query($constraint_sql); +			while ($row = $this->db->sql_fetchrow($result)) +			{ +				if (trim($row['constraint_data']) == trim($column_data['constraint'])) +				{ +					$constraint_exists = true; +					break; +				} +			} +			$this->db->sql_freeresult($result); + +			if (!$constraint_exists) +			{ +				$sql_array[] = 'ADD ' . $column_data['constraint']; +			} +		} + +		$sql .= implode(', ', $sql_array); + +		$statements[] = $sql; + +		return $this->_sql_run_sql($statements); +	} + +	/** +	* Get a list with existing indexes for the column +	* +	* @param string $table_name +	* @param string $column_name +	* @param bool $unique Should we get unique indexes or normal ones +	* @return array		Array with Index name => columns +	*/ +	public function get_existing_indexes($table_name, $column_name, $unique = false) +	{ +		// Not supported +		throw new \Exception('DBMS is not supported'); +	} +} diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools/tools.php index 775deccc30..0d1eb63c47 100644 --- a/phpBB/phpbb/db/tools.php +++ b/phpBB/phpbb/db/tools/tools.php @@ -11,13 +11,13 @@  *  */ -namespace phpbb\db; +namespace phpbb\db\tools;  /**  * Database Tools for handling cross-db actions such as altering columns, etc.  * Currently not supported is returning SQL for creating tables.  */ -class tools +class tools implements tools_interface  {  	/**  	* Current sql layer @@ -36,12 +36,6 @@ class tools  	var $dbms_type_map = array();  	/** -	* Is the used MS SQL Server a SQL Server 2000? -	* @var bool -	*/ -	protected $is_sql_server_2000; - -	/**  	* Get the column types for every database we support  	*  	* @return array @@ -109,66 +103,6 @@ class tools  				'VARBINARY'	=> 'varbinary(255)',  			), -			'mssql'		=> array( -				'INT:'		=> '[int]', -				'BINT'		=> '[float]', -				'UINT'		=> '[int]', -				'UINT:'		=> '[int]', -				'TINT:'		=> '[int]', -				'USINT'		=> '[int]', -				'BOOL'		=> '[int]', -				'VCHAR'		=> '[varchar] (255)', -				'VCHAR:'	=> '[varchar] (%d)', -				'CHAR:'		=> '[char] (%d)', -				'XSTEXT'	=> '[varchar] (1000)', -				'STEXT'		=> '[varchar] (3000)', -				'TEXT'		=> '[varchar] (8000)', -				'MTEXT'		=> '[text]', -				'XSTEXT_UNI'=> '[varchar] (100)', -				'STEXT_UNI'	=> '[varchar] (255)', -				'TEXT_UNI'	=> '[varchar] (4000)', -				'MTEXT_UNI'	=> '[text]', -				'TIMESTAMP'	=> '[int]', -				'DECIMAL'	=> '[float]', -				'DECIMAL:'	=> '[float]', -				'PDECIMAL'	=> '[float]', -				'PDECIMAL:'	=> '[float]', -				'VCHAR_UNI'	=> '[varchar] (255)', -				'VCHAR_UNI:'=> '[varchar] (%d)', -				'VCHAR_CI'	=> '[varchar] (255)', -				'VARBINARY'	=> '[varchar] (255)', -			), - -			'mssqlnative'	=> array( -				'INT:'		=> '[int]', -				'BINT'		=> '[float]', -				'UINT'		=> '[int]', -				'UINT:'		=> '[int]', -				'TINT:'		=> '[int]', -				'USINT'		=> '[int]', -				'BOOL'		=> '[int]', -				'VCHAR'		=> '[varchar] (255)', -				'VCHAR:'	=> '[varchar] (%d)', -				'CHAR:'		=> '[char] (%d)', -				'XSTEXT'	=> '[varchar] (1000)', -				'STEXT'		=> '[varchar] (3000)', -				'TEXT'		=> '[varchar] (8000)', -				'MTEXT'		=> '[text]', -				'XSTEXT_UNI'=> '[varchar] (100)', -				'STEXT_UNI'	=> '[varchar] (255)', -				'TEXT_UNI'	=> '[varchar] (4000)', -				'MTEXT_UNI'	=> '[text]', -				'TIMESTAMP'	=> '[int]', -				'DECIMAL'	=> '[float]', -				'DECIMAL:'	=> '[float]', -				'PDECIMAL'	=> '[float]', -				'PDECIMAL:'	=> '[float]', -				'VCHAR_UNI'	=> '[varchar] (255)', -				'VCHAR_UNI:'=> '[varchar] (%d)', -				'VCHAR_CI'	=> '[varchar] (255)', -				'VARBINARY'	=> '[varchar] (255)', -			), -  			'oracle'	=> array(  				'INT:'		=> 'number(%d)',  				'BINT'		=> 'number(20)', @@ -258,36 +192,6 @@ class tools  				'VCHAR_CI'	=> 'VARCHAR(255)',  				'VARBINARY'	=> 'BLOB',  			), - -			'postgres'	=> array( -				'INT:'		=> 'INT4', -				'BINT'		=> 'INT8', -				'UINT'		=> 'INT4', // unsigned -				'UINT:'		=> 'INT4', // unsigned -				'USINT'		=> 'INT2', // unsigned -				'BOOL'		=> 'INT2', // unsigned -				'TINT:'		=> 'INT2', -				'VCHAR'		=> 'varchar(255)', -				'VCHAR:'	=> 'varchar(%d)', -				'CHAR:'		=> 'char(%d)', -				'XSTEXT'	=> 'varchar(1000)', -				'STEXT'		=> 'varchar(3000)', -				'TEXT'		=> 'varchar(8000)', -				'MTEXT'		=> 'TEXT', -				'XSTEXT_UNI'=> 'varchar(100)', -				'STEXT_UNI'	=> 'varchar(255)', -				'TEXT_UNI'	=> 'varchar(4000)', -				'MTEXT_UNI'	=> 'TEXT', -				'TIMESTAMP'	=> 'INT4', // unsigned -				'DECIMAL'	=> 'decimal(5,2)', -				'DECIMAL:'	=> 'decimal(%d,2)', -				'PDECIMAL'	=> 'decimal(6,3)', -				'PDECIMAL:'	=> 'decimal(%d,3)', -				'VCHAR_UNI'	=> 'varchar(255)', -				'VCHAR_UNI:'=> 'varchar(%d)', -				'VCHAR_CI'	=> 'varchar_ci', -				'VARBINARY'	=> 'bytea', -			),  		);  	} @@ -298,12 +202,6 @@ class tools  	var $unsigned_types = array('UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP');  	/** -	* A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules. -	* @var array -	*/ -	var $supported_dbms = array('mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite', 'sqlite3'); - -	/**  	* This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array).  	* This mode has no effect on some methods (inserting of data for example). This is expressed within the methods command.  	*/ @@ -344,15 +242,6 @@ class tools  				$this->sql_layer = 'mysql_41';  			break; -			case 'mssql': -			case 'mssql_odbc': -				$this->sql_layer = 'mssql'; -			break; - -			case 'mssqlnative': -				$this->sql_layer = 'mssqlnative'; -			break; -  			default:  				$this->sql_layer = $this->db->get_sql_layer();  			break; @@ -371,10 +260,8 @@ class tools  	}  	/** -	* Gets a list of tables in the database. -	* -	* @return array		Array of table names  (all lower case) -	*/ +	 * {@inheritDoc} +	 */  	function sql_list_tables()  	{  		switch ($this->db->get_sql_layer()) @@ -398,19 +285,6 @@ class tools  						AND name <> "sqlite_sequence"';  			break; -			case 'mssql': -			case 'mssql_odbc': -			case 'mssqlnative': -				$sql = "SELECT name -					FROM sysobjects -					WHERE type='U'"; -			break; - -			case 'postgres': -				$sql = 'SELECT relname -					FROM pg_stat_user_tables'; -			break; -  			case 'oracle':  				$sql = 'SELECT table_name  					FROM USER_TABLES'; @@ -431,12 +305,8 @@ class tools  	}  	/** -	* Check if table exists -	* -	* -	* @param string	$table_name	The table name to check for -	* @return bool true if table exists, else false -	*/ +	 * {@inheritDoc} +	 */  	function sql_table_exists($table_name)  	{  		$this->db->sql_return_on_error(true); @@ -453,12 +323,8 @@ class tools  	}  	/** -	* Create SQL Table -	* -	* @param string	$table_name	The table name to create -	* @param array	$table_data	Array containing table data. -	* @return array	Statements if $return_statements is true. -	*/ +	 * {@inheritDoc} +	 */  	function sql_create_table($table_name, $table_data)  	{  		// holds the DDL for a column @@ -479,26 +345,7 @@ class tools  		$create_sequence = false;  		// Begin table sql statement -		switch ($this->sql_layer) -		{ -			case 'mssql': -			case 'mssqlnative': -				$table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n"; -			break; - -			default: -				$table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n"; -			break; -		} - -		if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') -		{ -			if (!isset($table_data['PRIMARY_KEY'])) -			{ -				$table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment'); -				$table_data['PRIMARY_KEY'] = 'mssqlindex'; -			} -		} +		$table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n";  		// Iterate through the columns to create a table  		foreach ($table_data['COLUMNS'] as $column_name => $column_data) @@ -512,17 +359,7 @@ class tools  			}  			// here we add the definition of the new column to the list of columns -			switch ($this->sql_layer) -			{ -				case 'mssql': -				case 'mssqlnative': -					$columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default']; -				break; - -				default: -					$columns[] = "\t {$column_name} " . $prepared_column['column_type_sql']; -				break; -			} +			$columns[] = "\t {$column_name} " . $prepared_column['column_type_sql'];  			// see if we have found a primary key set due to a column definition if we have found it, we can stop looking  			if (!$primary_key_gen) @@ -540,16 +377,6 @@ class tools  		// this makes up all the columns in the create table statement  		$table_sql .= implode(",\n", $columns); -		// Close the table for two DBMS and add to the statements -		switch ($this->sql_layer) -		{ -			case 'mssql': -			case 'mssqlnative': -				$table_sql .= "\n);"; -				$statements[] = $table_sql; -			break; -		} -  		// we have yet to create a primary key for this table,  		// this means that we can add the one we really wanted instead  		if (!$primary_key_gen) @@ -566,27 +393,11 @@ class tools  				{  					case 'mysql_40':  					case 'mysql_41': -					case 'postgres':  					case 'sqlite':  					case 'sqlite3':  						$table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';  					break; -					case 'mssql': -					case 'mssqlnative': -						// We need the data here -						$old_return_statements = $this->return_statements; -						$this->return_statements = true; - -						$primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']); -						foreach ($primary_key_stmts as $pk_stmt) -						{ -							$statements[] = $pk_stmt; -						} - -						$this->return_statements = $old_return_statements; -					break; -  					case 'oracle':  						$table_sql .= ",\n\t CONSTRAINT pk_{$table_name} PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';  					break; @@ -610,17 +421,6 @@ class tools  				$statements[] = $table_sql;  			break; -			case 'postgres': -				// do we need to add a sequence for auto incrementing columns? -				if ($create_sequence) -				{ -					$statements[] = "CREATE SEQUENCE {$table_name}_seq;"; -				} - -				$table_sql .= "\n);"; -				$statements[] = $table_sql; -			break; -  			case 'oracle':  				$table_sql .= "\n)";  				$statements[] = $table_sql; @@ -679,27 +479,8 @@ class tools  	}  	/** -	* Handle passed database update array. -	* Expected structure... -	* Key being one of the following -	*	drop_tables: Drop tables -	*	add_tables: Add tables -	*	change_columns: Column changes (only type, not name) -	*	add_columns: Add columns to a table -	*	drop_keys: Dropping keys -	*	drop_columns: Removing/Dropping columns -	*	add_primary_keys: adding primary keys -	*	add_unique_index: adding an unique index -	*	add_index: adding an index (can be column:index_size if you need to provide size) -	* -	* The values are in this format: -	*		{TABLE NAME}		=> array( -	*			{COLUMN NAME}		=> array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}), -	*			{KEY/INDEX NAME}	=> array({COLUMN NAMES}), -	*		) -	* -	* For more information have a look at /develop/create_schema_files.php (only available through SVN) -	*/ +	 * {@inheritDoc} +	 */  	function perform_schema_changes($schema_changes)  	{  		if (empty($schema_changes)) @@ -1079,13 +860,9 @@ class tools  	}  	/** -	* Gets a list of columns of a table. -	* -	* @param string $table		Table name -	* -	* @return array				Array of column names (all lower case) -	*/ -	function sql_list_columns($table) +	 * {@inheritDoc} +	 */ +	function sql_list_columns($table_name)  	{  		$columns = array(); @@ -1093,33 +870,13 @@ class tools  		{  			case 'mysql_40':  			case 'mysql_41': -				$sql = "SHOW COLUMNS FROM $table"; -			break; - -			// PostgreSQL has a way of doing this in a much simpler way but would -			// not allow us to support all versions of PostgreSQL -			case 'postgres': -				$sql = "SELECT a.attname -					FROM pg_class c, pg_attribute a -					WHERE c.relname = '{$table}' -						AND a.attnum > 0 -						AND a.attrelid = c.oid"; -			break; - -			// same deal with PostgreSQL, we must perform more complex operations than -			// we technically could -			case 'mssql': -			case 'mssqlnative': -				$sql = "SELECT c.name -					FROM syscolumns c -					LEFT JOIN sysobjects o ON c.id = o.id -					WHERE o.name = '{$table}'"; +				$sql = "SHOW COLUMNS FROM $table_name";  			break;  			case 'oracle':  				$sql = "SELECT column_name  					FROM user_tab_columns -					WHERE LOWER(table_name) = '" . strtolower($table) . "'"; +					WHERE LOWER(table_name) = '" . strtolower($table_name) . "'";  			break;  			case 'sqlite': @@ -1127,7 +884,7 @@ class tools  				$sql = "SELECT sql  					FROM sqlite_master  					WHERE type = 'table' -						AND name = '{$table}'"; +						AND name = '{$table_name}'";  				$result = $this->db->sql_query($sql); @@ -1173,64 +930,22 @@ class tools  	}  	/** -	* Check whether a specified column exist in a table -	* -	* @param string	$table			Table to check -	* @param string	$column_name	Column to check -	* -	* @return bool		True if column exists, false otherwise -	*/ -	function sql_column_exists($table, $column_name) +	 * {@inheritDoc} +	 */ +	function sql_column_exists($table_name, $column_name)  	{ -		$columns = $this->sql_list_columns($table); +		$columns = $this->sql_list_columns($table_name);  		return isset($columns[$column_name]);  	}  	/** -	* Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. -	* -	* @param string	$table_name		Table to check the index at -	* @param string	$index_name		The index name to check -	* -	* @return bool True if index exists, else false -	*/ +	 * {@inheritDoc} +	 */  	function sql_index_exists($table_name, $index_name)  	{ -		if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') -		{ -			$sql = "EXEC sp_statistics '$table_name'"; -			$result = $this->db->sql_query($sql); - -			while ($row = $this->db->sql_fetchrow($result)) -			{ -				if ($row['TYPE'] == 3) -				{ -					if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) -					{ -						$this->db->sql_freeresult($result); -						return true; -					} -				} -			} -			$this->db->sql_freeresult($result); - -			return false; -		} -  		switch ($this->sql_layer)  		{ -			case 'postgres': -				$sql = "SELECT ic.relname as index_name -					FROM pg_class bc, pg_class ic, pg_index i -					WHERE (bc.oid = i.indrelid) -						AND (ic.oid = i.indexrelid) -						AND (bc.relname = '" . $table_name . "') -						AND (i.indisunique != 't') -						AND (i.indisprimary != 't')"; -				$col = 'index_name'; -			break; -  			case 'mysql_40':  			case 'mysql_41':  				$sql = 'SHOW KEYS @@ -1266,7 +981,6 @@ class tools  			switch ($this->sql_layer)  			{  				case 'oracle': -				case 'postgres':  				case 'sqlite':  				case 'sqlite3':  					$row[$col] = substr($row[$col], strlen($table_name) + 1); @@ -1285,48 +999,12 @@ class tools  	}  	/** -	* Check if a specified index exists in table. Does not return PRIMARY KEY indexes. -	* -	* @param string	$table_name		Table to check the index at -	* @param string	$index_name		The index name to check -	* -	* @return bool True if index exists, else false -	*/ +	 * {@inheritDoc} +	 */  	function sql_unique_index_exists($table_name, $index_name)  	{ -		if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') -		{ -			$sql = "EXEC sp_statistics '$table_name'"; -			$result = $this->db->sql_query($sql); - -			while ($row = $this->db->sql_fetchrow($result)) -			{ -				// Usually NON_UNIQUE is the column we want to check, but we allow for both -				if ($row['TYPE'] == 3) -				{ -					if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) -					{ -						$this->db->sql_freeresult($result); -						return true; -					} -				} -			} -			$this->db->sql_freeresult($result); -			return false; -		} -  		switch ($this->sql_layer)  		{ -			case 'postgres': -				$sql = "SELECT ic.relname as index_name, i.indisunique -					FROM pg_class bc, pg_class ic, pg_index i -					WHERE (bc.oid = i.indrelid) -						AND (ic.oid = i.indexrelid) -						AND (bc.relname = '" . $table_name . "') -						AND (i.indisprimary != 't')"; -				$col = 'index_name'; -			break; -  			case 'mysql_40':  			case 'mysql_41':  				$sql = 'SHOW KEYS @@ -1363,11 +1041,6 @@ class tools  				continue;  			} -			if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't') -			{ -				continue; -			} -  			// These DBMS prefix index name with the table name  			switch ($this->sql_layer)  			{ @@ -1383,7 +1056,6 @@ class tools  					}  				break; -				case 'postgres':  				case 'sqlite':  				case 'sqlite3':  					$row[$col] = substr($row[$col], strlen($table_name) + 1); @@ -1458,50 +1130,6 @@ class tools  		switch ($this->sql_layer)  		{ -			case 'mssql': -			case 'mssqlnative': -				$sql .= " {$column_type} "; -				$sql_default = " {$column_type} "; - -				// For adding columns we need the default definition -				if (!is_null($column_data[1])) -				{ -					// For hexadecimal values do not use single quotes -					if (strpos($column_data[1], '0x') === 0) -					{ -						$return_array['default'] = 'DEFAULT (' . $column_data[1] . ') '; -						$sql_default .= $return_array['default']; -					} -					else -					{ -						$return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; -						$sql_default .= $return_array['default']; -					} -				} - -				if (isset($column_data[2]) && $column_data[2] == 'auto_increment') -				{ -//					$sql .= 'IDENTITY (1, 1) '; -					$sql_default .= 'IDENTITY (1, 1) '; -				} - -				$return_array['textimage'] = $column_type === '[text]'; - -				if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment')) -				{ -					$sql .= 'NOT NULL'; -					$sql_default .= 'NOT NULL'; -				} -				else -				{ -					$sql .= 'NULL'; -					$sql_default .= 'NULL'; -				} - -				$return_array['column_type_sql_default'] = $sql_default; - -			break; -  			case 'mysql_40':  			case 'mysql_41':  				$sql .= " {$column_type} "; @@ -1555,51 +1183,6 @@ class tools  			break; -			case 'postgres': -				$return_array['column_type'] = $column_type; - -				$sql .= " {$column_type} "; - -				$return_array['auto_increment'] = false; -				if (isset($column_data[2]) && $column_data[2] == 'auto_increment') -				{ -					$default_val = "nextval('{$table_name}_seq')"; -					$return_array['auto_increment'] = true; -				} -				else if (!is_null($column_data[1])) -				{ -					$default_val = "'" . $column_data[1] . "'"; -					$return_array['null'] = 'NOT NULL'; -					$sql .= 'NOT NULL '; -				} -				else -				{ -					// Integers need to have 0 instead of empty string as default -					if (strpos($column_type, 'INT') === 0) -					{ -						$default_val = '0'; -					} -					else -					{ -						$default_val = "'" . $column_data[1] . "'"; -					} -					$return_array['null'] = 'NULL'; -					$sql .= 'NULL '; -				} - -				$return_array['default'] = $default_val; - -				$sql .= "DEFAULT {$default_val}"; - -				// Unsigned? Then add a CHECK contraint -				if (in_array($orig_column_type, $this->unsigned_types)) -				{ -					$return_array['constraint'] = "CHECK ({$column_name} >= 0)"; -					$sql .= " CHECK ({$column_name} >= 0)"; -				} - -			break; -  			case 'sqlite':  			case 'sqlite3':  				$return_array['primary_key_set'] = false; @@ -1641,6 +1224,7 @@ class tools  	*/  	function get_column_type($column_map_type)  	{ +		$column_type = '';  		if (strpos($column_map_type, ':') !== false)  		{  			list($orig_column_type, $column_length) = explode(':', $column_map_type); @@ -1692,8 +1276,8 @@ class tools  	}  	/** -	* Add new column -	*/ +	 * {@inheritDoc} +	 */  	function sql_column_add($table_name, $column_name, $column_data, $inline = false)  	{  		$column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); @@ -1701,12 +1285,6 @@ class tools  		switch ($this->sql_layer)  		{ -			case 'mssql': -			case 'mssqlnative': -				// Does not support AFTER, only through temporary table -				$statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default']; -			break; -  			case 'mysql_40':  			case 'mysql_41':  				$after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : ''; @@ -1718,33 +1296,6 @@ class tools  				$statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];  			break; -			case 'postgres': -				// Does not support AFTER, only through temporary table -				if (version_compare($this->db->sql_server_info(true), '8.0', '>=')) -				{ -					$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; -				} -				else -				{ -					// old versions cannot add columns with default and null information -					$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint']; - -					if (isset($column_data['null'])) -					{ -						if ($column_data['null'] == 'NOT NULL') -						{ -							$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL'; -						} -					} - -					if (isset($column_data['default'])) -					{ -						$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; -					} -				} - -			break; -  			case 'sqlite':  				if ($inline && $this->return_statements)  				{ @@ -1810,59 +1361,14 @@ class tools  	}  	/** -	* Drop column -	*/ +	 * {@inheritDoc} +	 */  	function sql_column_remove($table_name, $column_name, $inline = false)  	{  		$statements = array();  		switch ($this->sql_layer)  		{ -			case 'mssql': -			case 'mssqlnative': -				// We need the data here -				$old_return_statements = $this->return_statements; -				$this->return_statements = true; - -				$indexes = $this->get_existing_indexes($table_name, $column_name); -				$indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true)); - -				// Drop any indexes -				$recreate_indexes = array(); -				if (!empty($indexes)) -				{ -					foreach ($indexes as $index_name => $index_data) -					{ -						$result = $this->sql_index_drop($table_name, $index_name); -						$statements = array_merge($statements, $result); -						if (sizeof($index_data) > 1) -						{ -							// Remove this column from the index and recreate it -							$recreate_indexes[$index_name] = array_diff($index_data, array($column_name)); -						} -					} -				} - -				// Drop default value constraint -				$result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name); -				$statements = array_merge($statements, $result); - -				// Remove the column -				$statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; - -				if (!empty($recreate_indexes)) -				{ -					// Recreate indexes after we removed the column -					foreach ($recreate_indexes as $index_name => $index_data) -					{ -						$result = $this->sql_create_index($table_name, $index_name, $index_data); -						$statements = array_merge($statements, $result); -					} -				} - -				$this->return_statements = $old_return_statements; -			break; -  			case 'mysql_40':  			case 'mysql_41':  				$statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`'; @@ -1872,10 +1378,6 @@ class tools  				$statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name;  			break; -			case 'postgres': -				$statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"'; -			break; -  			case 'sqlite':  			case 'sqlite3': @@ -1939,26 +1441,20 @@ class tools  	}  	/** -	* Drop Index -	*/ +	 * {@inheritDoc} +	 */  	function sql_index_drop($table_name, $index_name)  	{  		$statements = array();  		switch ($this->sql_layer)  		{ -			case 'mssql': -			case 'mssqlnative': -				$statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name; -			break; -  			case 'mysql_40':  			case 'mysql_41':  				$statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name;  			break;  			case 'oracle': -			case 'postgres':  			case 'sqlite':  			case 'sqlite3':  				$statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name; @@ -1969,8 +1465,8 @@ class tools  	}  	/** -	* Drop Table -	*/ +	 * {@inheritDoc} +	 */  	function sql_table_drop($table_name)  	{  		$statements = array(); @@ -2000,52 +1496,25 @@ class tools  				}  				$this->db->sql_freeresult($result);  			break; - -			case 'postgres': -				// PGSQL does not "tightly" bind sequences and tables, we must guess... -				$sql = "SELECT relname -					FROM pg_class -					WHERE relkind = 'S' -						AND relname = '{$table_name}_seq'"; -				$result = $this->db->sql_query($sql); - -				// We don't even care about storing the results. We already know the answer if we get rows back. -				if ($this->db->sql_fetchrow($result)) -				{ -					$statements[] =  "DROP SEQUENCE {$table_name}_seq;\n"; -				} -				$this->db->sql_freeresult($result); -			break;  		}  		return $this->_sql_run_sql($statements);  	}  	/** -	* Add primary key -	*/ +	 * {@inheritDoc} +	 */  	function sql_create_primary_key($table_name, $column, $inline = false)  	{  		$statements = array();  		switch ($this->sql_layer)  		{ -			case 'postgres':  			case 'mysql_40':  			case 'mysql_41':  				$statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';  			break; -			case 'mssql': -			case 'mssqlnative': -				$sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD "; -				$sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY  CLUSTERED ("; -				$sql .= '[' . implode("],\n\t\t[", $column) . ']'; -				$sql .= ')'; - -				$statements[] = $sql; -			break; -  			case 'oracle':  				$statements[] = 'ALTER TABLE ' . $table_name . ' add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')';  			break; @@ -2106,22 +1575,16 @@ class tools  	}  	/** -	* Add unique index -	*/ +	 * {@inheritDoc} +	 */  	function sql_create_unique_index($table_name, $index_name, $column)  	{  		$statements = array(); -		$table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) -		if (strlen($table_name . '_' . $index_name) - strlen($table_prefix) > 24) -		{ -			$max_length = strlen($table_prefix) + 24; -			trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); -		} +		$this->check_index_name_length($table_name, $index_name);  		switch ($this->sql_layer)  		{ -			case 'postgres':  			case 'oracle':  			case 'sqlite':  			case 'sqlite3': @@ -2132,29 +1595,19 @@ class tools  			case 'mysql_41':  				$statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')';  			break; - -			case 'mssql': -			case 'mssqlnative': -				$statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])'; -			break;  		}  		return $this->_sql_run_sql($statements);  	}  	/** -	* Add index -	*/ +	 * {@inheritDoc} +	 */  	function sql_create_index($table_name, $index_name, $column)  	{  		$statements = array(); -		$table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) -		if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) -		{ -			$max_length = strlen($table_prefix) + 24; -			trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); -		} +		$this->check_index_name_length($table_name, $index_name);  		// remove index length unless MySQL4  		if ('mysql_40' != $this->sql_layer) @@ -2164,7 +1617,6 @@ class tools  		switch ($this->sql_layer)  		{ -			case 'postgres':  			case 'oracle':  			case 'sqlite':  			case 'sqlite3': @@ -2185,99 +1637,79 @@ class tools  			case 'mysql_41':  				$statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . ' (' . implode(', ', $column) . ')';  			break; - -			case 'mssql': -			case 'mssqlnative': -				$statements[] = 'CREATE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])'; -			break;  		}  		return $this->_sql_run_sql($statements);  	}  	/** -	* List all of the indices that belong to a table, -	* does not count: -	* * UNIQUE indices -	* * PRIMARY keys -	*/ +	 * Check whether the index name is too long +	 * +	 * @param string $table_name +	 * @param string $index_name +	 */ +	protected function check_index_name_length($table_name, $index_name) +	{ +		$table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) +		if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) +		{ +			$max_length = strlen($table_prefix) + 24; +			trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); +		} +	} + +	/** +	 * {@inheritDoc} +	 */  	function sql_list_index($table_name)  	{  		$index_array = array(); -		if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') -		{ -			$sql = "EXEC sp_statistics '$table_name'"; -			$result = $this->db->sql_query($sql); -			while ($row = $this->db->sql_fetchrow($result)) -			{ -				if ($row['TYPE'] == 3) -				{ -					$index_array[] = $row['INDEX_NAME']; -				} -			} -			$this->db->sql_freeresult($result); -		} -		else +		switch ($this->sql_layer)  		{ -			switch ($this->sql_layer) -			{ -				case 'postgres': -					$sql = "SELECT ic.relname as index_name -						FROM pg_class bc, pg_class ic, pg_index i -						WHERE (bc.oid = i.indrelid) -							AND (ic.oid = i.indexrelid) -							AND (bc.relname = '" . $table_name . "') -							AND (i.indisunique != 't') -							AND (i.indisprimary != 't')"; -					$col = 'index_name'; +			case 'mysql_40': +			case 'mysql_41': +				$sql = 'SHOW KEYS +					FROM ' . $table_name; +				$col = 'Key_name';  				break; -				case 'mysql_40': -				case 'mysql_41': -					$sql = 'SHOW KEYS -						FROM ' . $table_name; -					$col = 'Key_name'; +			case 'oracle': +				$sql = "SELECT index_name +					FROM user_indexes +					WHERE table_name = '" . strtoupper($table_name) . "' +						AND generated = 'N' +						AND uniqueness = 'NONUNIQUE'"; +				$col = 'index_name';  				break; -				case 'oracle': -					$sql = "SELECT index_name -						FROM user_indexes -						WHERE table_name = '" . strtoupper($table_name) . "' -							AND generated = 'N' -							AND uniqueness = 'NONUNIQUE'"; -					$col = 'index_name'; +			case 'sqlite': +			case 'sqlite3': +				$sql = "PRAGMA index_info('" . $table_name . "');"; +				$col = 'name';  				break; +		} -				case 'sqlite': -				case 'sqlite3': -					$sql = "PRAGMA index_info('" . $table_name . "');"; -					$col = 'name'; -				break; +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) +			{ +				continue;  			} -			$result = $this->db->sql_query($sql); -			while ($row = $this->db->sql_fetchrow($result)) +			switch ($this->sql_layer)  			{ -				if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) -				{ -					continue; -				} - -				switch ($this->sql_layer) -				{ -					case 'oracle': -					case 'postgres': -					case 'sqlite': -					case 'sqlite3': -						$row[$col] = substr($row[$col], strlen($table_name) + 1); +				case 'oracle': +				case 'sqlite': +				case 'sqlite3': +					$row[$col] = substr($row[$col], strlen($table_name) + 1);  					break; -				} - -				$index_array[] = $row[$col];  			} -			$this->db->sql_freeresult($result); + +			$index_array[] = $row[$col];  		} +		$this->db->sql_freeresult($result);  		return array_map('strtolower', $index_array);  	} @@ -2295,8 +1727,8 @@ class tools  	}  	/** -	* Change column type (not name!) -	*/ +	 * {@inheritDoc} +	 */  	function sql_column_change($table_name, $column_name, $column_data, $inline = false)  	{  		$original_column_data = $column_data; @@ -2305,62 +1737,6 @@ class tools  		switch ($this->sql_layer)  		{ -			case 'mssql': -			case 'mssqlnative': -				// We need the data here -				$old_return_statements = $this->return_statements; -				$this->return_statements = true; - -				$indexes = $this->get_existing_indexes($table_name, $column_name); -				$unique_indexes = $this->get_existing_indexes($table_name, $column_name, true); - -				// Drop any indexes -				if (!empty($indexes) || !empty($unique_indexes)) -				{ -					$drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes)); -					foreach ($drop_indexes as $index_name) -					{ -						$result = $this->sql_index_drop($table_name, $index_name); -						$statements = array_merge($statements, $result); -					} -				} - -				// Drop default value constraint -				$result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name); -				$statements = array_merge($statements, $result); - -				// Change the column -				$statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; - -				if (!empty($column_data['default'])) -				{ -					// Add new default value constraint -					$statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $this->db->sql_escape($column_data['default']) . ' FOR [' . $column_name . ']'; -				} - -				if (!empty($indexes)) -				{ -					// Recreate indexes after we changed the column -					foreach ($indexes as $index_name => $index_data) -					{ -						$result = $this->sql_create_index($table_name, $index_name, $index_data); -						$statements = array_merge($statements, $result); -					} -				} - -				if (!empty($unique_indexes)) -				{ -					// Recreate unique indexes after we changed the column -					foreach ($unique_indexes as $index_name => $index_data) -					{ -						$result = $this->sql_create_unique_index($table_name, $index_name, $index_data); -						$statements = array_merge($statements, $result); -					} -				} - -				$this->return_statements = $old_return_statements; -			break; -  			case 'mysql_40':  			case 'mysql_41':  				$statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql']; @@ -2432,69 +1808,6 @@ class tools  				$this->return_statements = $old_return_statements;  			break; -			case 'postgres': -				$sql = 'ALTER TABLE ' . $table_name . ' '; - -				$sql_array = array(); -				$sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type']; - -				if (isset($column_data['null'])) -				{ -					if ($column_data['null'] == 'NOT NULL') -					{ -						$sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL'; -					} -					else if ($column_data['null'] == 'NULL') -					{ -						$sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL'; -					} -				} - -				if (isset($column_data['default'])) -				{ -					$sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; -				} - -				// we don't want to double up on constraints if we change different number data types -				if (isset($column_data['constraint'])) -				{ -					$constraint_sql = "SELECT consrc as constraint_data -								FROM pg_constraint, pg_class bc -								WHERE conrelid = bc.oid -									AND bc.relname = '{$table_name}' -									AND NOT EXISTS ( -										SELECT * -											FROM pg_constraint as c, pg_inherits as i -											WHERE i.inhrelid = pg_constraint.conrelid -												AND c.conname = pg_constraint.conname -												AND c.consrc = pg_constraint.consrc -												AND c.conrelid = i.inhparent -									)"; - -					$constraint_exists = false; - -					$result = $this->db->sql_query($constraint_sql); -					while ($row = $this->db->sql_fetchrow($result)) -					{ -						if (trim($row['constraint_data']) == trim($column_data['constraint'])) -						{ -							$constraint_exists = true; -							break; -						} -					} -					$this->db->sql_freeresult($result); - -					if (!$constraint_exists) -					{ -						$sql_array[] = 'ADD ' . $column_data['constraint']; -					} -				} - -				$sql .= implode(', ', $sql_array); - -				$statements[] = $sql; -			break; -  			case 'sqlite':  			case 'sqlite3': @@ -2563,52 +1876,6 @@ class tools  	}  	/** -	* Get queries to drop the default constraints of a column -	* -	* We need to drop the default constraints of a column, -	* before being able to change their type or deleting them. -	* -	* @param string $table_name -	* @param string $column_name -	* @return array		Array with SQL statements -	*/ -	protected function mssql_get_drop_default_constraints_queries($table_name, $column_name) -	{ -		$statements = array(); -		if ($this->mssql_is_sql_server_2000()) -		{ -			// http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx -			// Deprecated in SQL Server 2005 -			$sql = "SELECT so.name AS def_name -				FROM sysobjects so -				JOIN sysconstraints sc ON so.id = sc.constid -				WHERE object_name(so.parent_obj) = '{$table_name}' -					AND so.xtype = 'D' -					AND sc.colid = (SELECT colid FROM syscolumns -						WHERE id = object_id('{$table_name}') -							AND name = '{$column_name}')"; -		} -		else -		{ -			$sql = "SELECT dobj.name AS def_name -				FROM sys.columns col -					LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D') -				WHERE col.object_id = object_id('{$table_name}') -					AND col.name = '{$column_name}' -					AND dobj.name IS NOT NULL"; -		} - -		$result = $this->db->sql_query($sql); -		while ($row = $this->db->sql_fetchrow($result)) -		{ -			$statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']'; -		} -		$this->db->sql_freeresult($result); - -		return $statements; -	} - -	/**  	* Get a list with existing indexes for the column  	*  	* @param string $table_name @@ -2622,7 +1889,6 @@ class tools  		{  			case 'mysql_40':  			case 'mysql_41': -			case 'postgres':  			case 'sqlite':  			case 'sqlite3':  				// Not supported @@ -2635,40 +1901,6 @@ class tools  		switch ($this->sql_layer)  		{ -			case 'mssql': -			case 'mssqlnative': -				if ($this->mssql_is_sql_server_2000()) -				{ -					// http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx -					// Deprecated in SQL Server 2005 -					$sql = "SELECT DISTINCT ix.name AS phpbb_index_name -					FROM sysindexes ix -					INNER JOIN sysindexkeys ixc -						ON ixc.id = ix.id -							AND ixc.indid = ix.indid -					INNER JOIN syscolumns cols -						ON cols.colid = ixc.colid -							AND cols.id = ix.id -					WHERE ix.id = object_id('{$table_name}') -						AND cols.name = '{$column_name}' -						AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0'); -				} -				else -				{ -					$sql = "SELECT DISTINCT ix.name AS phpbb_index_name -					FROM sys.indexes ix -					INNER JOIN sys.index_columns ixc -						ON ixc.object_id = ix.object_id -							AND ixc.index_id = ix.index_id -					INNER JOIN sys.columns cols -						ON cols.column_id = ixc.column_id -							AND cols.object_id = ix.object_id -					WHERE ix.object_id = object_id('{$table_name}') -						AND cols.name = '{$column_name}' -						AND ix.is_unique = " . ($unique ? '1' : '0'); -				} -			break; -  			case 'oracle':  				$sql = "SELECT ix.index_name  AS phpbb_index_name, ix.uniqueness AS is_unique  					FROM all_ind_columns ixc, all_indexes ix @@ -2695,36 +1927,6 @@ class tools  		switch ($this->sql_layer)  		{ -			case 'mssql': -			case 'mssqlnative': -				if ($this->mssql_is_sql_server_2000()) -				{ -					$sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name -						FROM sysindexes ix -						INNER JOIN sysindexkeys ixc -							ON ixc.id = ix.id -								AND ixc.indid = ix.indid -						INNER JOIN syscolumns cols -							ON cols.colid = ixc.colid -								AND cols.id = ix.id -						WHERE ix.id = object_id('{$table_name}') -							AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); -				} -				else -				{ -					$sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name -						FROM sys.indexes ix -						INNER JOIN sys.index_columns ixc -							ON ixc.object_id = ix.object_id -								AND ixc.index_id = ix.index_id -						INNER JOIN sys.columns cols -							ON cols.column_id = ixc.column_id -								AND cols.object_id = ix.object_id -						WHERE ix.object_id = object_id('{$table_name}') -							AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes)); -				} -			break; -  			case 'oracle':  				$sql = "SELECT index_name AS phpbb_index_name, column_name AS phpbb_column_name  					FROM all_ind_columns @@ -2744,25 +1946,6 @@ class tools  	}  	/** -	* Is the used MS SQL Server a SQL Server 2000? -	* -	* @return bool -	*/ -	protected function mssql_is_sql_server_2000() -	{ -		if ($this->is_sql_server_2000 === null) -		{ -			$sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version"; -			$result = $this->db->sql_query($sql); -			$properties = $this->db->sql_fetchrow($result); -			$this->db->sql_freeresult($result); -			$this->is_sql_server_2000 = $properties['mssql_version'][0] == '8'; -		} - -		return $this->is_sql_server_2000; -	} - -	/**  	* Returns the Queries which are required to recreate a table including indexes  	*  	* @param string $table_name diff --git a/phpBB/phpbb/db/tools/tools_interface.php b/phpBB/phpbb/db/tools/tools_interface.php new file mode 100644 index 0000000000..f153f73a54 --- /dev/null +++ b/phpBB/phpbb/db/tools/tools_interface.php @@ -0,0 +1,202 @@ +<?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\tools; + +/** + * Interface for a Database Tools for handling cross-db actions such as altering columns, etc. + */ +interface tools_interface +{ +	/** +	 * Handle passed database update array. +	 * Expected structure... +	 * Key being one of the following +	 *	drop_tables: Drop tables +	 *	add_tables: Add tables +	 *	change_columns: Column changes (only type, not name) +	 *	add_columns: Add columns to a table +	 *	drop_keys: Dropping keys +	 *	drop_columns: Removing/Dropping columns +	 *	add_primary_keys: adding primary keys +	 *	add_unique_index: adding an unique index +	 *	add_index: adding an index (can be column:index_size if you need to provide size) +	 * +	 * The values are in this format: +	 *		{TABLE NAME}		=> array( +	 *			{COLUMN NAME}		=> array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}), +	 *			{KEY/INDEX NAME}	=> array({COLUMN NAMES}), +	 *		) +	 * +	 * +	 * @param array $schema_changes +	 * @return null +	 */ +	public function perform_schema_changes($schema_changes); + +	/** +	 * Gets a list of tables in the database. +	 * +	 * @return array		Array of table names  (all lower case) +	 */ +	public function sql_list_tables(); + +	/** +	 * Check if table exists +	 * +	 * @param string	$table_name	The table name to check for +	 * @return bool true if table exists, else false +	 */ +	public function sql_table_exists($table_name); + +	/** +	 * Create SQL Table +	 * +	 * @param string	$table_name		The table name to create +	 * @param array		$table_data		Array containing table data. +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_create_table($table_name, $table_data); + +	/** +	 * Drop Table +	 * +	 * @param string	$table_name		The table name to drop +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_table_drop($table_name); + +	/** +	 * Gets a list of columns of a table. +	 * +	 * @param string $table_name	Table name +	 * @return array		Array of column names (all lower case) +	 */ +	public function sql_list_columns($table_name); + +	/** +	 * Check whether a specified column exist in a table +	 * +	 * @param string	$table_name		Table to check +	 * @param string	$column_name	Column to check +	 * @return bool		True if column exists, false otherwise +	 */ +	public function sql_column_exists($table_name, $column_name); + +	/** +	 * Add new column +	 * +	 * @param string	$table_name		Table to modify +	 * @param string	$column_name	Name of the column to add +	 * @param array		$column_data	Column data +	 * @param bool		$inline			Whether the query should actually be run, +	 *						or return a string for adding the column +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_column_add($table_name, $column_name, $column_data, $inline = false); + +	/** +	 * Change column type (not name!) +	 * +	 * @param string	$table_name		Table to modify +	 * @param string	$column_name	Name of the column to modify +	 * @param array		$column_data	Column data +	 * @param bool		$inline			Whether the query should actually be run, +	 *						or return a string for modifying the column +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_column_change($table_name, $column_name, $column_data, $inline = false); + +	/** +	 * Drop column +	 * +	 * @param string	$table_name		Table to modify +	 * @param string	$column_name	Name of the column to drop +	 * @param bool		$inline			Whether the query should actually be run, +	 *						or return a string for deleting the column +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_column_remove($table_name, $column_name, $inline = false); + +	/** +	 * List all of the indices that belong to a table +	 * +	 * NOTE: does not list +	 * - UNIQUE indices +	 * - PRIMARY keys +	 * +	 * @param string	$table_name		Table to check +	 * @return array		Array with index names +	 */ +	public function sql_list_index($table_name); + +	/** +	 * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. +	 * +	 * @param string	$table_name		Table to check the index at +	 * @param string	$index_name		The index name to check +	 * @return bool			True if index exists, else false +	 */ +	public function sql_index_exists($table_name, $index_name); + +	/** +	 * Add index +	 * +	 * @param string	$table_name		Table to modify +	 * @param string	$index_name		Name of the index to create +	 * @param string|array	$column		Either a string with a column name, or an array with columns +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_create_index($table_name, $index_name, $column); + +	/** +	 * Drop Index +	 * +	 * @param string	$table_name		Table to modify +	 * @param string	$index_name		Name of the index to delete +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_index_drop($table_name, $index_name); + +	/** +	 * Check if a specified index exists in table. +	 * +	 * NOTE: Does not return normal and PRIMARY KEY indexes +	 * +	 * @param string	$table_name		Table to check the index at +	 * @param string	$index_name		The index name to check +	 * @return bool True if index exists, else false +	 */ +	public function sql_unique_index_exists($table_name, $index_name); + +	/** +	 * Add unique index +	 * +	 * @param string	$table_name		Table to modify +	 * @param string	$index_name		Name of the unique index to create +	 * @param string|array	$column		Either a string with a column name, or an array with columns +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_create_unique_index($table_name, $index_name, $column); + +	/** +	 * Add primary key +	 * +	 * @param string	$table_name		Table to modify +	 * @param string|array	$column		Either a string with a column name, or an array with columns +	 * @param bool		$inline			Whether the query should actually be run, +	 *						or return a string for creating the key +	 * @return array|true	Statements to run, or true if the statements have been executed +	 */ +	public function sql_create_primary_key($table_name, $column, $inline = false); +} diff --git a/phpBB/phpbb/di/container_builder.php b/phpBB/phpbb/di/container_builder.php index 638c13e86d..125ae28e9b 100644 --- a/phpBB/phpbb/di/container_builder.php +++ b/phpBB/phpbb/di/container_builder.php @@ -13,16 +13,25 @@  namespace phpbb\di; +use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Config\FileLocator;  use Symfony\Component\DependencyInjection\ContainerBuilder;  use Symfony\Component\DependencyInjection\Dumper\PhpDumper; -use Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; +use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;  class container_builder  { -	/** @var string phpBB Root Path */ +	/** +	 * @var string phpBB Root Path +	 */  	protected $phpbb_root_path; -	/** @var string php file extension  */ +	/** +	 * @var string php file extension +	 */  	protected $php_ext;  	/** @@ -112,6 +121,11 @@ class container_builder  	protected $config_php_file;  	/** +	 * @var string +	 */ +	protected $cache_dir; + +	/**  	* Constructor  	*  	* @param \phpbb\config_php_file $config_php_file @@ -133,23 +147,30 @@ class container_builder  	public function get_container()  	{  		$container_filename = $this->get_container_filename(); -		if (!defined('DEBUG_CONTAINER') && $this->dump_container && file_exists($container_filename)) +		$config_cache = new ConfigCache($container_filename, defined('DEBUG')); +		if ($this->dump_container && $config_cache->isFresh())  		{  			require($container_filename);  			$this->container = new \phpbb_cache_container();  		}  		else  		{ -			if ($this->config_path === null) -			{ -				$this->config_path = $this->phpbb_root_path . 'config'; -			} -			$container_extensions = array(new \phpbb\di\extension\core($this->config_path)); +			$container_extensions = array(new \phpbb\di\extension\core($this->get_config_path()));  			if ($this->use_extensions)  			{  				$installed_exts = $this->get_installed_extensions(); -				$container_extensions[] = new \phpbb\di\extension\ext($installed_exts); +				foreach ($installed_exts as $ext_name => $path) +				{ +					$extension_class = '\\' . str_replace('/', '\\', $ext_name) . '\\di\\extension'; + +					if (!class_exists($extension_class)) +					{ +						$extension_class = '\phpbb\extension\di\extension_base'; +					} + +					$container_extensions[] = new $extension_class($ext_name, $path); +				}  			}  			if ($this->inject_config) @@ -171,6 +192,9 @@ class container_builder  				}  			} +			$loader = new YamlFileLoader($this->container, new FileLocator(phpbb_realpath($this->get_config_path()))); +			$loader->load($this->container->getParameter('core.environment') . '/config.yml'); +  			$this->inject_custom_parameters();  			if ($this->compile_container) @@ -178,9 +202,9 @@ class container_builder  				$this->container->compile();  			} -			if ($this->dump_container && !defined('DEBUG_CONTAINER')) +			if ($this->dump_container)  			{ -				$this->dump_container($container_filename); +				$this->dump_container($config_cache);  			}  		} @@ -267,6 +291,16 @@ class container_builder  	}  	/** +	 * Returns the path to the container configuration (default: root_path/config) +	 * +	 * @return string +	 */ +	protected function get_config_path() +	{ +		return $this->config_path ?: $this->phpbb_root_path . 'config'; +	} + +	/**  	* Set custom parameters to inject into the container.  	*  	* @param array $custom_parameters @@ -277,11 +311,31 @@ class container_builder  	}  	/** +	 * Set the path to the cache directory. +	 * +	 * @param string $cache_dir Path to the cache directory +	 */ +	public function set_cache_dir($cache_dir) +	{ +		$this->cache_dir = $cache_dir; +	} + +	/** +	 * Returns the path to the cache directory (default: root_path/cache/environment). +	 * +	 * @return string Path to the cache directory. +	 */ +	protected function get_cache_dir() +	{ +		return $this->cache_dir ?: $this->phpbb_root_path . 'cache/' . $this->get_environment() . '/'; +	} + +	/**  	* Dump the container to the disk.  	* -	* @param string $container_filename The name of the file. +	* @param ConfigCache $cache The config cache  	*/ -	protected function dump_container($container_filename) +	protected function dump_container($cache)  	{  		$dumper = new PhpDumper($this->container);  		$cached_container_dump = $dumper->dump(array( @@ -289,7 +343,7 @@ class container_builder  			'base_class'    => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder',  		)); -		file_put_contents($container_filename, $cached_container_dump); +		$cache->write($cached_container_dump, $this->container->getResources());  	}  	/** @@ -362,34 +416,73 @@ class container_builder  	*/  	protected function create_container(array $extensions)  	{ -		$container = new ContainerBuilder(); +		$container = new ContainerBuilder(new ParameterBag($this->get_core_parameters())); + +		$extensions_alias = array();  		foreach ($extensions as $extension)  		{  			$container->registerExtension($extension); -			$container->loadFromExtension($extension->getAlias()); +			$extensions_alias[] = $extension->getAlias(); +			//$container->loadFromExtension($extension->getAlias());  		} +		$container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias)); +  		return $container;  	}  	/** -	* Inject the customs parameters into the container -	*/ +	 * Inject the customs parameters into the container +	 */  	protected function inject_custom_parameters()  	{ -		if ($this->custom_parameters === null) +		if ($this->custom_parameters !== null)  		{ -			$this->custom_parameters = array( -				'core.root_path' => $this->phpbb_root_path, -				'core.php_ext' => $this->php_ext, -			); +			foreach ($this->custom_parameters as $key => $value) +			{ +				$this->container->setParameter($key, $value); +			}  		} +	} -		foreach ($this->custom_parameters as $key => $value) +	/** +	 * Returns the core parameters. +	 * +	 * @return array An array of core parameters +	 */ +	protected function get_core_parameters() +	{ +		return array_merge( +			array( +				'core.root_path'     => $this->phpbb_root_path, +				'core.php_ext'       => $this->php_ext, +				'core.environment'   => $this->get_environment(), +				'core.debug'         => DEBUG, +			), +			$this->get_env_parameters() +		); +	} + +	/** +	 * Gets the environment parameters. +	 * +	 * Only the parameters starting with "PHPBB__" are considered. +	 * +	 * @return array An array of parameters +	 */ +	protected function get_env_parameters() +	{ +		$parameters = array(); +		foreach ($_SERVER as $key => $value)  		{ -			$this->container->setParameter($key, $value); +			if (0 === strpos($key, 'PHPBB__')) +			{ +				$parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value; +			}  		} + +		return $parameters;  	}  	/** @@ -400,6 +493,16 @@ class container_builder  	protected function get_container_filename()  	{  		$filename = str_replace(array('/', '.'), array('slash', 'dot'), $this->phpbb_root_path); -		return $this->phpbb_root_path . 'cache/container_' . $filename . '.' . $this->php_ext; +		return $this->get_cache_dir() . 'container_' . $filename . '.' . $this->php_ext; +	} + +	/** +	 * Return the name of the current environment. +	 * +	 * @return string +	 */ +	protected function get_environment() +	{ +		return PHPBB_ENVIRONMENT;  	}  } diff --git a/phpBB/phpbb/di/extension/container_configuration.php b/phpBB/phpbb/di/extension/container_configuration.php new file mode 100644 index 0000000000..ee58ec2b74 --- /dev/null +++ b/phpBB/phpbb/di/extension/container_configuration.php @@ -0,0 +1,44 @@ +<?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\di\extension; + +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; + +class container_configuration implements ConfigurationInterface +{ + +	/** +	 * Generates the configuration tree builder. +	 * +	 * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder +	 */ +	public function getConfigTreeBuilder() +	{ +		$treeBuilder = new TreeBuilder(); +		$rootNode = $treeBuilder->root('core'); +		$rootNode +			->children() +				->booleanNode('require_dev_dependencies')->defaultValue(false)->end() +				->arrayNode('twig') +					->addDefaultsIfNotSet() +					->children() +						->booleanNode('enable_debug_extension')->defaultValue(false)->end() +					->end() +				->end() +			->end() +		; +		return $treeBuilder; +	} +} diff --git a/phpBB/phpbb/di/extension/core.php b/phpBB/phpbb/di/extension/core.php index ca4fa5c082..451efc8e35 100644 --- a/phpBB/phpbb/di/extension/core.php +++ b/phpBB/phpbb/di/extension/core.php @@ -13,10 +13,11 @@  namespace phpbb\di\extension; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Resource\FileResource;  use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\DependencyInjection\Extension;  use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\Config\FileLocator; +use Symfony\Component\HttpKernel\DependencyInjection\Extension;  /**  * Container core extension @@ -24,42 +25,74 @@ use Symfony\Component\Config\FileLocator;  class core extends Extension  {  	/** -	* Config path -	* @var string -	*/ +	 * Config path +	 * @var string +	 */  	protected $config_path;  	/** -	* Constructor -	* -	* @param string $config_path Config path -	*/ +	 * Constructor +	 * +	 * @param string $config_path Config path +	 */  	public function __construct($config_path)  	{  		$this->config_path = $config_path;  	}  	/** -	* Loads a specific configuration. -	* -	* @param array            $config    An array of configuration values -	* @param ContainerBuilder $container A ContainerBuilder instance -	* -	* @throws \InvalidArgumentException When provided tag is not defined in this extension -	*/ -	public function load(array $config, ContainerBuilder $container) +	 * Loads a specific configuration. +	 * +	 * @param array            $configs   An array of configuration values +	 * @param ContainerBuilder $container A ContainerBuilder instance +	 * +	 * @throws \InvalidArgumentException When provided tag is not defined in this extension +	 */ +	public function load(array $configs, ContainerBuilder $container)  	{  		$loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($this->config_path))); -		$loader->load('services.yml'); +		$loader->load($container->getParameter('core.environment') . '/container/environment.yml'); + +		$config = $this->getConfiguration($configs, $container); +		$config = $this->processConfiguration($config, $configs); + +		if ($config['require_dev_dependencies']) +		{ +			if (!class_exists('Goutte\Client', true)) +			{ +				trigger_error( +					'Composer development dependencies have not been set up for the ' . $container->getParameter('core.environment') . ' environment yet, run ' . +					"'php ../composer.phar install --dev' from the phpBB directory to do so.", +					E_USER_ERROR +				); +			} +		} + +		if ($config['twig']['enable_debug_extension']) +		{ +			$definition = $container->getDefinition('template.twig.extensions.debug'); +			$definition->addTag('twig.extension'); +		} +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function getConfiguration(array $config, ContainerBuilder $container) +	{ +		$r = new \ReflectionClass('\phpbb\di\extension\container_configuration'); +		$container->addResource(new FileResource($r->getFileName())); + +		return new container_configuration();  	}  	/** -	* Returns the recommended alias to use in XML. -	* -	* This alias is also the mandatory prefix to use when using YAML. -	* -	* @return string The alias -	*/ +	 * Returns the recommended alias to use in XML. +	 * +	 * This alias is also the mandatory prefix to use when using YAML. +	 * +	 * @return string The alias +	 */  	public function getAlias()  	{  		return 'core'; diff --git a/phpBB/phpbb/di/extension/ext.php b/phpBB/phpbb/di/extension/ext.php deleted file mode 100644 index 718c992d2e..0000000000 --- a/phpBB/phpbb/di/extension/ext.php +++ /dev/null @@ -1,67 +0,0 @@ -<?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\di\extension; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\Config\FileLocator; - -/** -* Container ext extension -*/ -class ext extends Extension -{ -	protected $paths = array(); - -	public function __construct($enabled_extensions) -	{ -		foreach ($enabled_extensions as $ext => $path) -		{ -			$this->paths[] = $path; -		} -	} - -	/** -	* Loads a specific configuration. -	* -	* @param array            $config    An array of configuration values -	* @param ContainerBuilder $container A ContainerBuilder instance -	* -	* @throws \InvalidArgumentException When provided tag is not defined in this extension -	*/ -	public function load(array $config, ContainerBuilder $container) -	{ -		foreach ($this->paths as $path) -		{ -			if (file_exists($path . '/config/services.yml')) -			{ -				$loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($path . '/config'))); -				$loader->load('services.yml'); -			} -		} -	} - -	/** -	* Returns the recommended alias to use in XML. -	* -	* This alias is also the mandatory prefix to use when using YAML. -	* -	* @return string The alias -	*/ -	public function getAlias() -	{ -		return 'ext'; -	} -} diff --git a/phpBB/phpbb/event/kernel_request_subscriber.php b/phpBB/phpbb/event/kernel_request_subscriber.php deleted file mode 100644 index ee9f29a59d..0000000000 --- a/phpBB/phpbb/event/kernel_request_subscriber.php +++ /dev/null @@ -1,82 +0,0 @@ -<?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\event; - -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\EventListener\RouterListener; -use Symfony\Component\Routing\RequestContext; - -class kernel_request_subscriber implements EventSubscriberInterface -{ -	/** -	* Extension manager object -	* @var \phpbb\extension\manager -	*/ -	protected $manager; - -	/** -	* PHP file extension -	* @var string -	*/ -	protected $php_ext; - -	/** -	* Root path -	* @var string -	*/ -	protected $root_path; - -	/** -	* Construct method -	* -	* @param \phpbb\extension\manager $manager Extension manager object -	* @param string $root_path Root path -	* @param string $php_ext PHP file extension -	*/ -	public function __construct(\phpbb\extension\manager $manager, $root_path, $php_ext) -	{ -		$this->root_path = $root_path; -		$this->php_ext = $php_ext; -		$this->manager = $manager; -	} - -	/** -	* This listener is run when the KernelEvents::REQUEST event is triggered -	* -	* This is responsible for setting up the routing information -	* -	* @param GetResponseEvent $event -	* @throws \BadMethodCallException -	* @return null -	*/ -	public function on_kernel_request(GetResponseEvent $event) -	{ -		$request = $event->getRequest(); -		$context = new RequestContext(); -		$context->fromRequest($request); - -		$matcher = phpbb_get_url_matcher($this->manager, $context, $this->root_path, $this->php_ext); -		$router_listener = new RouterListener($matcher, $context); -		$router_listener->onKernelRequest($event); -	} - -	public static function getSubscribedEvents() -	{ -		return array( -			KernelEvents::REQUEST		=> 'on_kernel_request', -		); -	} -} diff --git a/phpBB/phpbb/event/md_exporter.php b/phpBB/phpbb/event/md_exporter.php index f7021875f3..84b10e79c1 100644 --- a/phpBB/phpbb/event/md_exporter.php +++ b/phpBB/phpbb/event/md_exporter.php @@ -89,7 +89,7 @@ class md_exporter  	{  		$this->crawl_eventsmd($md_file, 'styles'); -		$styles = array('prosilver', 'subsilver2'); +		$styles = array('prosilver');  		foreach ($styles as $style)  		{  			$file_list = $this->get_recursive_file_list( @@ -179,7 +179,7 @@ class md_exporter  		{  			$wiki_page = '= Template Events =' . "\n";  			$wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n"; -			$wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Subsilver Placement (If applicable) !! Added in Release !! Explanation' . "\n"; +			$wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Added in Release !! Explanation' . "\n";  		}  		foreach ($this->events as $event_name => $event) @@ -193,7 +193,7 @@ class md_exporter  			}  			else  			{ -				$wiki_page .= implode(', ', $event['files']['prosilver']) . ' || ' . implode(', ', $event['files']['subsilver2']); +				$wiki_page .= implode(', ', $event['files']['prosilver']);  			}  			$wiki_page .= " || {$event['since']} || " . str_replace("\n", ' ', $event['description']) . "\n"; @@ -246,7 +246,6 @@ class md_exporter  	{  		$files_list = array(  			'prosilver'		=> array(), -			'subsilver2'	=> array(),  			'adm'			=> array(),  		); @@ -266,10 +265,6 @@ class md_exporter  				{  					$files_list['prosilver'][] = substr($file, strlen('styles/prosilver/template/'));  				} -				else if (($this->filter !== 'adm') && strpos($file, 'styles/subsilver2/template/') === 0) -				{ -					$files_list['subsilver2'][] = substr($file, strlen('styles/subsilver2/template/')); -				}  				else if (($this->filter === 'adm') && strpos($file, 'adm/style/') === 0)  				{  					$files_list['adm'][] = substr($file, strlen('adm/style/')); diff --git a/phpBB/phpbb/extension/di/extension_base.php b/phpBB/phpbb/extension/di/extension_base.php new file mode 100644 index 0000000000..30cc37dbb6 --- /dev/null +++ b/phpBB/phpbb/extension/di/extension_base.php @@ -0,0 +1,137 @@ +<?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\di; + +use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Resource\FileResource; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; + +/** + * Container core extension + */ +class extension_base extends Extension +{ +	/** +	 * Name of the extension (vendor/name) +	 * +	 * @var string +	 */ +	protected $extension_name; + +	/** +	 * Path to the extension. +	 * +	 * @var string +	 */ +	protected $ext_path; + +	/** +	 * Constructor +	 * +	 * @param string $extension_name Name of the extension (vendor/name) +	 * @param string $ext_path       Path to the extension +	 */ +	public function __construct($extension_name, $ext_path) +	{ +		$this->extension_name = $extension_name; +		$this->ext_path = $ext_path; +	} + +	/** +	 * Loads a specific configuration. +	 * +	 * @param array            $configs   An array of configuration values +	 * @param ContainerBuilder $container A ContainerBuilder instance +	 * +	 * @throws \InvalidArgumentException When provided tag is not defined in this extension +	 */ +	public function load(array $configs, ContainerBuilder $container) +	{ +		$this->load_services($container); +	} + +	/** +	 * Loads the services.yml file. +	 * +	 * @param ContainerBuilder $container A ContainerBuilder instance +	 */ +	protected function load_services(ContainerBuilder $container) +	{ +		$services_directory = false; +		$services_file = false; + +		if (file_exists($this->ext_path . 'config/' . $container->getParameter('core.environment') . '/container/environment.yml')) +		{ +			$services_directory = $this->ext_path . 'config/' . $container->getParameter('core.environment') . '/container/'; +			$services_file = 'environment.yml'; +		} +		else if (!is_dir($this->ext_path . 'config/' . $container->getParameter('core.environment'))) +		{ +			if (file_exists($this->ext_path . 'config/default/container/environment.yml')) +			{ +				$services_directory = $this->ext_path . 'config/default/container/'; +				$services_file = 'environment.yml'; +			} +			else if (!is_dir($this->ext_path . 'config/default') && file_exists($this->ext_path . '/config/services.yml')) +			{ +				$services_directory = $this->ext_path . 'config'; +				$services_file = 'services.yml'; +			} +		} + +		if ($services_directory && $services_file) +		{ +			$loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($services_directory))); +			$loader->load($services_file); +		} +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function getConfiguration(array $config, ContainerBuilder $container) +	{ +		$reflected = new \ReflectionClass($this); +		$namespace = $reflected->getNamespaceName(); + +		$class = $namespace . '\\di\configuration'; +		if (class_exists($class)) +		{ +			$r = new \ReflectionClass($class); +			$container->addResource(new FileResource($r->getFileName())); + +			if (!method_exists($class, '__construct')) +			{ +				$configuration = new $class(); + +				return $configuration; +			} +		} + +	} + +	/** +	 * Returns the recommended alias to use in XML. +	 * +	 * This alias is also the mandatory prefix to use when using YAML. +	 * +	 * @return string The alias +	 */ +	public function getAlias() +	{ +		return str_replace('/', '_', $this->extension_name); +	} +} diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php index 76f0e3558e..880973d5fb 100644 --- a/phpBB/phpbb/extension/manager.php +++ b/phpBB/phpbb/extension/manager.php @@ -464,15 +464,17 @@ class manager  	* All enabled and disabled extensions are considered configured. A purged  	* extension that is no longer in the database is not configured.  	* +	* @param bool $phpbb_relative Whether the path should be relative to phpbb root +	*  	* @return array An array with extension names as keys and and the  	*               database stored extension information as values  	*/ -	public function all_configured() +	public function all_configured($phpbb_relative = true)  	{  		$configured = array();  		foreach ($this->extensions as $name => $data)  		{ -			$data['ext_path'] = $this->phpbb_root_path . $data['ext_path']; +			$data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];  			$configured[$name] = $data;  		}  		return $configured; @@ -480,18 +482,19 @@ class manager  	/**  	* Retrieves all enabled extensions. +	* @param bool $phpbb_relative Whether the path should be relative to phpbb root  	*  	* @return array An array with extension names as keys and and the  	*               database stored extension information as values  	*/ -	public function all_enabled() +	public function all_enabled($phpbb_relative = true)  	{  		$enabled = array();  		foreach ($this->extensions as $name => $data)  		{  			if ($data['ext_active'])  			{ -				$enabled[$name] = $this->phpbb_root_path . $data['ext_path']; +				$enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];  			}  		}  		return $enabled; @@ -500,17 +503,19 @@ class manager  	/**  	* Retrieves all disabled extensions.  	* +	* @param bool $phpbb_relative Whether the path should be relative to phpbb root +	*  	* @return array An array with extension names as keys and and the  	*               database stored extension information as values  	*/ -	public function all_disabled() +	public function all_disabled($phpbb_relative = true)  	{  		$disabled = array();  		foreach ($this->extensions as $name => $data)  		{  			if (!$data['ext_active'])  			{ -				$disabled[$name] = $this->phpbb_root_path . $data['ext_path']; +				$disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];  			}  		}  		return $disabled; diff --git a/phpBB/phpbb/help/controller/help.php b/phpBB/phpbb/help/controller/help.php new file mode 100644 index 0000000000..9cc3b0c8b4 --- /dev/null +++ b/phpBB/phpbb/help/controller/help.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\help\controller; + +use phpbb\exception\http_exception; + +class help +{ +	/** @var \phpbb\controller\helper */ +	protected $helper; + +	/** @var \phpbb\event\dispatcher_interface  */ +	protected $dispatcher; + +	/** @var \phpbb\template\template */ +	protected $template; + +	/** @var \phpbb\user */ +	protected $user; + +	/** @var string */ +	protected $root_path; + +	/** @var string */ +	protected $php_ext; + +	/** +	 * Constructor +	 * +	 * @param \phpbb\controller\helper	$helper +	 * @param \phpbb\event\dispatcher_interface	$dispatcher +	 * @param \phpbb\template\template	$template +	 * @param \phpbb\user				$user +	 * @param string					$root_path +	 * @param string					$php_ext +	 */ +	public function __construct(\phpbb\controller\helper $helper, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\template\template $template, \phpbb\user $user, $root_path, $php_ext) +	{ +		$this->helper = $helper; +		$this->dispatcher = $dispatcher; +		$this->template = $template; +		$this->user = $user; +		$this->root_path = $root_path; +		$this->php_ext = $php_ext; +	} + +	/** +	 * Controller for /help/{mode} routes +	 * +	 * @param string		$mode +	 * @return \Symfony\Component\HttpFoundation\Response A Symfony Response object +	 * @throws http_exception when the $mode is not known by any extension +	 */ +	public function handle($mode) +	{ +		switch ($mode) +		{ +			case 'faq': +			case 'bbcode': +				$page_title = ($mode === 'faq') ? $this->user->lang['FAQ_EXPLAIN'] : $this->user->lang['BBCODE_GUIDE']; +				$this->user->add_lang($mode, false, true); +			break; + +			default: +				$page_title = $this->user->lang['FAQ_EXPLAIN']; +				$ext_name = $lang_file = ''; + +				/** +				 * You can use this event display a custom help page +				 * +				 * @event core.faq_mode_validation +				 * @var	string	page_title		Title of the page +				 * @var	string	mode			FAQ that is going to be displayed +				 * @var	string	lang_file		Language file containing the help data +				 * @var	string	ext_name		Vendor and extension name where the help +				 *								language file can be loaded from +				 * @since 3.1.4-RC1 +				 */ +				$vars = array( +					'page_title', +					'mode', +					'lang_file', +					'ext_name', +				); +				extract($this->dispatcher->trigger_event('core.faq_mode_validation', compact($vars))); + +				if ($ext_name === '' || $lang_file === '') +				{ +					throw new http_exception(404, 'Not Found'); +				} + +				$this->user->add_lang($lang_file, false, true, $ext_name); +			break; + +		} + +		$this->template->assign_vars(array( +			'L_FAQ_TITLE'				=> $page_title, +			'S_IN_FAQ'					=> true, +		)); + +		$this->assign_to_template($this->user->help); + +		make_jumpbox(append_sid("{$this->root_path}viewforum.{$this->php_ext}")); +		return $this->helper->render('faq_body.html', $page_title); +	} + +	/** +	 * Assigns the help data to the template blocks +	 * +	 * @param array $help_data +	 * @return null +	 */ +	protected function assign_to_template(array $help_data) +	{ +		// Pull the array data from the lang pack +		$switch_column = $found_switch = false; +		foreach ($help_data as $help_ary) +		{ +			if ($help_ary[0] == '--') +			{ +				if ($help_ary[1] == '--') +				{ +					$switch_column = true; +					$found_switch = true; +					continue; +				} + +				$this->template->assign_block_vars('faq_block', array( +					'BLOCK_TITLE'		=> $help_ary[1], +					'SWITCH_COLUMN'		=> $switch_column, +				)); + +				if ($switch_column) +				{ +					$switch_column = false; +				} +				continue; +			} + +			$this->template->assign_block_vars('faq_block.faq_row', array( +				'FAQ_QUESTION'		=> $help_ary[0], +				'FAQ_ANSWER'		=> $help_ary[1], +			)); +		} + +		$this->template->assign_var('SWITCH_COLUMN_MANUALLY', !$found_switch); +	} +} diff --git a/phpBB/phpbb/log/log.php b/phpBB/phpbb/log/log.php index 0c5205530b..4bb2e7a75a 100644 --- a/phpBB/phpbb/log/log.php +++ b/phpBB/phpbb/log/log.php @@ -27,7 +27,7 @@ class log implements \phpbb\log\log_interface  	/**  	* An array with the disabled log types. Logs of such types will not be -	* added when add_log() is called. +	* added when add() is called.  	* @var array  	*/  	protected $disabled_types; @@ -223,14 +223,14 @@ class log implements \phpbb\log\log_interface  			return false;  		} -		if ($log_time == false) +		if ($log_time === false)  		{  			$log_time = time();  		}  		$sql_ary = array( -			'user_id'		=> $user_id, -			'log_ip'		=> $log_ip, +			'user_id'		=> $user_id ? (int) $user_id : ANONYMOUS, +			'log_ip'		=> empty($log_ip) ? '' : $log_ip,  			'log_time'		=> $log_time,  			'log_operation'	=> $log_operation,  		); diff --git a/phpBB/phpbb/log/log_interface.php b/phpBB/phpbb/log/log_interface.php index 5932f722aa..86286e6f88 100644 --- a/phpBB/phpbb/log/log_interface.php +++ b/phpBB/phpbb/log/log_interface.php @@ -32,8 +32,8 @@ interface log_interface  	* Disable log  	*  	* This function allows disabling the log system or parts of it, for this -	* page call. When add_log is called and the type is disabled, -	* the log will not be added to the database. +	* page call. When add() is called and the type is disabled, the log will +	* not be added to the database.  	*  	* @param	mixed	$type	The log type we want to disable. Empty to  	*						disable all logs. Can also be an array of types. @@ -57,12 +57,12 @@ interface log_interface  	/**  	* Adds a log entry to the database  	* -	* @param	string	$mode				The mode defines which log_type is used and from which log the entry is retrieved -	* @param	int		$user_id			User ID of the user -	* @param	string	$log_ip				IP address of the user -	* @param	string	$log_operation		Name of the operation -	* @param	int		$log_time			Timestamp when the log entry was added, if empty time() will be used -	* @param	array	$additional_data	More arguments can be added, depending on the log_type +	* @param	string		$mode				The mode defines which log_type is used and from which log the entry is retrieved +	* @param	int			$user_id			User ID of the user +	* @param	string		$log_ip				IP address of the user +	* @param	string		$log_operation		Name of the operation +	* @param	int|bool	$log_time			Timestamp when the log entry was added. If false, time() will be used +	* @param	array		$additional_data	More arguments can be added, depending on the log_type  	*  	* @return	int|bool		Returns the log_id, if the entry was added to the database, false otherwise.  	*/ diff --git a/phpBB/phpbb/profilefields/type/type_date.php b/phpBB/phpbb/profilefields/type/type_date.php index 90ac9a6703..414484920b 100644 --- a/phpBB/phpbb/profilefields/type/type_date.php +++ b/phpBB/phpbb/profilefields/type/type_date.php @@ -72,7 +72,7 @@ class type_date extends type_base  			'lang_options'			=> $field_data['lang_options'],  		); -		$always_now = request_var('always_now', -1); +		$always_now = $request->variable('always_now', -1);  		if ($always_now == -1)  		{  			$s_checked = ($field_data['field_default_value'] == 'now') ? true : false; diff --git a/phpBB/phpbb/request/deactivated_super_global.php b/phpBB/phpbb/request/deactivated_super_global.php index b6cad59be4..ab56240b14 100644 --- a/phpBB/phpbb/request/deactivated_super_global.php +++ b/phpBB/phpbb/request/deactivated_super_global.php @@ -56,7 +56,7 @@ class deactivated_super_global implements \ArrayAccess, \Countable, \IteratorAgg  		$file = '';  		$line = 0; -		$message = 'Illegal use of $' . $this->name . '. You must use the request class or request_var() to access input data. Found in %s on line %d. This error message was generated by deactivated_super_global.'; +		$message = 'Illegal use of $' . $this->name . '. You must use the request class to access input data. Found in %s on line %d. This error message was generated by deactivated_super_global.';  		$backtrace = debug_backtrace();  		if (isset($backtrace[1])) diff --git a/phpBB/phpbb/routing/router.php b/phpBB/phpbb/routing/router.php new file mode 100644 index 0000000000..4ccd3cf5e3 --- /dev/null +++ b/phpBB/phpbb/routing/router.php @@ -0,0 +1,318 @@ +<?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\routing; + +use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; +use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper; +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\Routing\RouterInterface; +use Symfony\Component\Routing\Loader\YamlFileLoader; +use Symfony\Component\Config\FileLocator; +use phpbb\extension\manager; + +/** + * Integration of all pieces of the routing system for easier use. + */ +class router implements RouterInterface +{ +	/** +	 * Extension manager +	 * +	 * @var manager +	 */ +	protected $extension_manager; + +	/** +	 * phpBB root path +	 * +	 * @var string +	 */ +	protected $phpbb_root_path; + +	/** +	 * PHP file extensions +	 * +	 * @var string +	 */ +	protected $php_ext; + +	/** +	 * Name of the current environment +	 * +	 * @var string +	 */ +	protected $environment; + +	/** +	 * YAML file(s) containing route information +	 * +	 * @var array +	 */ +	protected $routing_files; + +	/** +	 * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface|null +	 */ +	protected $matcher; + +	/** +	 * @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface|null +	 */ +	protected $generator; + +	/** +	 * @var RequestContext +	 */ +	protected $context; + +	/** +	 * @var RouteCollection|null +	 */ +	protected $route_collection; + +	/** +	 * Construct method +	 * +	 * @param manager	$extension_manager	Extension manager +	 * @param string	$phpbb_root_path	phpBB root path +	 * @param string	$php_ext			PHP file extension +	 * @param string	$environment		Name of the current environment +	 * @param array		$routing_files		Array of strings containing paths to YAML files holding route information +	 */ +	public function __construct(manager $extension_manager, $phpbb_root_path, $php_ext, $environment, $routing_files = array()) +	{ +		$this->extension_manager	= $extension_manager; +		$this->routing_files		= $routing_files; +		$this->phpbb_root_path		= $phpbb_root_path; +		$this->php_ext				= $php_ext; +		$this->environment			= $environment; +		$this->context				= new RequestContext(); +	} + +	/** +	 * Find the list of routing files +	 * +	 * @param array $paths Array of paths where to look for routing files (they must be relative to the phpBB root path). +	 * @return router +	 */ +	public function find_routing_files(array $paths) +	{ +		$this->routing_files = array('config/' . $this->environment . '/routing/environment.yml'); +		foreach ($paths as $path) +		{ +			if (file_exists($this->phpbb_root_path . $path . 'config/' . $this->environment . '/routing/environment.yml')) +			{ +				$this->routing_files[] = $path . 'config/' . $this->environment . '/routing/environment.yml'; +			} +			else if (!is_dir($this->phpbb_root_path . $path . 'config/' . $this->environment)) +			{ +				if (file_exists($this->phpbb_root_path . $path . 'config/default/routing/environment.yml')) +				{ +					$this->routing_files[] = $path . 'config/default/routing/environment.yml'; +				} +				else if (!is_dir($this->phpbb_root_path . $path . 'config/default/routing') && file_exists($this->phpbb_root_path . $path . 'config/routing.yml')) +				{ +					$this->routing_files[] = $path . 'config/routing.yml'; +				} +			} +		} + +		return $this; +	} + +	/** +	 * Find a list of controllers +	 * +	 * @param string $base_path Base path to prepend to file paths +	 * @return router +	 */ +	public function find($base_path = '') +	{ +		if ($this->route_collection === null || $this->route_collection->count() === 0) +		{ +			$this->route_collection = new RouteCollection; +			foreach ($this->routing_files as $file_path) +			{ +				$loader = new YamlFileLoader(new FileLocator(phpbb_realpath($base_path))); +				$this->route_collection->addCollection($loader->load($file_path)); +			} +		} + +		return $this; +	} + +	/** +	 * Get the list of routes +	 * +	 * @return RouteCollection Get the route collection +	 */ +	public function get_routes() +	{ +		if ($this->route_collection == null || empty($this->routing_files)) +		{ +			$this->find_routing_files($this->extension_manager->all_enabled(false)) +				->find($this->phpbb_root_path); +		} + +		return $this->route_collection; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function getRouteCollection() +	{ +		return $this->get_routes(); +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function setContext(RequestContext $context) +	{ +		$this->context = $context; + +		if ($this->matcher !== null) +		{ +			$this->get_matcher()->setContext($context); +		} +		if ($this->generator !== null) +		{ +			$this->get_generator()->setContext($context); +		} +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function getContext() +	{ +		return $this->context; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH) +	{ +		return $this->get_generator()->generate($name, $parameters, $referenceType); +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function match($pathinfo) +	{ +		return $this->get_matcher()->match($pathinfo); +	} + +	/** +	 * Gets the UrlMatcher instance associated with this Router. +	 * +	 * @return \Symfony\Component\Routing\Matcher\UrlMatcherInterface A UrlMatcherInterface instance +	 */ +	public function get_matcher() +	{ +		if ($this->matcher !== null) +		{ +			return $this->matcher; +		} + +		$this->create_dumped_url_matcher(); + +		return $this->matcher; +	} +	/** +	 * Creates a new dumped URL Matcher (dump it if necessary) +	 */ +	protected function create_dumped_url_matcher() +	{ +		$cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_matcher.{$this->php_ext}", defined('DEBUG')); +		if (!$cache->isFresh()) +		{ +			$dumper = new PhpMatcherDumper($this->get_routes()); + +			$options = array( +				'class'      => 'phpbb_url_matcher', +				'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', +			); + +			$cache->write($dumper->dump($options), $this->get_routes()->getResources()); +		} + +		require_once($cache); + +		$this->matcher = new \phpbb_url_matcher($this->context); +	} + +	/** +	 * Creates a new URL Matcher +	 */ +	protected function create_new_url_matcher() +	{ +		$this->matcher = new UrlMatcher($this->get_routes(), $this->context); +	} + +	/** +	 * Gets the UrlGenerator instance associated with this Router. +	 * +	 * @return \Symfony\Component\Routing\Generator\UrlGeneratorInterface A UrlGeneratorInterface instance +	 */ +	public function get_generator() +	{ +		if ($this->generator !== null) +		{ +			return $this->generator; +		} + +		$this->create_dumped_url_generator(); + +		return $this->generator; +	} + +	/** +	 * Creates a new dumped URL Generator (dump it if necessary) +	 */ +	protected function create_dumped_url_generator() +	{ +		$cache = new ConfigCache("{$this->phpbb_root_path}cache/{$this->environment}/url_generator.{$this->php_ext}", defined('DEBUG')); +		if (!$cache->isFresh()) +		{ +			$dumper = new PhpGeneratorDumper($this->get_routes()); + +			$options = array( +				'class'      => 'phpbb_url_generator', +				'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', +			); + +			$cache->write($dumper->dump($options), $this->get_routes()->getResources()); +		} + +		require_once($cache); + +		$this->generator = new \phpbb_url_generator($this->context); +	} + +	/** +	 * Creates a new URL Generator +	 */ +	protected function create_new_url_generator() +	{ +		$this->generator = new UrlGenerator($this->get_routes(), $this->context); +	} +} diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php index 1a0aba096f..da9de56009 100644 --- a/phpBB/phpbb/search/fulltext_mysql.php +++ b/phpBB/phpbb/search/fulltext_mysql.php @@ -188,8 +188,8 @@ class fulltext_mysql extends \phpbb\search\base  		}  		$this->db->sql_freeresult($result); -		set_config('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']); -		set_config('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']); +		$this->config->set('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']); +		$this->config->set('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']);  		return false;  	} @@ -745,7 +745,7 @@ class fulltext_mysql extends \phpbb\search\base  		// destroy too old cached search results  		$this->destroy_cache(array()); -		set_config('search_last_gc', time(), true); +		$this->config->set('search_last_gc', time(), false);  	}  	/** diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index 4d02dd1cbf..42ad97da30 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -18,6 +18,13 @@ namespace phpbb\search;  */  class fulltext_native extends \phpbb\search\base  { +	const UTF8_HANGUL_FIRST = "\xEA\xB0\x80"; +	const UTF8_HANGUL_LAST = "\xED\x9E\xA3"; +	const UTF8_CJK_FIRST = "\xE4\xB8\x80"; +	const UTF8_CJK_LAST = "\xE9\xBE\xBB"; +	const UTF8_CJK_B_FIRST = "\xF0\xA0\x80\x80"; +	const UTF8_CJK_B_LAST = "\xF0\xAA\x9B\x96"; +  	/**  	 * Associative array holding index stats  	 * @var array @@ -93,7 +100,7 @@ class fulltext_native extends \phpbb\search\base  	protected $user;  	/** -	* Initialises the fulltext_native search backend with min/max word length and makes sure the UTF-8 normalizer is loaded +	* Initialises the fulltext_native search backend with min/max word length  	*  	* @param	boolean|string	&$error	is passed by reference and should either be set to false on success or an error message on failure  	*/ @@ -110,10 +117,6 @@ class fulltext_native extends \phpbb\search\base  		/**  		* Load the UTF tools  		*/ -		if (!class_exists('utf_normalizer')) -		{ -			include($this->phpbb_root_path . 'includes/utf/utf_normalizer.' . $this->php_ext); -		}  		if (!function_exists('utf8_decode_ncr'))  		{  			include($this->phpbb_root_path . 'includes/utf/utf_tools.' . $this->php_ext); @@ -1172,9 +1175,9 @@ class fulltext_native extends \phpbb\search\base  				* Note: this could be optimized. If the codepoint is lower than Hangul's range  				* we know that it will also be lower than CJK ranges  				*/ -				if ((strncmp($word, UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, UTF8_HANGUL_LAST, 3) > 0) -					&& (strncmp($word, UTF8_CJK_FIRST, 3) < 0 || strncmp($word, UTF8_CJK_LAST, 3) > 0) -					&& (strncmp($word, UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, UTF8_CJK_B_LAST, 4) > 0)) +				if ((strncmp($word, self::UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, self::UTF8_HANGUL_LAST, 3) > 0) +					&& (strncmp($word, self::UTF8_CJK_FIRST, 3) < 0 || strncmp($word, self::UTF8_CJK_LAST, 3) > 0) +					&& (strncmp($word, self::UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, self::UTF8_CJK_B_LAST, 4) > 0))  				{  					$word = strtok(' ');  					continue; @@ -1419,7 +1422,7 @@ class fulltext_native extends \phpbb\search\base  		// carry on ... it's okay ... I know when I'm not wanted boo hoo  		if (!$this->config['fulltext_native_load_upd'])  		{ -			set_config('search_last_gc', time(), true); +			$this->config->set('search_last_gc', time(), false);  			return;  		} @@ -1454,7 +1457,7 @@ class fulltext_native extends \phpbb\search\base  				// by setting search_last_gc to the new time here we make sure that if a user reloads because the  				// following query takes too long, he won't run into it again -				set_config('search_last_gc', time(), true); +				$this->config->set('search_last_gc', time(), false);  				// Delete the matches  				$sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' @@ -1470,7 +1473,7 @@ class fulltext_native extends \phpbb\search\base  			$this->destroy_cache(array_unique($destroy_cache_words));  		} -		set_config('search_last_gc', time(), true); +		$this->config->set('search_last_gc', time(), false);  	}  	/** @@ -1541,8 +1544,6 @@ class fulltext_native extends \phpbb\search\base  	* @param	string	$allowed_chars	String of special chars to allow  	* @param	string	$encoding		Text encoding  	* @return	string					Cleaned up text, only alphanumeric chars are left -	* -	* @todo \normalizer::cleanup being able to be used?  	*/  	protected function cleanup($text, $allowed_chars = null, $encoding = 'utf-8')  	{ @@ -1569,12 +1570,9 @@ class fulltext_native extends \phpbb\search\base  		$text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES);  		/** -		* Load the UTF-8 normalizer -		* -		* If we use it more widely, an instance of that class should be held in a -		* a global variable instead +		* Normalize to NFC  		*/ -		\utf_normalizer::nfc($text); +		$text = \Normalizer::normalize($text);  		/**  		* The first thing we do is: @@ -1667,9 +1665,9 @@ class fulltext_native extends \phpbb\search\base  			$utf_char = substr($text, $pos, $utf_len);  			$pos += $utf_len; -			if (($utf_char >= UTF8_HANGUL_FIRST && $utf_char <= UTF8_HANGUL_LAST) -				|| ($utf_char >= UTF8_CJK_FIRST && $utf_char <= UTF8_CJK_LAST) -				|| ($utf_char >= UTF8_CJK_B_FIRST && $utf_char <= UTF8_CJK_B_LAST)) +			if (($utf_char >= self::UTF8_HANGUL_FIRST && $utf_char <= self::UTF8_HANGUL_LAST) +				|| ($utf_char >= self::UTF8_CJK_FIRST && $utf_char <= self::UTF8_CJK_LAST) +				|| ($utf_char >= self::UTF8_CJK_B_FIRST && $utf_char <= self::UTF8_CJK_B_LAST))  			{  				/**  				* All characters within these ranges are valid diff --git a/phpBB/phpbb/search/fulltext_postgres.php b/phpBB/phpbb/search/fulltext_postgres.php index b6af371d13..5a68f0cbfb 100644 --- a/phpBB/phpbb/search/fulltext_postgres.php +++ b/phpBB/phpbb/search/fulltext_postgres.php @@ -746,7 +746,7 @@ class fulltext_postgres extends \phpbb\search\base  		// destroy too old cached search results  		$this->destroy_cache(array()); -		set_config('search_last_gc', time(), true); +		$this->config->set('search_last_gc', time(), false);  	}  	/** diff --git a/phpBB/phpbb/search/fulltext_sphinx.php b/phpBB/phpbb/search/fulltext_sphinx.php index eb53ca6d40..a5ad96b114 100644 --- a/phpBB/phpbb/search/fulltext_sphinx.php +++ b/phpBB/phpbb/search/fulltext_sphinx.php @@ -85,7 +85,7 @@ class fulltext_sphinx  	/**  	 * Database Tools object -	 * @var \phpbb\db\tools +	 * @var \phpbb\db\tools\tools_interface  	 */  	protected $db_tools; @@ -135,12 +135,13 @@ class fulltext_sphinx  		$this->db = $db;  		$this->auth = $auth; -		// Initialize \phpbb\db\tools object -		$this->db_tools = new \phpbb\db\tools($this->db); +		// Initialize \phpbb\db\tools\tools object +		global $phpbb_container; // TODO inject into object +		$this->db_tools = $phpbb_container->get('dbal.tools');  		if(!$this->config['fulltext_sphinx_id'])  		{ -			set_config('fulltext_sphinx_id', unique_id()); +			$this->config->set('fulltext_sphinx_id', unique_id());  		}  		$this->id = $this->config['fulltext_sphinx_id'];  		$this->indexes = 'index_phpbb_' . $this->id . '_delta;index_phpbb_' . $this->id . '_main'; @@ -211,7 +212,7 @@ class fulltext_sphinx  		}  		// Move delta to main index each hour -		set_config('search_gc', 3600); +		$this->config->set('search_gc', 3600);  		return false;  	} @@ -454,6 +455,8 @@ class fulltext_sphinx  	*/  	public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page)  	{ +		global $user, $phpbb_log; +  		// No keywords? No posts.  		if (!strlen($this->search_query) && !sizeof($author_ary))  		{ @@ -601,7 +604,7 @@ class fulltext_sphinx  		if ($this->sphinx->GetLastError())  		{ -			add_log('critical', 'LOG_SPHINX_ERROR', $this->sphinx->GetLastError()); +			$phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_SPHINX_ERROR', false, array($this->sphinx->GetLastError()));  			if ($this->auth->acl_get('a_'))  			{  				trigger_error($this->user->lang('SPHINX_SEARCH_FAILED', $this->sphinx->GetLastError())); @@ -755,7 +758,7 @@ class fulltext_sphinx  	*/  	public function tidy($create = false)  	{ -		set_config('search_last_gc', time(), true); +		$this->config->set('search_last_gc', time(), false);  	}  	/** diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php index bedd581725..d49f88b676 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -219,7 +219,7 @@ class session  	function session_begin($update_session_page = true)  	{  		global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path; -		global $request, $phpbb_container; +		global $request, $phpbb_container, $user, $phpbb_log;  		// Give us some basic information  		$this->time_now				= time(); @@ -257,23 +257,23 @@ class session  		if ($request->is_set($config['cookie_name'] . '_sid', \phpbb\request\request_interface::COOKIE) || $request->is_set($config['cookie_name'] . '_u', \phpbb\request\request_interface::COOKIE))  		{ -			$this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true); -			$this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true); -			$this->session_id 		= request_var($config['cookie_name'] . '_sid', '', false, true); +			$this->cookie_data['u'] = $request->variable($config['cookie_name'] . '_u', 0, false, \phpbb\request\request_interface::COOKIE); +			$this->cookie_data['k'] = $request->variable($config['cookie_name'] . '_k', '', false, \phpbb\request\request_interface::COOKIE); +			$this->session_id 		= $request->variable($config['cookie_name'] . '_sid', '', false, \phpbb\request\request_interface::COOKIE);  			$SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';  			$_SID = (defined('NEED_SID')) ? $this->session_id : '';  			if (empty($this->session_id))  			{ -				$this->session_id = $_SID = request_var('sid', ''); +				$this->session_id = $_SID = $request->variable('sid', '');  				$SID = '?sid=' . $this->session_id;  				$this->cookie_data = array('u' => 0, 'k' => '');  			}  		}  		else  		{ -			$this->session_id = $_SID = request_var('sid', ''); +			$this->session_id = $_SID = $request->variable('sid', '');  			$SID = '?sid=' . $this->session_id;  		} @@ -349,8 +349,8 @@ class session  			}  			else  			{ -				set_config('limit_load', '0'); -				set_config('limit_search_load', '0'); +				$config->set('limit_load', '0'); +				$config->set('limit_search_load', '0');  			}  		} @@ -413,6 +413,7 @@ class session  					$session_expired = false;  					// Check whether the session is still valid if we have one +					/* @var $provider_collection \phpbb\auth\provider_collection */  					$provider_collection = $phpbb_container->get('auth.provider_collection');  					$provider = $provider_collection->get_provider(); @@ -493,11 +494,18 @@ class session  					{  						if ($referer_valid)  						{ -							add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for)); +							$phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_IP_BROWSER_FORWARDED_CHECK', false, array( +								$u_ip, +								$s_ip, +								$u_browser, +								$s_browser, +								htmlspecialchars($u_forwarded_for), +								htmlspecialchars($s_forwarded_for) +							));  						}  						else  						{ -							add_log('critical', 'LOG_REFERER_INVALID', $this->referer); +							$phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_REFERER_INVALID', false, array($this->referer));  						}  					}  				} @@ -582,6 +590,7 @@ class session  			}  		} +		/* @var $provider_collection \phpbb\auth\provider_collection */  		$provider_collection = $phpbb_container->get('auth.provider_collection');  		$provider = $provider_collection->get_provider();  		$this->data = $provider->autologin(); @@ -914,6 +923,7 @@ class session  		$db->sql_query($sql);  		// Allow connecting logout with external auth method logout +		/* @var $provider_collection \phpbb\auth\provider_collection */  		$provider_collection = $phpbb_container->get('auth.provider_collection');  		$provider = $provider_collection->get_provider();  		$provider->logout($this->data, $new_session); @@ -1030,7 +1040,7 @@ class session  		{  			// Less than 10 users, update gc timer ... else we want gc  			// called again to delete other sessions -			set_config('session_last_gc', $this->time_now, true); +			$config->set('session_last_gc', $this->time_now, false);  			if ($config['max_autologin_time'])  			{ @@ -1040,6 +1050,7 @@ class session  			}  			// only called from CRON; should be a safe workaround until the infrastructure gets going +			/* @var $captcha_factory \phpbb\captcha\factory */  			$captcha_factory = $phpbb_container->get('captcha.factory');  			$captcha_factory->garbage_collect($config['captcha_plugin']); diff --git a/phpBB/phpbb/template/asset.php b/phpBB/phpbb/template/asset.php index 67dbd7b357..4729685459 100644 --- a/phpBB/phpbb/template/asset.php +++ b/phpBB/phpbb/template/asset.php @@ -152,6 +152,12 @@ class asset  	*/  	public function set_path($path, $urlencode = false)  	{ +		// Since 1.7.0 Twig returns the real path of the file. We need it to be relative to the working directory. +		$real_root_path = realpath('.') . DIRECTORY_SEPARATOR; +		if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path) { +			$path = str_replace('\\', '/', substr($path, strlen($real_root_path))); +		} +  		if ($urlencode)  		{  			$paths = explode('/', $path); @@ -161,6 +167,7 @@ class asset  			}  			$path = implode('/', $paths);  		} +  		$this->components['path'] = $path;  	} diff --git a/phpBB/phpbb/template/twig/environment.php b/phpBB/phpbb/template/twig/environment.php index 476ffd935e..0ba7a265e4 100644 --- a/phpBB/phpbb/template/twig/environment.php +++ b/phpBB/phpbb/template/twig/environment.php @@ -21,6 +21,9 @@ class environment extends \Twig_Environment  	/** @var \phpbb\path_helper */  	protected $phpbb_path_helper; +	/** @var \Symfony\Component\DependencyInjection\ContainerInterface */ +	protected $container; +  	/** @var \phpbb\extension\manager */  	protected $extension_manager; @@ -38,24 +41,49 @@ class environment extends \Twig_Environment  	*  	* @param \phpbb\config\config $phpbb_config The phpBB configuration  	* @param \phpbb\path_helper $path_helper phpBB path helper +	* @param \Symfony\Component\DependencyInjection\ContainerInterface $container The dependency injection container +	* @param string $cache_path The path to the cache directory  	* @param \phpbb\extension\manager $extension_manager phpBB extension manager  	* @param \Twig_LoaderInterface $loader Twig loader interface  	* @param array $options Array of options to pass to Twig  	*/ -	public function __construct($phpbb_config, \phpbb\path_helper $path_helper, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, $options = array()) +	public function __construct($phpbb_config, \phpbb\path_helper $path_helper, \Symfony\Component\DependencyInjection\ContainerInterface $container, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, $options = array())  	{  		$this->phpbb_config = $phpbb_config;  		$this->phpbb_path_helper = $path_helper;  		$this->extension_manager = $extension_manager; +		$this->container = $container;  		$this->phpbb_root_path = $this->phpbb_path_helper->get_phpbb_root_path();  		$this->web_root_path = $this->phpbb_path_helper->get_web_root_path(); +		$options = array_merge(array( +			'cache'			=> (defined('IN_INSTALL')) ? false : $cache_path, +			'debug'			=> defined('DEBUG'), +			'auto_reload'	=> (bool) $this->phpbb_config['load_tplcompile'], +			'autoescape'	=> false, +		), $options); +  		return parent::__construct($loader, $options);  	}  	/** +	* {@inheritdoc} +	*/ +	public function getLexer() +	{ +		if (null === $this->lexer) +		{ +			$this->lexer = $this->container->get('template.twig.lexer'); +			$this->lexer->set_environment($this); +		} + +		return $this->lexer; +	} + + +	/**  	* Get the list of enabled phpBB extensions  	*  	* Used in EVENT node diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php index 3a983491b9..14d1258c09 100644 --- a/phpBB/phpbb/template/twig/extension.php +++ b/phpBB/phpbb/template/twig/extension.php @@ -71,6 +71,7 @@ class extension extends \Twig_Extension  	{  		return array(  			new \Twig_SimpleFilter('subset', array($this, 'loop_subset'), array('needs_environment' => true)), +			// @deprecated 3.2.0 Uses twig's JS escape method instead of addslashes  			new \Twig_SimpleFilter('addslashes', 'addslashes'),  		);  	} @@ -177,7 +178,7 @@ class extension extends \Twig_Extension  			return $context_vars['L_' . $key];  		} -		// LA_ is transformed into lang(\'$1\')|addslashes, so we should not +		// LA_ is transformed into lang(\'$1\')|escape('js'), so we should not  		// need to check for it  		return call_user_func_array(array($this->user, 'lang'), $args); diff --git a/phpBB/phpbb/template/twig/lexer.php b/phpBB/phpbb/template/twig/lexer.php index c5dc7273ba..f1542109a4 100644 --- a/phpBB/phpbb/template/twig/lexer.php +++ b/phpBB/phpbb/template/twig/lexer.php @@ -15,6 +15,11 @@ namespace phpbb\template\twig;  class lexer extends \Twig_Lexer  { +	public function set_environment(\Twig_Environment $env) +	{ +		$this->env = $env; +	} +  	public function tokenize($code, $filename = null)  	{  		// Our phpBB tags @@ -112,9 +117,9 @@ class lexer extends \Twig_Lexer  		// Appends any filters after lang()  		$code = preg_replace('#{L_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2 }}', $code); -		// Replace all of our escaped language variables, {LA_VARNAME}, with Twig style, {{ lang('NAME')|addslashes }} -		// Appends any filters after lang(), but before addslashes -		$code = preg_replace('#{LA_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2|addslashes }}', $code); +		// Replace all of our escaped language variables, {LA_VARNAME}, with Twig style, {{ lang('NAME')|escape('js') }} +		// Appends any filters after lang(), but before escape('js') +		$code = preg_replace('#{LA_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2|escape(\'js\') }}', $code);  		// Replace all of our variables, {VARNAME}, with Twig style, {{ VARNAME }}  		// Appends any filters diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php index bd754d9bbd..0e4c619029 100644 --- a/phpBB/phpbb/template/twig/twig.php +++ b/phpBB/phpbb/template/twig/twig.php @@ -78,9 +78,12 @@ class twig extends \phpbb\template\base  	* @param \phpbb\config\config $config  	* @param \phpbb\user $user  	* @param \phpbb\template\context $context template context +	* @param \phpbb\template\twig\environment $twig_environment +	* @param string $cache_path +	* @param array|\ArrayAccess $extensions  	* @param \phpbb\extension\manager $extension_manager extension manager, if null then template events will not be invoked  	*/ -	public function __construct(\phpbb\path_helper $path_helper, $config, $user, \phpbb\template\context $context, \phpbb\extension\manager $extension_manager = null) +	public function __construct(\phpbb\path_helper $path_helper, $config, $user, \phpbb\template\context $context, \phpbb\template\twig\environment $twig_environment, $cache_path, $extensions = array(), \phpbb\extension\manager $extension_manager = null)  	{  		$this->path_helper = $path_helper;  		$this->phpbb_root_path = $path_helper->get_phpbb_root_path(); @@ -89,41 +92,14 @@ class twig extends \phpbb\template\base  		$this->user = $user;  		$this->context = $context;  		$this->extension_manager = $extension_manager; +		$this->cachepath = $cache_path; +		$this->twig = $twig_environment; -		$this->cachepath = $this->phpbb_root_path . 'cache/twig/'; - -		// Initiate the loader, __main__ namespace paths will be setup later in set_style_names() -		$loader = new \phpbb\template\twig\loader(''); - -		$this->twig = new \phpbb\template\twig\environment( -			$this->config, -			$this->path_helper, -			$this->extension_manager, -			$loader, -			array( -				'cache'			=> (defined('IN_INSTALL')) ? false : $this->cachepath, -				'debug'			=> defined('DEBUG'), -				'auto_reload'	=> (bool) $this->config['load_tplcompile'], -				'autoescape'	=> false, -			) -		); - -		$this->twig->addExtension( -			new \phpbb\template\twig\extension( -				$this->context, -				$this->user -			) -		); - -		if (defined('DEBUG')) +		foreach ($extensions as $extension)  		{ -			$this->twig->addExtension(new \Twig_Extension_Debug()); +			$this->twig->addExtension($extension);  		} -		$lexer = new \phpbb\template\twig\lexer($this->twig); - -		$this->twig->setLexer($lexer); -  		// Add admin namespace  		if ($this->path_helper->get_adm_relative_path() !== null && is_dir($this->phpbb_root_path . $this->path_helper->get_adm_relative_path() . 'style/'))  		{ @@ -376,6 +352,12 @@ class twig extends \phpbb\template\base  		// cleanup  		unset($vars['loops']['.']); +		// Inject in the main context the value added by assign_block_vars() to be able to use directly the Twig loops. +		foreach ($vars['loops'] as $key => &$value) +		{ +			$vars[$key] = $value; +		} +  		return $vars;  	} diff --git a/phpBB/phpbb/user_loader.php b/phpBB/phpbb/user_loader.php index 24e663b150..0b192e4452 100644 --- a/phpBB/phpbb/user_loader.php +++ b/phpBB/phpbb/user_loader.php @@ -175,7 +175,7 @@ class user_loader  	/**  	* Get avatar  	* -	* @param int $user_id User ID of the user you want to retreive the avatar for +	* @param int $user_id User ID of the user you want to retrieve the avatar for  	* @param bool $query Should we query the database if this user has not yet been loaded?  	* 						Typically this should be left as false and you should make sure  	* 						you load users ahead of time with load_users() @@ -188,12 +188,14 @@ class user_loader  			return '';  		} -		if (!function_exists('get_user_avatar')) -		{ -			include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext); -		} +		$row = array( +			'avatar'		=> $user['user_avatar'], +			'avatar_type'	=> $user['user_avatar_type'], +			'avatar_width'	=> $user['user_avatar_width'], +			'avatar_height'	=> $user['user_avatar_height'], +		); -		return get_user_avatar($user['user_avatar'], $user['user_avatar_type'], $user['user_avatar_width'], $user['user_avatar_height']); +		return phpbb_get_avatar($row, 'USER_AVATAR');  	}  	/** | 
