diff options
Diffstat (limited to 'phpBB/phpbb')
65 files changed, 2385 insertions, 1040 deletions
diff --git a/phpBB/phpbb/auth/provider/ldap.php b/phpBB/phpbb/auth/provider/ldap.php index d32e7504eb..c71950c698 100644 --- a/phpBB/phpbb/auth/provider/ldap.php +++ b/phpBB/phpbb/auth/provider/ldap.php @@ -306,7 +306,7 @@ class ldap extends \phpbb\auth\provider\base return array( 'TEMPLATE_FILE' => 'auth_provider_ldap.html', 'TEMPLATE_VARS' => array( - 'AUTH_LDAP_DN' => $new_config['ldap_base_dn'], + 'AUTH_LDAP_BASE_DN' => $new_config['ldap_base_dn'], 'AUTH_LDAP_EMAIL' => $new_config['ldap_email'], 'AUTH_LDAP_PASSORD' => $new_config['ldap_password'], 'AUTH_LDAP_PORT' => $new_config['ldap_port'], 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 114959c06c..9c63d0010c 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -95,7 +95,7 @@ class file extends \phpbb\cache\driver\base */ function tidy() { - global $phpEx; + global $config, $phpEx; $dir = @opendir($this->cache_dir); @@ -149,7 +149,7 @@ class file extends \phpbb\cache\driver\base } } - set_config('cache_last_gc', time(), true); + $config->set('cache_last_gc', time(), false); } /** diff --git a/phpBB/phpbb/cache/driver/memory.php b/phpBB/phpbb/cache/driver/memory.php index 0cef9c3483..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); } /** 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..2c0b95411e 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; @@ -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 ca242a96dc..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\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\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/config/db_text.php b/phpBB/phpbb/config/db_text.php index b1e3ef5da4..ddc7c9aef0 100644 --- a/phpBB/phpbb/config/db_text.php +++ b/phpBB/phpbb/config/db_text.php @@ -154,6 +154,6 @@ class db_text $sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true); - $result = $this->db->sql_query($sql); + $this->db->sql_query($sql); } } diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php index c8516d6c85..02338a5c2f 100644 --- a/phpBB/phpbb/content_visibility.php +++ b/phpBB/phpbb/content_visibility.php @@ -45,7 +45,7 @@ class content_visibility /** * Event dispatcher object - * @var \phpbb\event\dispatcher + * @var \phpbb\event\dispatcher_interface */ protected $phpbb_dispatcher; @@ -66,7 +66,7 @@ class content_visibility * * @param \phpbb\auth\auth $auth Auth object * @param \phpbb\config\config $config Config object - * @param \phpbb\event\dispatcher $phpbb_dispatcher Event dispatcher object + * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object * @param \phpbb\db\driver\driver_interface $db Database object * @param \phpbb\user $user User object * @param string $phpbb_root_path Root path @@ -76,7 +76,7 @@ class content_visibility * @param string $topics_table Topics table name * @param string $users_table Users table name */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table) + public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table) { $this->auth = $auth; $this->config = $config; @@ -252,7 +252,7 @@ class content_visibility * @event core.phpbb_content_visibility_get_global_visibility_before * @var array where_sqls The action the user tried to execute * @var string mode Either "topic" or "post" depending on the query this is being used in - * @var array forum_ids Array of forum ids which the posts/topics are limited to + * @var array exclude_forum_ids Array of forum ids the current user doesn't have access to * @var string table_alias Table alias to prefix in SQL queries * @var array approve_forums Array of forums where the user has m_approve permissions * @var string visibility_sql_overwrite Forces the function to return an implosion of where_sqls (joined by "OR") @@ -261,7 +261,7 @@ class content_visibility $vars = array( 'where_sqls', 'mode', - 'forum_ids', + 'exclude_forum_ids', 'table_alias', 'approve_forums', 'visibility_sql_overwrite', diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php index 2bc8e6b9d0..2790ea4277 100644 --- a/phpBB/phpbb/controller/helper.php +++ b/phpBB/phpbb/controller/helper.php @@ -187,15 +187,34 @@ class helper * @param string $message The error message * @param int $code The error code (e.g. 404, 500, 503, etc.) * @return Response A Response instance + * + * @deprecated 3.1.3 (To be removed: 3.3.0) Use exceptions instead. */ public function error($message, $code = 500) { + return $this->message($message, array(), 'INFORMATION', $code); + } + + /** + * Output a message + * + * In case of an error, please throw an exception instead + * + * @param string $message The message to display (must be a language variable) + * @param array $parameters The parameters to use with the language var + * @param string $title Title for the message (must be a language variable) + * @param int $code The HTTP status code (e.g. 404, 500, 503, etc.) + * @return Response A Response instance + */ + public function message($message, array $parameters = array(), $title = 'INFORMATION', $code = 200) + { + array_unshift($parameters, $message); $this->template->assign_vars(array( - 'MESSAGE_TEXT' => $message, - 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'), + 'MESSAGE_TEXT' => call_user_func_array(array($this->user, 'lang'), $parameters), + 'MESSAGE_TITLE' => $this->user->lang($title), )); - return $this->render('message_body.html', $this->user->lang('INFORMATION'), $code); + return $this->render('message_body.html', $this->user->lang($title), $code); } /** 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/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php index debc3cc523..d43e201526 100644 --- a/phpBB/phpbb/db/driver/mysqli.php +++ b/phpBB/phpbb/db/driver/mysqli.php @@ -34,8 +34,7 @@ class mysqli extends \phpbb\db\driver\mysql_base return $this->sql_error(''); } - // Mysqli extension supports persistent connection since PHP 5.3.0 - $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false; + $this->persistency = $persistency; $this->user = $sqluser; // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix diff --git a/phpBB/phpbb/db/migration/container_aware_migration.php b/phpBB/phpbb/db/migration/container_aware_migration.php new file mode 100644 index 0000000000..3b4b49b04b --- /dev/null +++ b/phpBB/phpbb/db/migration/container_aware_migration.php @@ -0,0 +1,36 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration; + +use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** +* Abstract base class for container aware database migrations. +*/ +abstract class container_aware_migration extends migration implements ContainerAwareInterface +{ + /** + * @var ContainerInterface + */ + protected $container; + + /** + * {@inheritdoc} + */ + public function setContainer(ContainerInterface $container = null) + { + $this->container = $container; + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_13.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13.php new file mode 100644 index 0000000000..310fcc70fc --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13.php @@ -0,0 +1,37 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v30x; + +class release_3_0_13 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return phpbb_version_compare($this->config['version'], '3.0.13', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v30x\release_3_0_13_rc1'); + } + + public function update_data() + { + return array( + array('if', array( + phpbb_version_compare($this->config['version'], '3.0.13', '<'), + array('config.update', array('version', '3.0.13')), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_pl1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_pl1.php new file mode 100644 index 0000000000..b12a96a7fb --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_pl1.php @@ -0,0 +1,37 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v30x; + +class release_3_0_13_pl1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return phpbb_version_compare($this->config['version'], '3.0.13-PL1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v30x\release_3_0_13'); + } + + public function update_data() + { + return array( + array('if', array( + phpbb_version_compare($this->config['version'], '3.0.13-PL1', '<'), + array('config.update', array('version', '3.0.13-PL1')), + )), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_rc1.php new file mode 100644 index 0000000000..9ea68fa862 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_13_rc1.php @@ -0,0 +1,37 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v30x; + +class release_3_0_13_rc1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return phpbb_version_compare($this->config['version'], '3.0.13-RC1', '>=') && phpbb_version_compare($this->config['version'], '3.1.0-dev', '<'); + } + + static public function depends_on() + { + return array('\phpbb\db\migration\data\v30x\release_3_0_12'); + } + + public function update_data() + { + return array( + array('if', array( + phpbb_version_compare($this->config['version'], '3.0.13-RC1', '<'), + array('config.update', array('version', '3.0.13-RC1')), + )), + ); + } +} 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 20543463ab..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 @@ -13,7 +13,9 @@ namespace phpbb\db\migration\data\v30x; -class release_3_0_5_rc1 extends \phpbb\db\migration\migration +use phpbb\db\migration\container_aware_migration; + +class release_3_0_5_rc1 extends container_aware_migration { public function effectively_installed() { @@ -55,10 +57,9 @@ class release_3_0_5_rc1 extends \phpbb\db\migration\migration public function hash_old_passwords() { - global $phpbb_container; - /* @var $passwords_manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('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'; @@ -111,7 +112,7 @@ class release_3_0_5_rc1 extends \phpbb\db\migration\migration // Select auth_option_ids... the largest id will be preserved $sql = 'SELECT auth_option_id FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option = '" . $db->sql_escape($option) . "' + WHERE auth_option = '" . $this->db->sql_escape($option) . "' ORDER BY auth_option_id DESC"; // sql_query_limit not possible here, due to bug in postgresql layer $result = $this->db->sql_query($sql); diff --git a/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php b/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php index 58845b88ec..85b90da5fa 100644 --- a/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php +++ b/phpBB/phpbb/db/migration/data/v310/soft_delete_mod_convert.php @@ -13,12 +13,14 @@ namespace phpbb\db\migration\data\v310; +use phpbb\db\migration\container_aware_migration; + /** * Migration to convert the Soft Delete MOD for 3.0 * * https://www.phpbb.com/customise/db/mod/soft_delete/ */ -class soft_delete_mod_convert extends \phpbb\db\migration\migration +class soft_delete_mod_convert extends container_aware_migration { static public function depends_on() { @@ -115,19 +117,11 @@ class soft_delete_mod_convert extends \phpbb\db\migration\migration } } + /** + * @return \phpbb\content_visibility + */ protected function get_content_visibility() { - return new \phpbb\content_visibility( - new \phpbb\auth\auth(), - $this->config, - $this->db, - new \phpbb\user('\phpbb\datetime'), - $this->phpbb_root_path, - $this->php_ext, - $this->table_prefix . 'forums', - $this->table_prefix . 'posts', - $this->table_prefix . 'topics', - $this->table_prefix . 'users' - ); + return $this->container->get('content.visibility'); } } 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/data/v31x/update_custom_bbcodes_with_idn.php b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php new file mode 100644 index 0000000000..854ed1f568 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php @@ -0,0 +1,70 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class update_custom_bbcodes_with_idn extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v312', + ); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'update_bbcodes_table'))), + ); + } + + public function update_bbcodes_table() + { + if (!class_exists('acp_bbcodes')) + { + include($this->phpbb_root_path . 'includes/acp/acp_bbcodes.' . $this->php_ext); + } + + $bbcodes = new \acp_bbcodes(); + + $sql = 'SELECT bbcode_id, bbcode_match, bbcode_tpl + FROM ' . BBCODES_TABLE; + $result = $this->sql_query($sql); + + $sql_ary = array(); + while ($row = $this->db->sql_fetchrow($result)) + { + $data = array(); + if (preg_match('/(URL|LOCAL_URL|RELATIVE_URL)/', $row['bbcode_match'])) + { + $data = $bbcodes->build_regexp($row['bbcode_match'], $row['bbcode_tpl']); + $sql_ary[$row['bbcode_id']] = array( + 'first_pass_match' => $data['first_pass_match'], + 'first_pass_replace' => $data['first_pass_replace'], + 'second_pass_match' => $data['second_pass_match'], + 'second_pass_replace' => $data['second_pass_replace'] + ); + } + } + $this->db->sql_freeresult($result); + + foreach ($sql_ary as $bbcode_id => $bbcode_data) + { + $sql = 'UPDATE ' . BBCODES_TABLE . ' + SET ' . $this->db->sql_build_array('UPDATE', $bbcode_data) . ' + WHERE bbcode_id = ' . (int) $bbcode_id; + $this->sql_query($sql); + } + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v313.php b/phpBB/phpbb/db/migration/data/v31x/v313.php new file mode 100644 index 0000000000..5a4e21a9b7 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v313.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v313 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v313rc2', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.3')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v313rc1.php b/phpBB/phpbb/db/migration/data/v31x/v313rc1.php new file mode 100644 index 0000000000..e50754f805 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v313rc1.php @@ -0,0 +1,35 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v313rc1 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v30x\release_3_0_13_rc1', + '\phpbb\db\migration\data\v31x\plupload_last_gc_dynamic', + '\phpbb\db\migration\data\v31x\profilefield_remove_underscore_from_alpha', + '\phpbb\db\migration\data\v31x\profilefield_yahoo_update_url', + '\phpbb\db\migration\data\v31x\update_custom_bbcodes_with_idn', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.3-RC1')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/v313rc2.php b/phpBB/phpbb/db/migration/data/v31x/v313rc2.php new file mode 100644 index 0000000000..d832d6f502 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v313rc2.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v313rc2 extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v30x\release_3_0_13_pl1', + '\phpbb\db\migration\data\v31x\v313rc1', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.1.3-RC2')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/profilefield_base_migration.php b/phpBB/phpbb/db/migration/profilefield_base_migration.php index bc3d2e9ee5..3f26a4998c 100644 --- a/phpBB/phpbb/db/migration/profilefield_base_migration.php +++ b/phpBB/phpbb/db/migration/profilefield_base_migration.php @@ -13,7 +13,7 @@ namespace phpbb\db\migration; -abstract class profilefield_base_migration extends \phpbb\db\migration\migration +abstract class profilefield_base_migration extends container_aware_migration { protected $profilefield_name; @@ -237,10 +237,8 @@ abstract class profilefield_base_migration extends \phpbb\db\migration\migration if ($profile_row === null) { - global $phpbb_container; - /* @var $manager \phpbb\profilefields\manager */ - $manager = $phpbb_container->get('profilefields.manager'); + $manager = $this->container->get('profilefields.manager'); $profile_row = $manager->build_insert_sql_array(array()); } 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/migration/tool/permission.php b/phpBB/phpbb/db/migration/tool/permission.php index 5cfbc5ca00..1a91127d2d 100644 --- a/phpBB/phpbb/db/migration/tool/permission.php +++ b/phpBB/phpbb/db/migration/tool/permission.php @@ -537,7 +537,8 @@ class permission implements \phpbb\db\migration\tool\tool_interface } $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' - WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove); + WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove) . ' + AND role_id = ' . (int) $role_id; $this->db->sql_query($sql); break; diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php index bb79c0dd68..6902913c64 100644 --- a/phpBB/phpbb/db/migrator.php +++ b/phpBB/phpbb/db/migrator.php @@ -13,11 +13,19 @@ namespace phpbb\db; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + /** * The migrator is responsible for applying new migrations in the correct order. */ class migrator { + /** + * @var ContainerInterface + */ + protected $container; + /** @var \phpbb\config\config */ protected $config; @@ -77,15 +85,16 @@ class migrator /** * The output handler. A null handler is configured by default. * - * @var migrator_output_handler + * @var migrator_output_handler_interface */ public $output_handler; /** * Constructor of the database migrator */ - public function __construct(\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) + 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; $this->db = $db; $this->db_tools = $db_tools; @@ -172,6 +181,18 @@ class migrator */ public function update() { + $this->container->get('dispatcher')->disable(); + $this->update_do(); + $this->container->get('dispatcher')->enable(); + } + + /** + * Effectively runs a single update step from the next migration to be applied. + * + * @return null + */ + protected function update_do() + { foreach ($this->migrations as $name) { if (!isset($this->migration_state[$name]) || @@ -317,7 +338,7 @@ class migrator catch (\phpbb\db\migration\exception $e) { // Revert the schema changes - $this->revert($name); + $this->revert_do($name); // Rethrow exception throw $e; @@ -337,10 +358,22 @@ class migrator * check if revert() needs to be called again use the migration_state() method. * * @param string $migration String migration name to revert (including any that depend on this migration) - * @return null */ public function revert($migration) { + $this->container->get('dispatcher')->disable(); + $this->revert_do($migration); + $this->container->get('dispatcher')->enable(); + } + + /** + * Effectively runs a single revert step from the last migration installed + * + * @param string $migration String migration name to revert (including any that depend on this migration) + * @return null + */ + protected function revert_do($migration) + { if (!isset($this->migration_state[$migration])) { // Not installed @@ -351,7 +384,7 @@ class migrator { if (!empty($state['migration_depends_on']) && in_array($migration, $state['migration_depends_on'])) { - $this->revert($name); + $this->revert_do($name); } } @@ -742,7 +775,14 @@ class migrator */ protected function get_migration($name) { - return new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); + $migration = new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); + + if ($migration instanceof ContainerAwareInterface) + { + $migration->setContainer($this->container); + } + + return $migration; } /** 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/tools.php b/phpBB/phpbb/db/tools/tools.php index e1389a24bf..0d1eb63c47 100644 --- a/phpBB/phpbb/db/tools/tools.php +++ b/phpBB/phpbb/db/tools/tools.php @@ -36,12 +36,6 @@ class tools implements tools_interface 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 implements tools_interface '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 implements tools_interface '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 implements tools_interface 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 implements tools_interface $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; @@ -396,19 +285,6 @@ class tools implements tools_interface 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'; @@ -469,26 +345,7 @@ class tools implements tools_interface $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) @@ -502,17 +359,7 @@ class tools implements tools_interface } // 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) @@ -530,16 +377,6 @@ class tools implements tools_interface // 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) @@ -556,27 +393,11 @@ class tools implements tools_interface { 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; @@ -600,17 +421,6 @@ class tools implements tools_interface $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; @@ -1063,26 +873,6 @@ class tools implements tools_interface $sql = "SHOW COLUMNS FROM $table_name"; 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_name}' - 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_name}'"; - break; - case 'oracle': $sql = "SELECT column_name FROM user_tab_columns @@ -1154,40 +944,8 @@ class tools implements tools_interface */ 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 @@ -1223,7 +981,6 @@ class tools implements tools_interface switch ($this->sql_layer) { case 'oracle': - case 'postgres': case 'sqlite': case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); @@ -1246,39 +1003,8 @@ class tools implements tools_interface */ 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 @@ -1315,11 +1041,6 @@ class tools implements tools_interface continue; } - if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't') - { - continue; - } - // These DBMS prefix index name with the table name switch ($this->sql_layer) { @@ -1335,7 +1056,6 @@ class tools implements tools_interface } break; - case 'postgres': case 'sqlite': case 'sqlite3': $row[$col] = substr($row[$col], strlen($table_name) + 1); @@ -1410,50 +1130,6 @@ class tools implements tools_interface 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} "; @@ -1507,43 +1183,6 @@ class tools implements tools_interface 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 - { - $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; @@ -1585,6 +1224,7 @@ class tools implements tools_interface */ 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); @@ -1645,12 +1285,6 @@ class tools implements tools_interface 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'] : ''; @@ -1662,33 +1296,6 @@ class tools implements tools_interface $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) { @@ -1762,51 +1369,6 @@ class tools implements tools_interface 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 . '`'; @@ -1816,10 +1378,6 @@ class tools implements tools_interface $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': @@ -1891,18 +1449,12 @@ class tools implements tools_interface 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; @@ -1944,22 +1496,6 @@ class tools implements tools_interface } $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); @@ -1974,22 +1510,11 @@ class tools implements tools_interface 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; @@ -2056,16 +1581,10 @@ class tools implements tools_interface { $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': @@ -2076,11 +1595,6 @@ class tools implements tools_interface 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); @@ -2093,12 +1607,7 @@ class tools implements tools_interface { $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) @@ -2108,7 +1617,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'postgres': case 'oracle': case 'sqlite': case 'sqlite3': @@ -2129,96 +1637,79 @@ class tools implements tools_interface 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); } /** + * 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); } @@ -2246,62 +1737,6 @@ class tools implements tools_interface 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']; @@ -2373,69 +1808,6 @@ class tools implements tools_interface $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': @@ -2504,52 +1876,6 @@ class tools implements tools_interface } /** - * 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 @@ -2563,7 +1889,6 @@ class tools implements tools_interface { case 'mysql_40': case 'mysql_41': - case 'postgres': case 'sqlite': case 'sqlite3': // Not supported @@ -2576,40 +1901,6 @@ class tools implements tools_interface 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 @@ -2636,36 +1927,6 @@ class tools implements tools_interface 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 @@ -2685,25 +1946,6 @@ class tools implements tools_interface } /** - * 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/event/dispatcher.php b/phpBB/phpbb/event/dispatcher.php index 9a786022c2..1c4abeb108 100644 --- a/phpBB/phpbb/event/dispatcher.php +++ b/phpBB/phpbb/event/dispatcher.php @@ -14,6 +14,7 @@ namespace phpbb\event; use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; +use Symfony\Component\EventDispatcher\Event; /** * Extension of the Symfony2 EventDispatcher @@ -32,6 +33,11 @@ use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; class dispatcher extends ContainerAwareEventDispatcher implements dispatcher_interface { /** + * @var bool + */ + protected $disabled = false; + + /** * {@inheritdoc} */ public function trigger_event($eventName, $data = array()) @@ -40,4 +46,33 @@ class dispatcher extends ContainerAwareEventDispatcher implements dispatcher_int $this->dispatch($eventName, $event); return $event->get_data_filtered(array_keys($data)); } + + /** + * {@inheritdoc} + */ + public function dispatch($eventName, Event $event = null) + { + if ($this->disabled) + { + return $event; + } + + return parent::dispatch($eventName, $event); + } + + /** + * {@inheritdoc} + */ + public function disable() + { + $this->disabled = true; + } + + /** + * {@inheritdoc} + */ + public function enable() + { + $this->disabled = false; + } } diff --git a/phpBB/phpbb/event/dispatcher_interface.php b/phpBB/phpbb/event/dispatcher_interface.php index 50a3ef9101..c66aa98260 100644 --- a/phpBB/phpbb/event/dispatcher_interface.php +++ b/phpBB/phpbb/event/dispatcher_interface.php @@ -37,4 +37,14 @@ interface dispatcher_interface extends \Symfony\Component\EventDispatcher\EventD * @return mixed */ public function trigger_event($eventName, $data = array()); + + /** + * Disable the event dispatcher. + */ + public function disable(); + + /** + * Enable the event dispatcher. + */ + public function enable(); } diff --git a/phpBB/phpbb/event/kernel_exception_subscriber.php b/phpBB/phpbb/event/kernel_exception_subscriber.php index 44e87507f9..eb7831ad34 100644 --- a/phpBB/phpbb/event/kernel_exception_subscriber.php +++ b/phpBB/phpbb/event/kernel_exception_subscriber.php @@ -14,9 +14,10 @@ namespace phpbb\event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; -use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpFoundation\Response; class kernel_exception_subscriber implements EventSubscriberInterface @@ -53,23 +54,55 @@ class kernel_exception_subscriber implements EventSubscriberInterface */ public function on_kernel_exception(GetResponseForExceptionEvent $event) { - page_header($this->user->lang('INFORMATION')); - $exception = $event->getException(); - $this->template->assign_vars(array( - 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'), - 'MESSAGE_TEXT' => $exception->getMessage(), - )); + $message = $exception->getMessage(); + + if ($exception instanceof \phpbb\exception\exception_interface) + { + $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($message), $exception->get_parameters())); + } + + if (!$event->getRequest()->isXmlHttpRequest()) + { + page_header($this->user->lang('INFORMATION')); + + $this->template->assign_vars(array( + 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'), + 'MESSAGE_TEXT' => $message, + )); + + $this->template->set_filenames(array( + 'body' => 'message_body.html', + )); + + page_footer(true, false, false); + + $response = new Response($this->template->assign_display('body'), 500); + } + else + { + $data = array(); + + if (!empty($message)) + { + $data['message'] = $message; + } + + if (defined('DEBUG')) + { + $data['trace'] = $exception->getTrace(); + } - $this->template->set_filenames(array( - 'body' => 'message_body.html', - )); + $response = new JsonResponse($data, 500); + } - page_footer(true, false, false); + if ($exception instanceof HttpExceptionInterface) + { + $response->setStatusCode($exception->getStatusCode()); + $response->headers->add($exception->getHeaders()); + } - $status_code = $exception instanceof HttpException ? $exception->getStatusCode() : 500; - $response = new Response($this->template->assign_display('body'), $status_code); $event->setResponse($response); } diff --git a/phpBB/phpbb/event/kernel_terminate_subscriber.php b/phpBB/phpbb/event/kernel_terminate_subscriber.php index 57e4840380..3a709f73fd 100644 --- a/phpBB/phpbb/event/kernel_terminate_subscriber.php +++ b/phpBB/phpbb/event/kernel_terminate_subscriber.php @@ -35,7 +35,7 @@ class kernel_terminate_subscriber implements EventSubscriberInterface public static function getSubscribedEvents() { return array( - KernelEvents::TERMINATE => 'on_kernel_terminate', + KernelEvents::TERMINATE => array('on_kernel_terminate', ~PHP_INT_MAX), ); } } diff --git a/phpBB/phpbb/exception/exception_interface.php b/phpBB/phpbb/exception/exception_interface.php new file mode 100644 index 0000000000..e8526a35f5 --- /dev/null +++ b/phpBB/phpbb/exception/exception_interface.php @@ -0,0 +1,29 @@ +<?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\exception; + +/** + * Interface exception_interface + * + * Define an exception which support a language var as message. + */ +interface exception_interface +{ + /** + * Return the arguments associated with the message if it's a language var. + * + * @return array + */ + public function get_parameters(); +} diff --git a/phpBB/phpbb/exception/http_exception.php b/phpBB/phpbb/exception/http_exception.php new file mode 100644 index 0000000000..0e6ffe4f59 --- /dev/null +++ b/phpBB/phpbb/exception/http_exception.php @@ -0,0 +1,70 @@ +<?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\exception; + +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; + +/** + * Class http_exception + */ +class http_exception extends runtime_exception implements HttpExceptionInterface +{ + /** + * Http status code. + * + * @var integer + */ + private $status_code; + + /** + * Additional headers to set in the response. + * + * @var array + */ + private $headers; + + /** + * Constructor + * + * @param integer $status_code The http status code. + * @param string $message The Exception message to throw (must be a language variable). + * @param array $parameters The parameters to use with the language var. + * @param \Exception $previous The previous exception used for the exception chaining. + * @param array $headers Additional headers to set in the response. + * @param integer $code The Exception code. + */ + public function __construct($status_code, $message = "", array $parameters = array(), \Exception $previous = null, array $headers = array(), $code = 0) + { + $this->status_code = $status_code; + $this->headers = $headers; + + parent::__construct($message, $parameters, $previous, $code); + } + + /** + * {@inheritdoc} + */ + public function getStatusCode() + { + return $this->status_code; + } + + /** + * {@inheritdoc} + */ + public function getHeaders() + { + return $this->headers; + } +} diff --git a/phpBB/phpbb/exception/runtime_exception.php b/phpBB/phpbb/exception/runtime_exception.php new file mode 100644 index 0000000000..6568bbf86f --- /dev/null +++ b/phpBB/phpbb/exception/runtime_exception.php @@ -0,0 +1,52 @@ +<?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\exception; + +/** + * Class runtime_exception + * + * Define an exception which support a language var as message. + */ +class runtime_exception extends \RuntimeException implements exception_interface +{ + /** + * Parameters to use with the language var. + * + * @var array + */ + private $parameters; + + /** + * Constructor + * + * @param string $message The Exception message to throw (must be a language variable). + * @param array $parameters The parameters to use with the language var. + * @param \Exception $previous The previous runtime_exception used for the runtime_exception chaining. + * @param integer $code The Exception code. + */ + public function __construct($message = "", array $parameters = array(), \Exception $previous = null, $code = 0) + { + $this->parameters = $parameters; + + parent::__construct($message, $code, $previous); + } + + /** + * {@inheritdoc} + */ + public function get_parameters() + { + return $this->parameters; + } +} diff --git a/phpBB/phpbb/feed/base.php b/phpBB/phpbb/feed/base.php index e31854160a..322e2ee9f1 100644 --- a/phpBB/phpbb/feed/base.php +++ b/phpBB/phpbb/feed/base.php @@ -67,6 +67,9 @@ abstract class base */ var $separator_stats = "\xE2\x80\x94"; // — + /** @var mixed Query result handle */ + protected $result; + /** * Constructor * @@ -229,9 +232,7 @@ abstract class base function get_item() { - static $result; - - if (!isset($result)) + if (!isset($this->result)) { if (!$this->get_sql()) { @@ -240,10 +241,10 @@ abstract class base // Query database $sql = $this->db->sql_build_query('SELECT', $this->sql); - $result = $this->db->sql_query_limit($sql, $this->num_items); + $this->result = $this->db->sql_query_limit($sql, $this->num_items); } - return $this->db->sql_fetchrow($result); + return $this->db->sql_fetchrow($this->result); } function user_viewprofile($row) diff --git a/phpBB/phpbb/file_downloader.php b/phpBB/phpbb/file_downloader.php index d717b394d5..462b87ca51 100644 --- a/phpBB/phpbb/file_downloader.php +++ b/phpBB/phpbb/file_downloader.php @@ -33,7 +33,7 @@ class file_downloader * @return mixed File data as string if file can be read and there is no * timeout, false if there were errors or the connection timed out * - * @throws \RuntimeException If data can't be retrieved and no error + * @throws \phpbb\exception\runtime_exception If data can't be retrieved and no error * message is returned */ public function get($host, $directory, $filename, $port = 80, $timeout = 6) @@ -69,7 +69,7 @@ class file_downloader } else if (stripos($line, '404 not found') !== false) { - throw new \RuntimeException(array('FILE_NOT_FOUND', $filename)); + throw new \phpbb\exception\runtime_exception('FILE_NOT_FOUND', array($filename)); } } @@ -77,7 +77,7 @@ class file_downloader if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop) { - throw new \RuntimeException('FSOCK_TIMEOUT'); + throw new \phpbb\exception\runtime_exception('FSOCK_TIMEOUT'); } } @fclose($socket); @@ -91,7 +91,7 @@ class file_downloader } else { - throw new \RuntimeException('FSOCK_DISABLED'); + throw new \phpbb\exception\runtime_exception('FSOCK_DISABLED'); } } 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/notification/manager.php b/phpBB/phpbb/notification/manager.php index aa52eb61d0..db92170dd8 100644 --- a/phpBB/phpbb/notification/manager.php +++ b/phpBB/phpbb/notification/manager.php @@ -38,7 +38,7 @@ class manager /** @var \phpbb\config\config */ protected $config; - /** @var \phpbb\event\dispatcher */ + /** @var \phpbb\event\dispatcher_interface */ protected $phpbb_dispatcher; /** @var \phpbb\db\driver\driver_interface */ @@ -73,7 +73,7 @@ class manager * @param ContainerInterface $phpbb_container * @param \phpbb\user_loader $user_loader * @param \phpbb\config\config $config - * @param \phpbb\event\dispatcher $phpbb_dispatcher + * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\cache\service $cache * @param \phpbb\user $user @@ -85,7 +85,7 @@ class manager * * @return \phpbb\notification\manager */ - public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\event\dispatcher $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table) + public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table) { $this->notification_types = $notification_types; $this->notification_methods = $notification_methods; diff --git a/phpBB/phpbb/notification/type/post.php b/phpBB/phpbb/notification/type/post.php index d9e74f2e95..421eff6372 100644 --- a/phpBB/phpbb/notification/type/post.php +++ b/phpBB/phpbb/notification/type/post.php @@ -357,6 +357,7 @@ class post extends \phpbb\notification\type\base { $tracking_data[$row['user_id']] = $row['mark_time']; } + $this->db->sql_freeresult($result); return $tracking_data; } diff --git a/phpBB/phpbb/notification/type/topic.php b/phpBB/phpbb/notification/type/topic.php index cf0ec77099..5f57087b73 100644 --- a/phpBB/phpbb/notification/type/topic.php +++ b/phpBB/phpbb/notification/type/topic.php @@ -257,6 +257,7 @@ class topic extends \phpbb\notification\type\base { $tracking_data[$row['user_id']] = $row['mark_time']; } + $this->db->sql_freeresult($result); return $tracking_data; } diff --git a/phpBB/phpbb/path_helper.php b/phpBB/phpbb/path_helper.php index b49d8d13c2..5400c1c5a6 100644 --- a/phpBB/phpbb/path_helper.php +++ b/phpBB/phpbb/path_helper.php @@ -455,4 +455,38 @@ class path_helper return $url_parts['base'] . (($params) ? '?' . $this->glue_url_params($params) : ''); } + + /** + * Get a valid page + * + * @param string $page The page to verify + * @param bool $mod_rewrite Whether mod_rewrite is enabled, default: false + * + * @return string A valid page based on given page and mod_rewrite + */ + public function get_valid_page($page, $mod_rewrite = false) + { + // We need to be cautious here. + // On some situations, the redirect path is an absolute URL, sometimes a relative path + // For a relative path, let's prefix it with $phpbb_root_path to point to the correct location, + // else we use the URL directly. + $url_parts = parse_url($page); + + // URL + if ($url_parts === false || empty($url_parts['scheme']) || empty($url_parts['host'])) + { + // Remove 'app.php/' from the page, when rewrite is enabled. + // Treat app.php as a reserved file name and remove on mod rewrite + // even if it might not be in the phpBB root. + if ($mod_rewrite && ($app_position = strpos($page, 'app.' . $this->php_ext . '/')) !== false) + { + $page = substr($page, 0, $app_position) . substr($page, $app_position + strlen('app.' . $this->php_ext . '/')); + } + + // Remove preceding slashes from page name and prepend root path + $page = $this->get_phpbb_root_path() . ltrim($page, '/\\'); + } + + return $page; + } } diff --git a/phpBB/phpbb/profilefields/type/type_bool.php b/phpBB/phpbb/profilefields/type/type_bool.php index 75934e3be7..f6f3f17a6c 100644 --- a/phpBB/phpbb/profilefields/type/type_bool.php +++ b/phpBB/phpbb/profilefields/type/type_bool.php @@ -173,7 +173,7 @@ class type_bool extends type_base } else { - return $this->lang_helper->is_set($field_id, $lang_id, $field_value + 1); + return $this->lang_helper->is_set($field_id, $lang_id, $field_value + 1) ? $this->lang_helper->get($field_id, $lang_id, $field_value + 1) : null; } } @@ -367,29 +367,29 @@ class type_bool extends type_base */ public function prepare_hidden_fields($step, $key, $action, &$field_data) { - if ($key == 'l_lang_options' && $this->request->is_set('l_lang_options')) + if ($key == 'field_default_value') { - return $this->request->variable($key, array(array('')), true); - } - else if ($key == 'field_default_value') - { - return $this->request->variable($key, $field_data[$key]); - } - else - { - if (!$this->request->is_set($key)) - { - return false; - } - else if ($key == 'field_ident' && isset($field_data[$key])) - { - return $field_data[$key]; - } - else + $field_length = $this->request->variable('field_length', 0); + + // Do a simple is set check if using checkbox. + if ($field_length == 2) { - return ($key == 'lang_options') ? $this->request->variable($key, array(''), true) : $this->request->variable($key, '', true); + return $this->request->is_set($key); } + return $this->request->variable($key, $field_data[$key], true); + } + + $default_lang_options = array( + 'l_lang_options' => array(0 => array('')), + 'lang_options' => array(0 => ''), + ); + + if (isset($default_lang_options[$key]) && $this->request->is_set($key)) + { + return $this->request->variable($key, $default_lang_options[$key], true); } + + return parent::prepare_hidden_fields($step, $key, $action, $field_data); } /** 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 index 601d774129..4ccd3cf5e3 100644 --- a/phpBB/phpbb/routing/router.php +++ b/phpBB/phpbb/routing/router.php @@ -13,6 +13,7 @@ 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; @@ -232,14 +233,7 @@ class router implements RouterInterface return $this->matcher; } - if (defined('DEBUG')) - { - $this->create_new_url_matcher(); - } - else - { - $this->create_dumped_url_matcher(); - } + $this->create_dumped_url_matcher(); return $this->matcher; } @@ -248,21 +242,22 @@ class router implements RouterInterface */ protected function create_dumped_url_matcher() { - if (!file_exists($this->phpbb_root_path . 'cache/url_matcher.' . $this->php_ext)) + $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', + 'class' => 'phpbb_url_matcher', + 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', ); - $dump = $dumper->dump($options); - file_put_contents($this->phpbb_root_path . 'cache/url_matcher.' . $this->php_ext, $dump); + $cache->write($dumper->dump($options), $this->get_routes()->getResources()); } - require_once($this->phpbb_root_path . 'cache/url_matcher.' . $this->php_ext); + require_once($cache); - $this->matcher = new phpbb_url_matcher($this->context); + $this->matcher = new \phpbb_url_matcher($this->context); } /** @@ -285,14 +280,7 @@ class router implements RouterInterface return $this->generator; } - if (defined('DEBUG')) - { - $this->create_new_url_generator(); - } - else - { - $this->create_dumped_url_generator(); - } + $this->create_dumped_url_generator(); return $this->generator; } @@ -302,21 +290,22 @@ class router implements RouterInterface */ protected function create_dumped_url_generator() { - if (!file_exists($this->phpbb_root_path . 'cache/url_generator.' . $this->php_ext)) + $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', + 'class' => 'phpbb_url_generator', + 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', ); - $dump = $dumper->dump($options); - file_put_contents($this->phpbb_root_path . 'cache/url_generator.' . $this->php_ext, $dump); + $cache->write($dumper->dump($options), $this->get_routes()->getResources()); } - require_once($this->phpbb_root_path . 'cache/url_generator.' . $this->php_ext); + require_once($cache); - $this->generator = new phpbb_url_generator($this->context); + $this->generator = new \phpbb_url_generator($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 ea239c0b36..b18015ba1a 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -303,7 +303,7 @@ class fulltext_native extends \phpbb\search\base $this->search_query = $keywords; $exact_words = array(); - preg_match_all('#([^\\s+\\-|*()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words); + preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words); $exact_words = $exact_words[1]; $common_ids = $words = array(); @@ -437,7 +437,7 @@ class fulltext_native extends \phpbb\search\base // throw an error if we shall not ignore unexistant words else if (!$ignore_no_id && sizeof($non_common_words)) { - trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], implode($user->lang['COMMA_SEPARATOR'], $non_common_words))); + trigger_error(sprintf($this->user->lang['WORDS_IN_NO_POST'], implode($this->user->lang['COMMA_SEPARATOR'], $non_common_words))); } unset($non_common_words); } @@ -1425,7 +1425,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; } @@ -1460,7 +1460,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 . ' @@ -1476,7 +1476,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); } /** 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 2765d05b94..a5ad96b114 100644 --- a/phpBB/phpbb/search/fulltext_sphinx.php +++ b/phpBB/phpbb/search/fulltext_sphinx.php @@ -136,11 +136,12 @@ class fulltext_sphinx $this->auth = $auth; // Initialize \phpbb\db\tools\tools object - $this->db_tools = new \phpbb\db\tools\tools($this->db); + 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 5b9fb6d835..6aeb8a91de 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -139,7 +139,7 @@ class session 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)), 'page' => $page, - 'forum' => request_var('f', 0), + 'forum' => $request->variable('f', 0), ); return $page_array; @@ -215,7 +215,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(); @@ -253,23 +253,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; } @@ -345,8 +345,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'); } } @@ -490,11 +490,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)); } } } @@ -1029,7 +1036,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']) { 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/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 a7848738bb..f1542109a4 100644 --- a/phpBB/phpbb/template/twig/lexer.php +++ b/phpBB/phpbb/template/twig/lexer.php @@ -117,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 4962d14aef..605d37e954 100644 --- a/phpBB/phpbb/template/twig/twig.php +++ b/phpBB/phpbb/template/twig/twig.php @@ -261,19 +261,19 @@ class twig extends \phpbb\template\base $ext_style_theme_path = $ext_style_path . 'theme/'; } - $ok = false; + $is_valid_dir = false; if (is_dir($ext_style_template_path)) { - $ok = true; + $is_valid_dir = true; $paths[] = $ext_style_template_path; } if (is_dir($ext_style_theme_path)) { - $ok = true; + $is_valid_dir = true; $paths[] = $ext_style_theme_path; } - if ($ok) + if ($is_valid_dir) { // Add the base style directory as a safe directory $this->twig->getLoader()->addSafeDirectory($ext_style_path); diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php index dc62f06fb2..e4f68f5aab 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -257,9 +257,10 @@ class version_helper try { $info = $this->file_downloader->get($this->host, $this->path, $this->file); } - catch (\RuntimeException $exception) + catch (\phpbb\exception\runtime_exception $exception) { - throw new \RuntimeException($this->user->lang($exception->getMessage())); + $prepare_parameters = array_merge(array($exception->getMessage()), $exception->get_parameters()); + throw new \RuntimeException(call_user_func_array(array($this->user, 'lang'), $prepare_parameters)); } $error_string = $this->file_downloader->get_error_string(); |